You need to enable JavaScript to run this app.
企业直播

企业直播

复制全文
iOS 开播 SDK
进阶功能
复制全文
进阶功能

本文介绍如何实现 iOS 开播 SDK 的进阶功能。

前提条件

您已集成 iOS 开播 SDK。详见 集成 iOS 开播 SDK

录屏直播

主持人可以实时共享屏幕画面,而无需有线或无线连接的繁琐步骤,大大降低了直播门槛。录屏直播适用于游戏直播或演示效果直播等场景。

注意

  • 该功能仅适用于 iOS 12 及以上版本。
  • iOS 16.4 硬编存在问题,会导致直播画面模糊。

完成以下步骤实现该功能:

  1. 在项目的 Podfile 文件中添加 ScreenShare 依赖。

    # 只集成开播 SDK
      pod'BDLive', '1.65.2', :subspecs => [
        'LiveStreaming',
        'ScreenShare' 
      ]
      
    # 同时集成开播 SDK 和观播 SDK
      pod'BDLive', '1.65.2', :subspecs => [
       'LiveStreaming',
       'Viewer',
       'ScreenShare'
      ]
    end
    
  2. 打开终端窗口,执行 cd 命令进入您的项目目录。执行 pod install 命令安装依赖。

  3. 在 Xcode 中,完成以下步骤,创建屏幕共享扩展的 Target。

    1. 单击 File > New > Target
      Image
    2. iOS 页签下,选择 Broadcast Upload Extension,即屏幕共享扩展。单击 Next
      Image
    3. 输入 Target 名称并单击 Finish
      Image

      说明

      • 录屏直播功能暂不支持 Broadcast Setup UI Extension 扩展。如需自定义录屏直播的界面 UI,您必须实现 Broadcast Setup UI Extension 扩展的必要逻辑并选择 Include UI Extension 复选框。
      • 请将屏幕共享扩展的 Bundle Identifier 记录在某个安全的地方。在步骤 7 中,您必须将该 Bundle Identifier 传入 SDK。
  4. 在 Xcode 中完成以下步骤,实现屏幕共享扩展和 App 之间的数据共享。

    1. 进入步骤 3 中创建的扩展 Target 中。

    2. 单击 Signing & Capabilities 页签并单击 + Capability
      Image

    3. 双击对话框中的 App Groups
      Image

    4. 单击 App Groups 区域的 +

      说明

      如果您有可用的 App Group,可直接选中该 App Group 而无需新建。请将该 App Group 的 Container ID 记录在某个安全的地方。在步骤 6 和 7 中,您必须将该 Container ID 传入 SDK。

    5. 在弹出的对话框中,输入以 group. 开头的 Container ID 并单击 OK

      注意

      请将该 Container ID 记录在某个安全的地方。在步骤 6 和 7 中,您必须将该 Container ID 传入 SDK。

      Image
      App Group 新建成功后,会自动在 App Groups 区域中被选中。

    6. 进入 App Target 中,重复步骤 4-b4-c。在 App Groups 区域中,选择在扩展 Target 中被选中的 App Group。

    详见 Configuring App Groups

  5. 在 Xcode 中,完成以下步骤,实现屏幕采集的逻辑。

    1. 进入步骤 3 中创建的扩展 Target 中。
    2. General 页签下,单击 Frameworks and Libraries 区域的 +
      Image
    3. 在弹出的对话框中,选择项目下的 VolcEngineRTCScreenCapturer.xcframework 并单击 Add
      Image
    4. VolcEngineRTCScreenCapturer.xcframework 的嵌入方法设置为 Do Not Embed
      Image

      说明

      录屏直播功能仅对 Deployment Info 区域选定版本及以上的 iOS 设备可见。

  6. 在步骤 3 中创建的扩展 Target 中,Xcode 自动创建以下文件:SampleHandler.hSampleHandler.m。在 Xcode 中打开 SampleHandler.m 文件,实现屏幕采集逻辑。示例代码如下所示。

    #import "SampleHandler.h"
    #import <VolcEngineRTCScreenCapturer/ByteRTCScreenCapturerExt.h>
    
    @interface SampleHandler () <ByteRtcScreenCapturerExtDelegate>
    
    @property (nonatomic, assign) BOOL shouldScreenShare;
    
    @end
    
    @implementation SampleHandler
    
    - (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {
        // groupId:步骤 4 中选中的 App Group 的 Container ID
        [[ByteRtcScreenCapturerExt shared] startWithDelegate:self groupId:xxx];
        // 如果主持人在 App 的预览页(即可选择录屏直播的页面)中,屏幕共享扩展将收到 App 发出的 onNotifyAppRunning 回调。如果扩展在 2 秒内没有收到 onNotifyAppRunning 回调,则认为主持人未在 App 的预览页,您应该通过调用 finishBroadcastWithError: 方法停止屏幕采集
        // 按需自定义 NSLocalizedFailureReasonErrorKey 的值
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            if (!self.shouldScreenShare) {
                NSDictionary *dic = @{
                    NSLocalizedFailureReasonErrorKey : @"The host is not in the live room"};
                NSError *error = [NSError errorWithDomain:RPRecordingErrorDomain
                                                     code:RPRecordingErrorUserDeclined
                                                 userInfo:dic];
                [self finishBroadcastWithError:error];
            }
        });
    }
    
    
    - (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
    
        // 混流
        switch (sampleBufferType) {
            case RPSampleBufferTypeVideo: // 采集到的屏幕视频流
            case RPSampleBufferTypeAudioApp: // 采集到的设备音频流
                [[ByteRtcScreenCapturerExt shared] processSampleBuffer:sampleBuffer withType:sampleBufferType]; // 使用该方法,将采集到的屏幕视频流和设备音频流推送至观看页
                break;
            case RPSampleBufferTypeAudioMic:
                // 采集到的麦克风音频流
                // 开播 SDK 实现了麦克风音频流的采集并将其推送至观看页。因此,您无需在此处理麦克风音频流
                break;
    
            default:
                break;
        }
    }
    
    /// 在主持人停止共享屏幕时触发该回调,通知您停止屏幕采集
    - (void)onQuitFromApp {
        // 按需自定义 NSLocalizedFailureReasonErrorKey 的值
        NSDictionary *dic = @{
            NSLocalizedFailureReasonErrorKey : @"You stopped sharing the screen"};
        NSError *error = [NSError errorWithDomain:RPRecordingErrorDomain
                                             code:RPRecordingErrorUserDeclined
                                         userInfo:dic];
        [self finishBroadcastWithError:error];
    }
    
    /// App 在后台被终止时触发该回调,通知您停止屏幕采集
    - (void)onSocketDisconnect {
        // 按需自定义 NSLocalizedFailureReasonErrorKey 的值
        NSDictionary *dic = @{
            NSLocalizedFailureReasonErrorKey : @"Disconnected"};
        NSError *error = [NSError errorWithDomain:RPRecordingErrorDomain
                                             code:RPRecordingErrorUserDeclined
                                         userInfo:dic];
        [self finishBroadcastWithError:error];
    }
    
    /// 检测到 App 正在运行时触发该回调
    - (void)onNotifyAppRunning {
        self.shouldScreenShare = YES;
    }
    
    @end
    
  7. 在 Xcode 的 App Target 中,打开定义如何进入直播间的文件并添加以下代码。详见进入直播间

    if (@available(iOS 12.0, *)) {
       model.extensionBundleId = @"BUNDLE_ID"; // 将 BUNDLE_ID 替换为屏幕共享扩展的 Bundle Identifier
       model.groupId = @"GROUP_ID"; // 将 GROUP_ID 替换为步骤 4 中选中的 App Group 的 Container ID
    }
    

