Skip to main content

🖥️ iOS screen sharing

Viewing someone else's screen always works. Sharing this device's screen on iOS needs a Broadcast Upload Extension in your app: ReplayKit hands the screen frames to a second process, which forwards them to the SDK's WebRTC module over a socket in a shared App Group. A framework cannot ship an app extension, so your app adds it once.

Android

Nothing to add on Android: sharing the screen is built in on Android 10 (API 29) and later (screensharePresenter is on by default there).


🛠️ Manual setup​

  1. Extension target. In Xcode choose File → New → Target → Broadcast Upload Extension, named for example BroadcastExtension, with bundle id <app bundle id>.broadcast and deployment target 16.4. Replace its generated sources with the files in ios/BroadcastExtension/ of the SDK repository (SampleHandler.swift, SampleUploader.swift, SocketConnection.swift, DarwinNotificationCenter.swift, Atomic.swift). Use the shipped Info.plist (RPBroadcastProcessMode = RPBroadcastProcessModeSampleBuffer) and BroadcastExtension.entitlements, with their {{APP_GROUP}}, {{DISPLAY_NAME}}, {{SHORT_VERSION}} and {{BUILD_VERSION}} placeholders replaced.
  2. App Group group.<app bundle id> on both targets (Signing & Capabilities), and enabled for both App IDs in the Apple Developer portal. A mismatch is silent: the broadcast starts and stops immediately.
  3. Info.plist keys in the app target: RTCAppGroupIdentifier = group.<app bundle id> and RTCScreenSharingExtension = <app bundle id>.broadcast. The extension's Info.plist carries the same RTCAppGroupIdentifier.
  4. Keep the extension's CFBundleShortVersionString / CFBundleVersion equal to the app's (App Store Connect rejects mismatches), and make sure the app's UIBackgroundModes includes audio.
  5. Pass screensharePresenter: true in the join options. The meeting then offers the share button, presents the system broadcast picker and publishes the screen track.

⚡ With the shipped tool​

Steps 1 to 4 (except the background modes) are scripted for Xcode projects whose app is the project's first target: Flutter's Runner.xcodeproj, a React Native app's .xcodeproj, or a new Xcode app project. The tool embeds the extension into the first target, so in a project where another target comes first, add the extension by hand.

Two templates need a small change first:

  • React Native — replace the template's org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) bundle id with a literal one.
  • New SwiftUI app — it has no Info.plist file. Add the Info.plist keys from the iOS guide first, so that Xcode creates one and sets INFOPLIST_FILE; without it the tool stops with a TypeError.

Run the tool with Node.js from a clone of the SDK repository; it takes the extension files from ios/BroadcastExtension/:

cd tools/ios && npm install && cd ../..
node tools/ios/add-broadcast-extension.mjs --project <path to YourApp.xcodeproj> \
--app-target <YourApp> --team <TEAMID> --version <app version> --build <app build number>
OptionMeaning
--teamyour Apple Developer team ID
--version / --buildthe extension's CFBundleShortVersionString / CFBundleVersion (step 4; default 1.0.0 / 1). They are written as literal values: re-run the tool with the new values, or edit the extension's Info.plist, whenever your app's version or build number changes. Re-running without them resets the extension to 1.0.0 / 1.
--display-namethe extension's CFBundleDisplayName (default: app target name + " Screen Share")
--app-groupdefault group.<app bundle id>
--target-namedefault BroadcastExtension
--deployment-targetdefault 16.4

The app target's build settings must hold a literal PRODUCT_BUNDLE_IDENTIFIER (no $(...) variables) and an INFOPLIST_FILE.

The tool copies the extension files into a BroadcastExtension/ folder (named after --target-name) next to the .xcodeproj, with the placeholders filled in. It adds the extension target (sources, Info.plist, entitlements, build settings, app dependency, embed phase), writes the two Info.plist keys and sets automatic signing with your team on both targets. Xcode's automatic signing then registers the App Group on both App IDs on the first device build (xcodebuild -allowProvisioningUpdates, flutter build ios). Running the tool again only refreshes files and settings. The tool places the extension's embed phase before script phases such as Flutter's "Thin Binary". If you add the extension by hand and Xcode reports "Cycle inside Runner", move the embed phase above "Thin Binary" in the app target's Build Phases.

Existing App Groups

The tool sets the app target's App Groups entitlement to this one group: any App Groups already in your app's entitlements (for widgets, notification extensions and so on) are replaced, on every run. Add your other groups back after running it.

Test on a device

The simulator cannot capture the screen (ReplayKit's capturer is compiled out), so the SDK turns presenter mode off there and the share button stays disabled, even with screensharePresenter: true.