屏幕共享

更新时间: 2025/09/04 15:21:13

在大型会议或在线教育等场景中,为了满足提升沟通效率的需求,主讲人或老师需要将本端的屏幕内容分享给远端参会者或在线学生观看。NERoom 支持屏幕共享功能,帮助您实时分享本端设备的屏幕内容,满足在线教育、互动娱乐、金融面签、视频会议等低延时高互动场景的需求。

功能介绍

通过 NERoom SDK 可以在视频通话中实现屏幕共享,主播或连麦者可以将自己的屏幕内容,以视频的方式分享给远端参会者或在线观众观看,从而提升沟通效率,一般适用于多人视频聊天、在线会议以及在线教育场景。

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

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

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

Android 注意事项

  • 在开始屏幕共享前,请确保已在您的项目中实现基本的实时音视频功能。
  • 您需要先调用 joinRoom 进入房间,再通过 joinRtcChannel 加入音视频房间,才能使用屏幕共享功能。
  • MediaProjection 等 API 需要 Android API level 21+,使用方法请参考 Google MediaProjection API 文档。
  • Android 10 及以后的版本屏幕共享系统要求开启一个前台服务,因此需要在 AndroidManifest.xml 中添加 service,同时将 compileSdkVersion 设置为 29。请根据您的业务需求添加 service。

iOS 注意事项

  • 在开始屏幕共享前,请确保已在您的项目中实现基本的实时音视频功能。
  • 您需要先调用 joinRoom 进入房间,再通过 joinRtcChannel 加入音视频房间,才能使用屏幕共享功能。
  • 屏幕共享功能目前仅适用于 iOS 12.0 及以上版本的系统。
  • 主 App 进程的屏幕共享任务和系统录屏需使用相同的 App Group 名称。

本端共享屏幕

Android端 配置步骤

  1. AndroidManifest.xml 文件中添加前台服务 ScreenShareService
  2. 通过 MediaProjection 创建 ScreenCaptureIntent 请求屏幕共享权限,并将 intent 传递给 startActivityForResult()
  3. 在加入房间之后调用 startScreenShare 方法开启屏幕共享,以辅流形式发送屏幕共享内容。调用此方法时,您需要传入请求权限后返回的 screenShareResultData,并设置 MediaProjection.Callback() 以接收屏幕共享状态回调。
  4. 开启屏幕共享后,房间内其他成员会收到 MemberScreenShareStateChanged 回调,通知房间内其他成员关于您屏幕共享状态的变更。
  5. 若您要结束屏幕共享,请调用 stopScreenShare 方法关闭辅流形式的屏幕共享。

示例代码

dart//需要在 AndroidManifest.xml 中添加前台服务
       <service
            android:name=".services.ScreenShareService"
            android:foregroundServiceType="mediaProjection">
            <intent-filter>
                <action android:name="com.netease.Yunxin.ScreenShare" />
            </intent-filter>
        </service>
        
public class RoomActivity extends AppCompatActivity {
    private ScreenShareServiceConnection mServiceConnection;
    private ScreenShareService mScreenService;
      private class ScreenShareServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            if (service instanceof ScreenShareService.ScreenShareBinder) {
                mScreenService = ((ScreenShareService.ScreenShareBinder) service).getService();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mScreenService = null;
        }
    }

    private ActivityResultLauncher<Intent> launcher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {

                @Override
                public void onActivityResult(ActivityResult result) {
                    ALog.d(TAG, "onActivityResult,result:" + result.getResultCode());
                    if (result.getResultCode() == Activity.RESULT_OK) {
                        mScreenService.startScreenShare(currentRoomContext.getRtcController(), result.getData(),
                                new MediaProjection.Callback() {

                                    @Override
                                    public void onStop() {
                                        super.onStop();
                                        Log.d(TAG,"屏幕共享结束");
                                    }
                                }, new NECallback<Unit>() {

                                    @Override
                                    public void onResult(int code, @Nullable String message, @Nullable Unit unit) {
                                        ALog.d(TAG, "code:" + code);
                                        if (code == NEErrorCode.SUCCESS) {
                                            Log.d(TAG,"开始屏幕共享");
                                        }
                                    }
                                });
                    }
                }
            });
            
      @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_room);
        bindScreenService();
           findViewById(R.id.startScreenShare).setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(
                        Context.MEDIA_PROJECTION_SERVICE);
                launcher.launch(mediaProjectionManager.createScreenCaptureIntent());
            }
        });
        findViewById(R.id.stopScreenShare).setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                mScreenService.stopScreenShare(currentRoomContext.getRtcController(), new NECallback<Unit>() {

                    @Override
                    public void onResult(int code, @Nullable String message, @Nullable Unit unit) {
                        Log.d(TAG,"结束屏幕共享");
                    }
                });
            }
        });
    }
    
        @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindScreenService();
    }
    
     private void bindScreenService() {
        Intent intent = new Intent();
        intent.setClass(this, ScreenShareService.class);
        mServiceConnection = new ScreenShareServiceConnection();
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }
    
       private void unbindScreenService() {
        if (mServiceConnection != null) {
            unbindService(mServiceConnection);
        }
    }
}