自定义消息

BDLCustomIMService

收到自定义的 IM(长链接消息)信令。
IM 信令消息目前适用于发送自定义消息的场景,您可以通过监听自定义消息实现自己的业务逻辑。

onReceiveIMString:

自定义的 IM 信令收到回调。

- (void)onReceiveIMString:(NSString *)string;

参数

名称

类型

说明

string

NSString

通过 SendCustomSystemMessageAPI 接口发送的自定义的 IM 信令。

onConnected

IM 建立连接成功回调。

- (void)onConnected;

onConnectFailed

IM 建立连接失败回调。

- (void)onConnectFailed;

自定义美颜

新增、修改或删除美颜。

注意

  • 如需增加美颜,请联系 CV 技术支持获取美颜文件。
  • 修改美颜指修改美颜在开播页的图标名称和样式。

以下示例代码新增、修改、删除了指定美颜:

model.effectConfig.customizeBeauties = ^(NSMutableArray<BDLEffectBeautyModel *> * _Nonnull beauties) {
    // 美颜文件的 bundle 目录
    NSString *beautyPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"ComposeMakeup.bundle"];
    
    [beauties enumerateObjectsUsingBlock:^(BDLEffectBeautyModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        // 修改美颜在开播页的图标名称和样式。此处以修改 beautyKey 为 whiten 的美颜为例。请联系企业直播技术支持获取美颜对应的 beautyKey
        if ([obj.beautyKey isEqualToString:@"whiten"]) {
            obj.name = [NSString stringWithFormat:@"TT %@", beauties.firstObject.name]; // 美颜图标在开播页展示的名称
            // 您可以通过 iconURL(图片的本地路径或网络地址)或 iconName(assets 中的图片名称)设置美颜图标。此处以通过 iconName 设置美颜图标为例
            obj.iconURL = nil;
            obj.iconName = @"uncheck";
            *stop = YES;
        }
    }];
    
    [beauties.copy enumerateObjectsUsingBlock:^(BDLEffectBeautyModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        // 删除美颜。此处以删除 beautyKey 为 Internal_Deform_Overall 的美颜为例。请联系企业直播技术支持获取美颜对应的 beautyKey
        if ([obj.beautyKey isEqualToString:@"Internal_Deform_Overall"]) {
            [beauties removeObject:obj];
            *stop = YES;
        }
    }];
    
    // 新增美颜
    BDLEffectBeautyModel *model = [[BDLEffectBeautyModel alloc] init];
    // 美颜图标在开播页展示的名称
    model.name = @"Name";
    // 美颜文件的资源目录。请联系 CV 技术支持获取美颜文件
    model.resFilePath = [beautyPath stringByAppendingPathComponent:@"ComposeMakeup/reshape_lite"];
    // 您可以通过 iconURL(图片的本地路径或网络地址)或 iconName(assets 中的图片名称)设置美颜图标。此处以通过 iconName 设置美颜图标为例
    model.iconName = @"bdl_bottom_button_product";
