The plugin's on-device proof (Mob.Plugin.SelfTest), run by
mix mob.selftest and mob_ci for every activated plugin.
One read-only native call, no UI, nothing scheduled: :mob_wake_nif.platform_signal/0.
- iOS — the Objective-C NIF reads
UIApplication.backgroundRefreshStatuson the main thread and answers%{background_refresh_status: :available | :denied | :restricted}. Any of the three passes: the answer can only come from the linked NIF asking UIKit.:denied/:restrictedare the user's or MDM's Background App Refresh setting, not a plugin fault. - Android — the Zig NIF calls the Kotlin
MobWakeBridge.platformSignal()over JNI and answers%{battery_optimized: boolean, has_context: boolean}. It passes only withhas_context: true: that proves the NIF is linked, the bootstrap ranMobWakeBridge.register()(the JNI class + method IDs are cached) and handed the bridge the app context (setActivity/1), which is whatMob.Wake.schedule/2needs to reach WorkManager.battery_optimizedis the user's battery setting either way. has_context: falsefails: the bridge never got a context, so scheduling can't reach WorkManager in this host.{:error, :bridge_not_registered}(Android:register()never ran or theplatformSignalmethod-ID lookup failed) and{:error, :no_jni_env}fail.- The other platform's map, an empty map, or anything else fails.
The host stub's nif_not_loaded is a failure. Nothing here needs
hardware or the user, so the test never skips.