iOS 配置步骤

步骤一 创建 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,用于存放屏幕共享功能的实现代码。

  1. 在 Xcode 中打开项目的工程文件。
  2. 在菜单中选择 Editor > Add Target
  3. iOS 页签中 选择 Broadcast Upload Extension,并单击 Next
  4. Product Name 中为 Extension 命名,然后单击 Finish

步骤三 引入 NEScreenShareBroadcaster 库

在主工程的 podfile 文件中引入 NEScreenShareBroadcaster 库。

pod 'NEScreenShareBroadcaster', '0.5.0'

步骤四 创建继承自 NEScreenShareSampleHandler 的类

在 extension 中创建继承自 NEScreenShareSampleHandler 的类。

// .h文件内容
#import <ReplayKit/ReplayKit.h>
#import <NEScreenShareBroadcaster/NEScreenShareBroadcaster.h>

@interface SampleHandler : NEScreenShareSampleHandler

@end

// .m内容
@implementation SampleHandler

- (void)setupWithOptions:(NEScreenShareBroadcasterOptions *)options {
    options.appGroup = @"your App Group";
    options.frameRate = 10;
    options.targetFrameSize = CGSizeMake(720, 0);
}

@end

观看远端屏幕共享

注意事项

必须在指定用户开启了屏幕共享辅流通道后,即收到 MemberScreenShareStateChanged 回调后,才能订阅该远端用户的辅流。

配置步骤

  1. 远端用户加入音视频房间。
  2. 收到 MemberScreenShareStateChanged 其他用户开启屏幕共享辅流通道的回调。
  3. 调用 subscribeRemoteSubStreamVideo 方法订阅远端的屏幕共享辅流视频,订阅之后才能接收远端的辅流视频数据。调用此方法时,您需要设置指定用户的 uid。
  4. 收到 MemberScreenShareStateChanged 其他用户关闭屏幕共享辅流通道的回调,结束屏幕共享。

示例代码

dartif (remoteMember.isSharingScreen()) {
  NERoomService roomService = NERoomKit.instance.roomService;
  NERoomContext? roomContext = roomService.getRoomContext(roomUuid);
  roomContext?.rtcController.subscribeRemoteSubStreamVideo(remoteMember.uuid).then((result){
    if(result.isSuccess()){
      debugPrint('subscribeRemoteSubStreamVideo success');
    }else{
      debugPrint('subscribeRemoteSubStreamVideo error code ${result.code},msg:${result.msg}');
    }
  });
}

关闭某成员的屏幕共享

在会议等场景中,主持人可以关闭某成员的屏幕共享。

您可以在云信控制台上配置某角色是否具备该权限,只有具备该权限的角色才可以执行此操作。

配置步骤

  1. 调用 stopMemberScreenShare 关闭房间内某成员的屏幕共享。

    参数 说明
    userUuid 待关闭屏幕共享的成员的 uuid。
    callback 回调
  2. 房间内其他成员会收到 MemberScreenShareStateChanged 回调,通知房间内其他成员关于屏幕共享状态的变更。

示例代码

dartNERoomService roomService = NERoomKit.instance.roomService;
  NERoomContext? roomContext = roomService.getRoomContext(roomUuid);
  roomContext?.rtcController.stopMemberScreenShare(remoteMember.uuid).then((result){
    if(result.isSuccess()){
      debugPrint('stopMemberScreenShare success');
    }else{
      debugPrint('stopMemberScreenShare error code ${result.code},msg:${result.msg}');
    }
  });

监听共享状态示例代码如下:

dartNERoomService roomService = NERoomKit.instance.roomService;
NERoomContext? roomContext = roomService.getRoomContext(roomUuid);
roomContext?.addEventCallback(NERoomEventCallback(
memberScreenShareStateChanged: (member, isSharing, operator){
    debugPrint('memberScreenShareStateChanged isSharing:$isSharing');
}
));

API 参考

方法 功能描述
joinRoom 加入 NERoom 的房间
joinRtcChannel 加入音视频房间
startScreenShare 开始屏幕共享
stopScreenShare 结束屏幕共享
MemberScreenShareStateChanged 成员屏幕共享状态回调
stopMemberScreenShare 关闭房间内某成员的屏幕共享
此文档是否对你有帮助?
有帮助
去反馈
  • 功能介绍
  • Android 注意事项
  • iOS 注意事项
  • 本端共享屏幕
  • Android端 配置步骤
  • 示例代码
  • iOS 配置步骤
  • 观看远端屏幕共享
  • 注意事项
  • 配置步骤
  • 示例代码
  • 关闭某成员的屏幕共享
  • 配置步骤
  • 示例代码
  • API 参考