// 您可以通过 iconURL(图片的本地路径或网络地址)或 iconName(assets 中的图片名称)设置美颜图标。此处以通过 iconURL 设置美颜图标为例
//  model.iconURL = [NSURL fileURLWithPath:[beautyPath stringByAppendingPathComponent:@"icon/icon_naixiong.png"]];
    // 美颜对应的 beautyKey。请联系企业直播技术支持获取
    model.beautyKey = @"Internal_Deform_Overall";
    // 美颜配置是否正确
    BOOL isValid = [model isValid];
    if (!isValid) {
        NSLog(@"Model is not Valid, model: %@", model);
    }
    // 将美颜添加至美颜列表中的第一个
    [beauties insertObject:model atIndex:0];
};

自定义滤镜

新增、修改或删除滤镜。

注意

  • 如需增加滤镜,请联系 CV 技术支持获取滤镜文件。
  • 修改滤镜指修改滤镜在开播页的图标名称和样式。

以下示例代码新增、修改、删除了指定滤镜:

model.effectConfig.customizeFilters = ^(NSMutableArray<BDLEffectFilterModel *> * _Nonnull filters) {
    // 滤镜文件的 bundle 目录
    NSString *filterPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"FilterResource.bundle"];
    
 
    [filters enumerateObjectsUsingBlock:^(BDLEffectFilterModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
       // 修改滤镜在开播页的图标名称和样式。此处以修改滤镜 ID 为 01 的滤镜为例
        if ([obj.filterId isEqualToString:@"01"]) {
            obj.name = [NSString stringWithFormat:@"TT %@", filters.firstObject.name]; // 滤镜图标在开播页展示的名称
            // 您可以通过 iconURL(图片的本地路径或网络地址)或 iconName(assets 中的图片名称)设置滤镜图标。此处以通过 iconName 设置滤镜图标为例
            obj.iconURL = nil;
            obj.iconName = @"AppIcon";
            *stop = YES;
        }
    }];
    
    // 删除滤镜。此处以删除滤镜 ID 为 33 的滤镜为例
    [filters.copy enumerateObjectsUsingBlock:^(BDLEffectFilterModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj.filterId isEqualToString:@"33"]) {
            [filters removeObject:obj];
            *stop = YES;
        }
    }];
    
    // 新增滤镜
    BDLEffectFilterModel *model = [[BDLEffectFilterModel alloc] init];
    // 滤镜图标在开播页展示的名称
    model.name = @"Name";
    // 滤镜文件的资源目录。请联系 CV 技术支持获取滤镜文件
    model.resFilePath = [filterPath stringByAppendingPathComponent:@"Filter/Filter_33_L1"];
    // 您可以通过 iconURL(图片的本地路径或网络地址)或 iconName(assets 中的图片名称)设置滤镜图标。此处以通过 iconName 设置滤镜图标为例
    model.iconName = @"AppIcon";
