屏幕共享

更新时间: 2026/01/06 15:49:38

通过 NEMeeting SDK 可以在会议过程中实现屏幕共享,主讲人或参会者可以将自己的屏幕内容,以视频的方式分享给远端参会者观看,从而提升沟通效率。

  • 视频会议场景中,参会者可以在会议中将本地的文件、数据、网页、PPT 等画面分享给其他与会者,让其他与会者更加直观的了解讨论的内容和主题。

  • 在线课堂场景中,老师可以通过屏幕共享将课件、笔记、教学内容等画面展示给远端的其他学生观看,降低传统教学模式下的沟通成本,提升教育场景的用户体验。

网易云信以辅流的形式实现屏幕共享,即单独为屏幕共享开启一路上行的视频流,摄像头的视频流作为主流,屏幕共享的视频流作为辅流,两路视频流并行,主播同时上行摄像头画面和屏幕画面两路画面。

实现流程

基于 iOS 系统的屏幕共享功能,需要在 App Extension 中通过 iOS 原生的 ReplayKit 特性实现录屏进程,并配合主 App 进程进行推流。需要进行屏幕共享的时候,使用 Apple ReplayKit 框架进行屏幕录制,接收系统采集的屏幕图像,并将其发送给 SDK 以传输视频流数据。

屏幕共享的主要流程包括:

  1. 创建 App Group。 App Group 用于在主 App 进程和扩展程序之间之间进行视频数据和控制指令的传输。
  2. 通过 Xcode 在工程中创建一个 Target。Target 的类型为 Broadcast Upload Extension,用于开启屏幕共享的进程。
  3. 在 Extension 进程中采集录屏数据作为自定义视频源发送给 SDK,并使用 SDK 进行视频流的传输。

注意事项

主进程和系统录屏 Extension 进程需使用相同的 App Group 名以及签名。

配置步骤

第一步:创建 App Group

  1. Certificates, Identifiers & Profiles 页面中注册 App Group。

    操作步骤请参考 注册 App Group

  2. 为您的 App ID 启用 App Group 功能。

    操作步骤请参考 启用 App Group

  3. 重新下载 Provisioning Profile 并配置到 XCode 中。

第二步:创建 Extension 录屏进程

创建一个类型为 Broadcast Upload Extension 的 Target,用于存放屏幕共享功能的实现代码。有关 iOS 主 App 与 Extension 的 Bundle ID 的规则和限制,请参考下文 常见问题

  1. 在 Xcode 中打开项目的工程文件。

  2. 在菜单中选择 Editor > Add Target...

  3. iOS 页签中 选择 Broadcast Upload Extension,并单击 Next

    Add Target
  4. Product Name 中为 Extension 命名,单击 Finish

至此,Xcode 会为此 Extension Target 创建对应的 Group,并自动生成了 SampleHandler.hSampleHandler.m 两个文件。

第三步:在 Extension 进程中采集并发送数据

