跳到主要内容

屏幕共享

RTCLib SDK 为开发者提供了屏幕共享插件,屏幕共享功能以插件库形式提供。开发者可自行选择是否向项目中集成 RongRTCReplayKitExt 插件库来实现屏幕共享功能。RongRTCReplayKitExt 插件用于扩展 target 上使用。

环境要求​

  • iOS 系统版本 12 及以上
  • 屏幕共享功能在 RTCLib SDK 5.1.8.1 及以后支持
  • 屏幕共享库 RongRTCReplayKitExt 依赖的 RTCLib SDK 版本必须大于等于 5.1.8.1

实现方式​

我们可以通过苹果的 Extension 来实现屏幕共享技术。这里将通过使用 iOS 11 之后新增的系统级别的录屏能力,来实现录制自身 App 以外手机屏幕内容的效果。

提示

受 iOS 系统的 ReplayKit 库限制,iOS 12 前在 App 中调用 Extension 启动屏幕共享时,只能作用于 App 内,如果退出 App 则无法得到屏幕内容。

iOS 端的屏幕共享是通过在 Extension 中使用 RongRTCReplayKitExt 框架实现录制屏幕流的接收,然后将屏幕共享流传输到 RTCLib 实现的。由于 Apple 不支持 Extension 进程与主 App 进程通信,因此您需要为屏幕共享流单独创建一个进程。

(height=300)

实现流程​

实现屏幕共享的主要步骤如下:

  1. 创建 App Group:在 Xcode 中进行配置,让 Extension 录屏进程可以与主 App 进程进行跨进程通信
  2. 创建 Broadcast Upload Extension:用于开启屏幕共享的进程
  3. 宿主 App 开启屏幕共享:发布屏幕共享流
  4. 屏幕共享 Extension 处理:收到消息后,初始化 RongRTCReplayKitExt 库,接收系统录制数据

集成说明​

创建 App Group​

提示
  • 新版本 Xcode 支持在 Target 下 Signing & Capabilities 页面中 App Groups 进行创建并关联 AppGroup,可以直接跳过如下 1-5 步。
  • 老版本 Xcode 可能无法直接使用 Xcode 创建 AppGroup,需要使用您的帐号登录 苹果开发者后台 ,进行以下 1-5 步操作来创建 AppGroup,然后再关联 AppGroup。
  1. 单击 Certificates, IDs & Profiles,在右侧的界面中单击加号。

    (height=300)

  2. 选择 App Groups,单击 Continue。

    (height=300)

  3. 在弹出的表单中填写 Description 和 Identifier, 其中 Identifier 需要传入接口中的对应的 AppGroup 参数。完成后单击 Continue。

    (height=300)

  4. 回到 Identifier 页面,然后单击您的 App ID,进入 Edit your App ID Configuration 页面,选中 App Groups 并单击 Edit。

    (height=300)

  5. 在弹出的表单中选择您之前创建的 App Group,单击 Continue 返回 Edit your App ID Configuration 页面,单击 Save 保存。

    (height=300)

  6. 打开 Xcode,选中屏幕共享 Target(Broadcast Upload Extension) 点击 App Groups 的 + 按钮。

    (height=300)

  7. 输入的 AppGroup,然后点击 OK 按钮,如果输入的 AppGroup 的已经创建过,则直接关联上;如果输入的 AppGroup 没有被创建过,则创建的同时进行关联。

    (height=300)

创建 Broadcast Upload Extension:

  1. 在 Xcode 菜单依次单击 File、New、Target...,选择 Broadcast Upload Extension,创建类型为 Broadcast Upload Extension 的新 target。

    (height=300)

  2. 在弹出的对话框中填写相关信息,不用勾选 Include UI Extension,单击 Finish 完成创建。

  3. 在您的屏幕共享 Target - Build Phases - Compile Sources 中添加您可能在屏幕共享 Extension 里引用类的 .m 文件名

  4. 受限于 RongIMLib 库中的默认 2 分钟断开连接的限制,需要修改如下 Pod 路径下的 .plist 配置文件:

    您的工程名/Pods/RongCloudIM/IMLibCore/RCConfig.plist

    在此文件中添加:

    xml
    <key>Connection</key>
    <dict>
    <key>ForceKeepAlive</key>
    <true/>
    </dict>

    其中:Connection 和 ForceKeepAlive 类型为 Key 值,true 的类型为 Bool

  5. 选中新增加的 Target,依次单击 + Capability,双击 App Groups,如下图:

    (height=300)

    操作完成后,会在文件列表中生成一个以您自己创建的 Target 命名的 Target名.entitlements 的文件,如下图所示,选中该文件并单击 + 号填写上述步骤中的 App Group 即可

    (height=300)

  6. 选中宿主 App 的 Target,并按照上述步骤对宿主 App 的 Target 做同样的处理

导入 SDK​

融云支持使用 CocoaPods 和本地手动导入两种方式,将 RTCLib SDK 和屏幕共享扩展导入到您的应用工程中。