// 您可以通过 iconURL(图片的本地路径或网络地址)或 iconName(assets 中的图片名称)设置滤镜图标。此处以通过 iconURL 设置滤镜图标为例
//  model.iconURL = [NSURL fileURLWithPath:[filterPath stringByAppendingPathComponent:@"icon/xx.png"]];
    // 滤镜配置是否正确
    BOOL isValid = [model isValid];
    if (!isValid) {
        NSLog(@"Model is not Valid, model: %@", model);
    }
    // 将滤镜添加至滤镜列表中的第一个
    [filters insertObject:model atIndex:0];
};

自定义道具贴纸

新增、修改或删除道具贴纸。

注意

  • 如需增加道具贴纸,请联系 CV 技术支持获取贴纸文件。
  • 修改道具贴纸指修改贴纸在开播页的图标样式。

以下示例代码新增、修改、删除了指定道具贴纸:

model.effectConfig.customizeStickers = ^(NSMutableArray<BDLEffectStickerModel *> * _Nonnull stickers) {
    // 贴纸文件的 bundle 目录
    NSString *stickerPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"StickerResource.bundle"];
    // 修改道具贴纸在开播页的图标样式。此处以修改文件目录包含 stickers_sd_gan 的贴纸为例
    [stickers enumerateObjectsUsingBlock:^(BDLEffectStickerModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj.resFilePath containsString:@"stickers_sd_gan"]) {
            // 您可以通过 iconURL(图片的本地路径或网络地址)或 iconName(assets 中的图片名称)设置贴纸图标。此处以通过 iconName 设置贴纸图标为例
            obj.iconURL = nil;
            obj.iconName = @"check";
            *stop = YES;
        }
    }];
    
    // 删除道具贴纸。此处以删除文件目录包含 tryon_nail_zhuanhongse 的贴纸为例
    [stickers.copy enumerateObjectsUsingBlock:^(BDLEffectStickerModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj.resFilePath containsString:@"tryon_nail_zhuanhongse"]) {
            [stickers removeObject:obj];
            *stop = YES;
        }
    }];
    
    // 新增道具贴纸
    BDLEffectStickerModel *model = [[BDLEffectStickerModel alloc] init];
    // 贴纸文件的资源目录。请联系 CV 技术支持获取贴纸文件
    model.resFilePath = [stickerPath stringByAppendingPathComponent:@"stickers/tryon_nail_zhuanhongse"];
// 您可以通过 iconURL(图片的本地路径或网络地址)或 iconName(assets 中的图片名称)设置贴纸图标。此处以通过 iconName 设置贴纸图标为例
// model.iconName = @"AppIcon";
    // 您可以通过 iconURL(图片的本地路径或网络地址)或 iconName(assets 中的图片名称)设置贴纸图标。此处以通过 iconURL 设置贴纸图标为例
    model.iconURL = [NSURL fileURLWithPath:[stickerPath stringByAppendingPathComponent:@"icon/xx.png"]];
    // 贴纸配置是否正确
    BOOL isValid = [model isValid];
    if (!isValid) {
        NSLog(@"Model is not Valid, model: %@", model);
    }
    // 将贴纸添加至贴纸列表中的第一个
    [stickers insertObject:model atIndex:0];
};
最近更新时间:2025.11.26 13:58:32
这个页面对您有帮助吗?
有用
有用
无用
无用