Skip to main content
Version: 1.x.x

Screen Sharing for Expo React Native (iOS)

This guide walks you through integrating screen sharing functionality for iOS in your Expo React Native application using Video SDK.

note

This page uses the following asynchronous methods. Refer to their API reference for the errors each Promise may reject with, and handle these rejections appropriately based on your use case.

Install the plugin:

npm install @videosdk.live/expo-ios-screen-share

Usage

Update your app.json to include the plugin along with your Apple Developer teamId and an optional extensionName:

{
"plugins": [
[
"@videosdk.live/expo-ios-screen-share",
{
"appleTeamId": "YOUR_APPLE_TEAM_ID", // example: "EHV7XZLAHA"
"extensionName": "YOUR_BROADCAST_EXTENSION_NAME",
}
],
]
}
info

If no extensionName is provided, the default value broadcast will be used.

What This Plugin Does

  • Adds a Broadcast Upload Extension target.
  • Configures App Group, Entitlements, and Info.plist entries.
  • Automatically links the broadcast extension with your main app target.
  • Minimizes manual native code configuration required for ReplayKit.
  • Provides a native bridge (VideosdkRPK.swift) for broadcasting control.

VideosdkRPK.js file

Create a JS bridge to interface with the native broadcast extension:

import { NativeModules, NativeEventEmitter, Platform } from 'react-native';

const { VideosdkRPK } = NativeModules;

if (!VideosdkRPK) {
console.warn('⚠️ Native Module VideosdkRPK is not loaded');
}

const emitter = Platform.OS === 'ios' && VideosdkRPK ? new NativeEventEmitter(VideosdkRPK) : null;

const VideosdkBridge = {
startBroadcast: Platform.OS === 'ios' ? () => VideosdkRPK?.startBroadcast() : () => {},
addListener: (callback) => {
if (!emitter) return { remove: () => {} };
return emitter.addListener('onScreenShare', callback);
},
removeListener: (subscription) => {
subscription?.remove?.();
},
};

export default VideosdkBridge;

Implementing Screen Share Controls

import VideosdkRPK from "./VideosdkRPK";

function ControlsContainer() {

const {toggleScreenShare} = useMeeting({});

useEffect(() => {
const subscription = VideosdkRPK.addListener((event) => {
if (event === "START_BROADCAST") {
try {
await toggleScreenShare();
} catch (err) {
console.error("toggleScreenShare failed:", err);
}
} else if (event === "STOP_BROADCAST") {
try {
await toggleScreenShare();
} catch (err) {
console.error("toggleScreenShare failed:", err);
}
}
});

return () => {
VideosdkRPK.removeListener(subscription);
};
}, []);

return (
<View
style={{
padding: 24,
flexDirection: "row",
justifyContent: "space-between",
}}
>
<Button
onPress={async () => {
VideosdkRPK.startBroadcast();
}}
buttonText={"Screen Share"}
backgroundColor={"#1178F8"}
/>
</View>
);
}

Got a Question? Ask us on discord