%{
name: :mob_notify,
mob_version: "~> 0.6",
plugin_spec_version: 1,
description:
"Local + push notifications (device half) — extracted from mob core in Wave 2. " <>
"Pairs with the server-side mob_push package.",
nifs: [
# iOS: Objective-C NIF — UNUserNotificationCenter scheduling/cancel +
# registerForRemoteNotifications. The notification-center DELEGATE, push-token
# forwarding (mob_send_push_token) and launch-notification handoff
# (take_launch_notification, consumed by core Mob.Screen) STAY IN CORE; this
# NIF calls core's exported mob_notify_set_screen_pid. lang: :objc;
# platform: :ios so it isn't pulled into the Android build.
%{module: :mob_notify_nif, native_dir: "priv/native/ios", lang: :objc, platform: :ios},
# Android: zig NIF bridging to NotificationManager/AlarmManager/FCM via the
# Kotlin io.mob.notify.MobNotifyBridge.
%{module: :mob_notify_nif, native_dir: "priv/native/jni", lang: :zig, platform: :android}
],
# NOTE: the :notifications runtime-permission CAPABILITY stays in core for now
# (its request flow is part of core's permission enum on both platforms and is
# used by core delivery). Revisit when the permission registry owns all caps.
android: %{
bridge_kt: "priv/native/android/MobNotifyBridge.kt",
bridge_class: "io.mob.notify.MobNotifyBridge",
permissions: [
"android.permission.POST_NOTIFICATIONS",
# Exact-alarm scheduling (setExactAndAllowWhileIdle). Special-access on
# Android 13+; notify_schedule falls back to an inexact alarm when the user
# hasn't granted it. The plugin declares the permission it uses rather than
# leaning on the host manifest.
"android.permission.SCHEDULE_EXACT_ALARM",
# Boot re-arm. AlarmManager alarms are wiped on reboot; MobNotifyBootReceiver
# re-arms persisted schedules on ACTION_BOOT_COMPLETED, which requires this
# permission. The <receiver> itself can't be contributed by a plugin manifest
# (see host_requirements).
"android.permission.RECEIVE_BOOT_COMPLETED"
],
gradle_deps: [
# FCM client. The google-services GRADLE PLUGIN + google-services.json are
# host-level (see host_requirements) — a plugin manifest can't contribute
# buildscript classpath entries.
"com.google.firebase:firebase-messaging:24.0.0"
]
},
ios: %{
frameworks: ["UserNotifications"]
# No plist key: notification permission has no usage-description string.
},
# Manual host-app steps the build can't automate; printed as a warning on
# every `mix mob.deploy --native` of the host. mob_new-generated apps already
# satisfy all of these via their templates.
host_requirements: [
"Android: AndroidManifest.xml must declare the FCM service inside <application>: " <>
~s(<service android:name=".MobFirebaseService" android:exported="false"> ) <>
~s(<intent-filter><action android:name="com.google.firebase.MESSAGING_EVENT" /></intent-filter></service>) <>
" — the MobFirebaseService.kt class ships in the host app (mob_new template), " <>
"not in this plugin (FirebaseMessagingService subclasses must live in the host package).",
"Android: the host build.gradle needs the com.google.gms.google-services plugin " <>
"+ a google-services.json (Firebase console) — buildscript classpath entries " <>
"are host-level, a plugin manifest can't contribute them.",
"iOS: the host AppDelegate must forward the APNs device token: in " <>
"didRegisterForRemoteNotificationsWithDeviceToken call mob_send_push_token(hex) " <>
"(exported by mob core; the mob_new template ships this wired).",
"Android: scheduled notifications display via a <applicationId>.NotificationReceiver " <>
"BroadcastReceiver declared in AndroidManifest (the mob_new template ships it) — " <>
"display/tap delivery stays host-side; this plugin only arms the alarm.",
"Android: AndroidManifest.xml must declare the boot re-arm receiver inside <application>: " <>
~s(<receiver android:name="io.mob.notify.MobNotifyBootReceiver" android:exported="true">) <>
~s(<intent-filter><action android:name="android.intent.action.BOOT_COMPLETED" /></intent-filter></receiver>) <>
" — AlarmManager alarms are wiped on reboot; this receiver re-arms persisted " <>
"schedules on boot. A plugin manifest can't contribute a <receiver> fragment " <>
"(same limitation as mob_screencast's foreground <service>), so the host must add it."
]
}