Skip to main content

priv/mob_plugin.exs

%{
  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 <service> — 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 <application>: " <>
      ~s(<service android:name="io.mob.screencast.ScreencastService" ) <>
      ~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."
  ]
}