CocoaPods 导入(推荐)​

  1. 如果您的项目中没有 Podfile 文件,您需要打开终端并进入到项目的根目录,在终端中运行 pod init 命令,之后系统会自动创建一个默认的 Podfile 文件。

  2. 在项目中的 Podfile 文件中添加如下内容:

    ruby
    target '主进程APP Target' do
    use_frameworks!
    pod 'RongCloudRTC/RongRTCLib', '~> x.y.z'
    end

    target '您的屏幕共享的 target' do
    use_frameworks!
    pod 'RongCloudRTC/RongRTCReplayKitExt', '~> x.y.z'
    end
  3. 打开终端并进入到 Podfile 文件所在的目录,在终端中运行以下命令:

    shell
    pod install
    提示

    如果终端中出现类似 CocoaPods could not find compatible versions for 等找不到相关版本的报错,可先在终端中执行 pod repo update 命令,再执行 pod install 命令。

  4. 通过 Xcode 打开项目目录下的 xcworkspace 文件加载工程。

手动集成​

  1. 您可以前往融云官网 SDK 下载页面,将音视频通话(无 UI)SDK 下载到本地。

  2. 使用 Xcode 打开您的工程,然后将下载下来的 SDK 手动拖入到您的项目中:

    主进程 App Target 所需的 SDK:

    Framework
    • RongRTCLib.xcframework
    • RongIMLibCore.xcframework
    • RongRTCReplayKitExt.xcframework

    屏幕共享 Extension Target 所需的 SDK:

    Framework
    • RongRTCReplayKitExt.xcframework

    (width=300) (width=300)

  3. 修改您的项目配置。在 General → Frameworks, Libraries, and Embedded Binaries 中,将手动导入的 RTCLib SDK 所有的 Framework 全部改为 Embed & Sign。

工程配置​

  1. 音视频通话需要用到摄像头和麦克风权限,请在工程的 Info.plist 中添加如下键值:

    • Privacy - Microphone Usage Description
    • Privacy - Camera Usage Description
  2. 请将工程中 Target → Signing & Capabilities → Background Modes 如下内容勾选:

    • Audio, AirPlay, and Picture in Picture

导入头文件​

在需要使用的业务层导入 RTCLib 头文件,即可使用 SDK 的方法来实现屏幕共享相关业务。

主进程 App 导入:

Objective C
#import <RongRTCLib/RongRTCLib.h>

屏幕共享 Extension 导入:

Objective C
#import <RongRTCReplayKitExt/RongRTCReplayKitExt.h>

共享实现​

iOS 系统上的跨应用屏幕分享,需要增加 Extension 录屏进程以配合宿主 App 进程进行推流。Extension 录屏进程由系统在需要录屏的时候创建,并负责接收系统采集的 CMSampleBufferRef 数据。

宿主 App​

宿主 App 在加入房间后在需要屏幕共享时,通过点击录制按钮通知屏幕共享 target、并发布屏幕共享流。

添加系统录制按钮​

提示

此按钮需 iOS 12 及以上可用。

代码示例​
Objective C
#import <ReplayKit/ReplayKit.h>

// 添加录制按钮
RPSystemBroadcastPickerView *systemBroadcastPickerView = [[RPSystemBroadcastPickerView alloc] initWithFrame:CGRectMake(0, 64, 50, 80)];
systemBroadcastPickerView.preferredExtension = @"您的屏幕共享 target 的 Bundle Identifier";
systemBroadcastPickerView.backgroundColor = [UIColor colorWithRed:53.0/255.0 green:129.0/255.0 blue:242.0/255.0 alpha:1.0];
systemBroadcastPickerView.showsMicrophoneButton = NO;
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:systemBroadcastPickerView];

初始化并连接​

初始化 SDK 并连接融云服务器。

代码示例​
Objective C
#import <RongRTCLib/RongRTCLib.h>

[[RCCoreClient sharedCoreClient] initWithAppKey:@"您的AppKey"];
// 连接 IM
[[RCCoreClient sharedCoreClient] connectWithToken:@"您的token" dbOpened:^(RCDBErrorCode code) {

} success:^(NSString *userId) {
// 可以在此处加入房间
} error:^(RCConnectErrorCode errorCode) {

}];

监听屏幕共享流的发布与取消​

在发布屏幕共享流之前,可以先设置 RCRTCEngine 的代理,通过对应的代理方法来获取发布与取消屏幕共享流的时机。

屏幕共享扩展结束​
接口原型​
Objective C
- (void)screenShareExtentionFinished;
屏幕共享扩展开始​
接口原型​
Objective C
- (void)screenShareExtentionStarted;
代码示例​
Objective C
#import <RongRTCLib/RongRTCLib.h>

[RCRTCEngine sharedInstance].delegate = self;

// 屏幕共享扩展结束消息回调 Added from 5.1.8
- (void)screenShareExtentionFinished {
NSLog(@"屏幕共享扩展结束");
}

// 屏幕共享扩展开始消息回调 Added from 5.2.0
- (void)screenShareExtentionStarted {
NSLog(@"屏幕共享扩展开始");
}

加入房间​

连接 SDK 成功后,配置房间信息并加入房间。

代码示例​
Objective C
#import <RongRTCLib/RongRTCLib.h>

