%{ name: :mob_biometric, mob_version: "~> 0.6", plugin_spec_version: 1, description: "Biometric authentication (Face ID / Touch ID / fingerprint) — extracted from mob core in Wave 2", # A sample screen the host can navigate to by route (auto-listed by a home # that enumerates Mob.Plugins.screens/0). Pure-Elixir + hot-pushable; drop it # and this entry in a real app that builds its own UI. screens: [ %{module: MobBiometric.DemoScreen, default_route: "/mob_biometric/demo"} ], nifs: [ # iOS: Objective-C NIF driving LAContext evaluatePolicy # (deviceOwnerAuthenticationWithBiometrics). lang: :objc -> compiled as # ObjC (-fobjc-arc); platform: :ios so it isn't pulled into the Android # build. %{module: :mob_biometric_nif, native_dir: "priv/native/ios", lang: :objc, platform: :ios}, # Android: zig NIF bridging to the platform android.hardware.biometrics # BiometricPrompt via the Kotlin MobBiometricBridge (Context-based, so it # works on mob's ComponentActivity host). platform: :android so iOS skips it. %{module: :mob_biometric_nif, native_dir: "priv/native/jni", lang: :zig, platform: :android} ], # NO permissions capability entry: biometric auth shows no runtime # permission dialog — it uses the device's existing biometric enrollment # (the OS-level prompt IS the auth flow), so there is nothing for # Mob.Permissions.request/2 to route here. android: %{ bridge_kt: "priv/native/android/MobBiometricBridge.kt", bridge_class: "io.mob.biometric.MobBiometricBridge", # No manifest permission needed from the host: the androidx.biometric AAR's # own manifest declares USE_BIOMETRIC / USE_FINGERPRINT and Gradle # manifest-merges them into the app. The bridge itself no longer uses the # androidx library (it moved to the platform BiometricPrompt), so the AAR is # retained ONLY for this permission contribution — a follow-up could declare # USE_BIOMETRIC here directly and drop the dep (needs a device re-verify). permissions: [], gradle_deps: ["androidx.biometric:biometric:1.1.0"] }, ios: %{ frameworks: ["LocalAuthentication"], plist_keys: %{ # NOT present in the template Info.plist.eex today — a latent core gap: # Face ID requires NSFaceIDUsageDescription (iOS 11+); without it the # first Face ID evaluatePolicy is denied by the system (Touch ID # devices don't need it, which is why it went unnoticed). Added here so # plugin hosts get it merged at build time. "NSFaceIDUsageDescription" => "Face ID is used to authenticate you within the app." } } }