3.13.0 及之后版本
  1. 在项目的 Podfile 文件中添加 pod 'NEMeetingKit/ScreenShare', '~> 3.13.0',并执行 pod install 命令,引入 NERtcReplayKit framework 依赖。该 framework 封装了数据的采集与发送,供 Extension 进程调用。

    Rubytarget 'BroadcasterExtension' do
    use_frameworks!
    pod 'NEMeetingKit/ScreenShare', '~> 3.13.0'
    end
    
    pod install
    
  2. 请在 SampleHandle.h 文件中添加 iOS 系统类 RPBroadcastSampleHandler 的依赖,以实现录屏功能。

    Objective-C#import <ReplayKit/ReplayKit.h>
    @interface SampleHandler : RPBroadcastSampleHandler
    @end
    
  3. SampleHandle.m 文件中,使用步骤一中创建的 App Group 初始化 NEScreenShareSampleHandler,并设置相关参数,同时需要处理停止直播。

    Objective-C#import "SampleHandler.h"
    #import <NERtcReplayKit/NERtcReplayKit.h>
    
    static NSString *kAppGroup =@"<Your_App_Group>";//具体实现时,只需修改此 kAppGroup 部分。
    
    @interface SampleHandler () <NEScreenShareSampleHandlerDelegate>
    
    @end
    
    @implementation SampleHandler
    
    - (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {
        // User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional.
        NEScreenShareBroadcasterOptions *options = [[NEScreenShareBroadcasterOptions alloc] init];
        options.appGroup = kAppGroup;
        // 设置采集帧率 30 帧
        options.frameRate = 30;
        // 设置需要采集系统音频数据
        options.needAudioSampleBuffer = YES;
        [[NEScreenShareSampleHandler sharedInstance] broadcastStartedWithSetupInfo:options];
        NEScreenShareSampleHandler.sharedInstance.delegate = self;
    }
    
    - (void)broadcastPaused {
        // User has requested to pause the broadcast. Samples will stop being delivered.
        [[NEScreenShareSampleHandler sharedInstance] broadcastPaused];
    }
    
    - (void)broadcastResumed {
        // User has requested to resume the broadcast. Samples delivery will resume.
        [[NEScreenShareSampleHandler sharedInstance] broadcastResumed];
    }
    
    - (void)broadcastFinished {
        // User has requested to finish the broadcast.
        [[NEScreenShareSampleHandler sharedInstance] broadcastFinished];
    }
    
    - (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
        [[NEScreenShareSampleHandler sharedInstance] processSampleBuffer:sampleBuffer
                                                                withType:sampleBufferType];
    }
    
    - (void)onRequestToFinishBroadcastWithError:(NSError *)error {
    [self finishBroadcastWithError:error];
    }
    
    @end
    
3.12.0 及之前版本
  1. 在项目的 Podfile 文件中添加 pod 'NEScreenShareBroadcaster', '~> 0.5.3',并执行 pod install 命令,引入 NEScreenShareBroadcaster framework 依赖。该 framework 封装了数据的采集与发送,供 Extension 进程调用。

    Rubytarget 'BroadcasterExtension' do
    use_frameworks!
    pod 'NEScreenShareBroadcaster', '~> 0.5.3'
    end
    
    pod install
    
  2. SampleHandler.h 文件中添加 ReplayKit 和 NEScreenShareBroadcaster

    请调整代码,使 SampleHandler 类继承于 NEScreenShareSampleHandler,否则会出现对端看到共享的屏幕是黑屏的情况。

    Objective-C#import <ReplayKit/ReplayKit.h>
    #import <NEScreenShareBroadcaster/NEScreenShareBroadcaster.h>
    
    @interface SampleHandler : NEScreenShareSampleHandler
    
    @end
    
  3. SampleHandle.m 文件中使用步骤一中创建的 App Group 初始化 NEScreenShareBroadcaster,并设置相关参数,同时需要处理停止直播的请求。

    Objective-C#import "SampleHandler.h"
    
    static NSString *kAppGroup = @"<Your_App_Group>";//具体实现时,只需修改此 kAppGroup 部分。
    
    @implementation SampleHandler
    
    - (void)setupWithOptions:(NEScreenShareBroadcasterOptions *)options {
        options.appGroup = kAppGroup;
        CGRect screenRect = [[UIScreen mainScreen] bounds];
        CGFloat scale = [UIScreen mainScreen].scale;
        CGFloat screenWidth = screenRect.size.width * scale;
        CGFloat screenHeight = screenRect.size.height * scale;
        options.targetFrameSize = CGSizeMake(0, 0);
    }
    
    #pragma mark - NEScreenShareBroadcasterDelegate
    - (void)onHostRequestFinishBroadcast {
        NSError *error = [NSError errorWithDomain:NSStringFromClass(self.class)
                                            code:0
                                        userInfo:@{
                                            NSLocalizedFailureReasonErrorKey:NSLocalizedString(@"屏幕共享已结束。", nil)
                                        }];
        [self finishBroadcastWithError:error];
    }
    
    @end
    

第四步:初始化会议组件

使用与 Extension 进程相同的 App Group 初始化会议 SDK。

Objective-CNEMeetingKitConfig *config = [[NEMeetingKitConfig alloc] init];
config.appKey = kAppKey; // 会议 AppKey
config.appName = @"APPName";
config.broadcastAppGroup = @"<Your_App_Group>"; // 指定 App Group

// 其他初始化参数设置
// ...

[[NEMeetingKit getInstance] initialize:config
            callback:^(NSInteger resultCode, NSString *resultMsg, id result) {
    if (resultCode == ERROR_CODE_SUCCESS) {
        //TODO when initialize success
    } else {
        //TODO when initalize fail
    }
}];

常见问题

pod 集成出错

如果 pod 集成后,编译出错。如:'sharedApplication' is unavailable: not available on iOS (App Extension) - Use view controller based solutions where appropriate instead.`

请在 podfile 文件中添加如下代码:

post_install do |installer|
    installer.pods_project.targets.each do |target|
        target.build_configurations.each do |config|
            config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'No'
        end
    end
end

iOS 主 App 与 Extension 的 Bundle ID 有什么规则和限制?

Extension 的 Bundle ID 必须以主 App 的 Bundle ID 作为前缀。例如:

  • 主 App:com.example.myapp
  • Extension:com.example.myapp.broadcast

两者必须使用同一 Apple 开发者账号证书签名,并且各自的 Provisioning Profile 中显式包含对应的 Bundle ID(不能使用通配符 *)。

会议中点击屏幕共享,没有“屏幕录制”弹窗?

  • 请确保主进程和系统录屏 Extension 进程已经配置并使用了相同的 App Group 名以及签名。
  • 请检查 Extension 的 Deploy Target Version,创建 Extension 时,Xcode 可能会将 Target 版本设置得比较高,导致该 Extension 无法在较低版本的 iOS 系统中安装。(主工程最低支持 iOS 10,Extensiong 工程最低支持 iOS 12.0

共享成功后,对端看到黑屏画面?

  • 3.13.0 及之后版本

    • 请检查 Extension 代码,确保生成的代码中, SampleHandler 类继承于 RPBroadcastSampleHandler,并确认 SampleHandle 的实现是否与上面提供的代码一致。
    • 请检查 Extension 工程中的 App Group 是否与创建的一致。
  • 3.12.0 及之前版本

    请检查 Extension 代码,确保生成的代码中,SampleHandler 类继承于 NEScreenShareSampleHandler,因为推流操作都是封装在 NEScreenShareSampleHandler 这个类中的。

共享屏幕失败

屏幕共享失败的排查思路如下:

  1. 请检查已生成的 App Group 是否可用,并确认以下设置是否正确:

    • 在 NEMeetingKit 初始化设置中,NEMeetingKitConfig.broadcastAppGroup 参数是否设置为正确的 App Group。

    • 在 SampleHandle.m 文件中,kAppGroup 参数是否设置为正确的 App Group。

    • 在 Xcode 中确认主工程与 Extension 工程配置的 App Groups 是否一致。

  2. 检查 iOS 最低系统版本满足如下要求:

    主工程最低支持 iOS 10,Extensiong 工程最低支持 iOS 12.0

如何处理主进程异常退出的问题?

当处于会议中并开启了屏幕共享时,如果主进程意外退出,则需要您手动停止直播扩展进程。您可通过注册监听进程退出的事件,并调用相应方法停止直播进程。

示例代码如下:

Objective-C@implementation AppDelegate

- (void)applicationWillTerminate:(UIApplication *)application {

    [[[NEMeetingKit getInstance] getMeetingService] stopBroadcastExtension];

}

@end

正常结束或退出会议时不需要您手动停止直播进程。

此文档是否对你有帮助?
有帮助
去反馈
  • 实现流程
  • 注意事项
  • 配置步骤
  • 第一步:创建 App Group
  • 第二步:创建 Extension 录屏进程
  • 第三步:在 Extension 进程中采集并发送数据
  • 第四步:初始化会议组件
  • 常见问题
  • pod 集成出错
  • iOS 主 App 与 Extension 的 Bundle ID 有什么规则和限制?
  • 会议中点击屏幕共享,没有“屏幕录制”弹窗?
  • 共享成功后,对端看到黑屏画面?
  • 共享屏幕失败
  • 如何处理主进程异常退出的问题?