%{ name: :mob_screencast, mob_version: "~> 0.6", plugin_spec_version: 1, description: "In-app screen capture → on-device H264 (MediaProjection/MediaCodec, ReplayKit/VideoToolbox), streamed to the BEAM as Annex-B NAL units for WebRTC", nifs: [ # iOS: Objective-C NIF — ReplayKit/ScreenCaptureKit capture + a VideoToolbox AVC # encoder; emits Annex-B access units via cam_send-style enif_send. lang: :objc # (-fobjc-arc); platform: :ios so it isn't pulled into the Android build. %{module: :mob_screencast_nif, native_dir: "priv/native/ios", lang: :objc, platform: :ios}, # Android: zig NIF bridging to MediaProjection + MediaCodec via the Kotlin # io.mob.screencast.MobScreencastBridge. %{module: :mob_screencast_nif, native_dir: "priv/native/jni", lang: :zig, platform: :android} ], android: %{ bridge_kt: "priv/native/android/MobScreencastBridge.kt", bridge_class: "io.mob.screencast.MobScreencastBridge", # MediaProjection itself is granted per-session via a system consent dialog # (MediaProjectionManager.createScreenCaptureIntent), NOT a manifest permission — # the bridge drives that. What the manifest needs is the foreground-service perms a # MediaProjection capture must run under (API 34+ split out the typed one). permissions: [ "android.permission.FOREGROUND_SERVICE", "android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" ] # A MediaProjection capture must run inside a typed foreground — an # AndroidManifest fragment the plugin manifest can't yet contribute (Stage-2 # decision, tracked in PLAN.md). Declared in :host_requirements below so # every native build warns the host author instead of failing silently at # first capture (SecurityException). mob_camera has the same class of gap. }, ios: %{ # On-device capture uses ReplayKit's in-app RPScreenRecorder (no broadcast # extension, no plist key — the user grants per session). ScreenCaptureKit is the # simulator/macOS path. The VideoToolbox encoder needs no extra entitlement. frameworks: ["ReplayKit", "VideoToolbox", "CoreMedia", "CoreVideo"] }, # Manual host-app steps the build can't automate; printed as a warning on # every `mix mob.deploy --native` of the host. host_requirements: [ "AndroidManifest.xml must declare the capture service inside : " <> ~s( ~s(android:exported="false" android:foregroundServiceType="mediaProjection" />) <> " — MediaProjection capture must run in a typed foreground service; without it " <> "the app builds + boots fine and throws a SecurityException at first capture." ] }