[[RCRTCEngine sharedInstance] joinRoom:@"您的房间号" completion:^(RCRTCRoom * _Nullable room, RCRTCCode code) {
room.delegate = self;
// 发布资源
[self publishScreenStream];
}];

发布资源​

加入房间成功后可以发布 RCRTCScreenShareOutputStream 流。直播与会议场景发布流的方法不同,请注意区分。

获取屏幕共享流​
接口原型​
Objective C
- (RCRTCScreenShareOutputStream *)getScreenShareVideoStreamWithGroupId:(NSString *)groupId;
参数说明​
参数类型是否必填说明
groupIdNSString *是苹果开发者账号后台申请的 Group ID
返回值​
类型说明
RCRTCScreenShareOutputStream屏幕共享输出流
代码示例​
会议场景​

在会议场景下,请使用 publishStream:completion 方法。

Objective C
#import <RongRTCLib/RongRTCLib.h>

RCRTCScreenShareOutputStream *videoOutputStream = [[RCRTCEngine sharedInstance] getScreenShareVideoStreamWithGroupId:@"您的屏幕共享 Extension 的 Group ID"];

RCRTCVideoStreamConfig *videoConfig = videoOutputStream.videoConfig;
videoConfig.videoSizePreset = RCRTCVideoSizePreset1280x720;
videoConfig.videoFps = RCRTCVideoFPS24;
[videoOutputStream setVideoConfig:videoConfig];

[self.room.localUser publishStream:videoOutputStream completion:^(BOOL isSuccess, RCRTCCode desc) {

}];
直播场景​

在直播场景下,请使用 publishLiveStream:completion 方法。

Objective C
#import <RongRTCLib/RongRTCLib.h>

RCRTCScreenShareOutputStream *videoOutputStream = [[RCRTCEngine sharedInstance] getScreenShareVideoStreamWithGroupId:@"您的屏幕共享 Extension 的 Group ID"];

RCRTCVideoStreamConfig *videoConfig = videoOutputStream.videoConfig;
videoConfig.videoSizePreset = RCRTCVideoSizePreset1280x720;
videoConfig.videoFps = RCRTCVideoFPS24;
[videoOutputStream setVideoConfig:videoConfig];

[self.room.localUser publishLiveStream:videoOutputStream completion:^(BOOL isSuccess, RCRTCCode code, RCRTCLiveInfo *_Nullable liveInfo) {

}];

屏幕共享 Extension​

屏幕共享 target 在收到录制通知后,需要初始化 RongRTCReplayKitExt 库,并接收系统源数据。

SampleHandler 文件处理​

在系统对应函数中初始化 SDK,接收系统 CMSampleBufferRef 源数据。

初始化屏幕共享引擎​
接口原型​
Objective C
- (void)setupWithAppGroup:(NSString *)appGroup delegate:(id<RCRTCReplayKitEngineDelegate>)delegate;
参数说明​
参数类型是否必填说明
appGroupNSString *是App Group 标识符
delegateid<RCRTCReplayKitEngineDelegate>是屏幕共享引擎代理
发送系统数据​
接口原型​
Objective C
- (void)sendSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType;
参数说明​
参数类型是否必填说明
sampleBufferCMSampleBufferRef是系统采集的数据
sampleBufferTypeRPSampleBufferType是数据类型
提示
  • sampleBufferType 当前支持 RPSampleBufferTypeVideo 和 RPSampleBufferTypeAudioApp 类型的数据帧处理。
  • RPSampleBufferTypeAudioMic 不支持,请在主 app 处理麦克风采集数据
结束广播​
接口原型​
Objective C
- (void)broadcastFinished;
代码示例​
Objective C
#import "SampleHandler.h"
#import <RongRTCReplayKitExt/RongRTCReplayKitExt.h>

static NSString *const ScreenShareGroupID = @"您的屏幕共享 Extension 的 Group ID";

@implementation SampleHandler

- (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *, NSObject *> *)setupInfo {
// 初始化 SDK
[[RCRTCReplayKitEngine sharedInstance] setupWithAppGroup:ScreenShareGroupID delegate:self];
}

- (void)broadcastPaused {
// 广播暂停
}

- (void)broadcastResumed {
// 广播恢复
}

- (void)broadcastFinished {
// 结束处理
[[RCRTCReplayKitEngine sharedInstance] broadcastFinished];
}

- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType API_AVAILABLE(ios(10.0)) {
switch (sampleBufferType) {
case RPSampleBufferTypeVideo:
// 接收系统数据回调
[[RCRTCReplayKitEngine sharedInstance] sendSampleBuffer:sampleBuffer withType:RPSampleBufferTypeVideo];
break;
case RPSampleBufferTypeAudioApp:
// Handle audio sample buffer for app audio
break;
case RPSampleBufferTypeAudioMic:
// Handle audio sample buffer for mic audio
break;
default:
break;
}
}

@end
提示

Broadcast Upload Extension 的内存使用限制为 50 MB,请确保屏幕共享的 Extension 内存使用不超过 50 MB。可以参考 RTC Quick Demo(GitHub · Gitee)内屏幕共享的实现。