You need to enable JavaScript to run this app.
导航
基础功能
最近更新时间:2024.12.12 21:20:40首次发布时间:2024.02.21 18:10:11

本文介绍 iOS 观播 SDK 的基础功能接入方法,包括如何接入完整直播间、完整播放器、独立播放器以及浮窗播放器。

说明

目前仅支持同时进入一个直播间。

前提条件

您已完成集成 iOS 观播 SDK 的前 5 步。

功能列表

本文介绍以下功能的接入方法。

完整直播间

完整直播间包含企业直播直播间的所有功能模块,相较于模块化接入,更为简单、便捷。如无特殊需求,推荐接入完整直播间。
Image
有关完整直播间支持的具体功能,详见 功能列表

进入直播间

您可以通过以下示例代码,让观众进入完整直播间并在 App 内显示完整直播间页面。

...
[[BDLLiveEngine sharedInstance] joinLiveRoomWithActivity:activity
                                                 success:^{
    // 1. 获取完整直播间实例。
    BDLLivePullViewController *livePullVC = [[BDLLiveEngine sharedInstance] getLivePullViewController];
    // 2.(可选)设置 modalPresentationStyle,即直播间的显示方式。此处以全屏显示直播间为例。
    // 如选择通过 UINavigationController 的 push 方式显示直播间,或者选择系统默认方式显示直播间,则无需额外配置。
    livePullVC.modalPresentationStyle = UIModalPresentationFullScreen;
    // 3. 设置 actionProvider。此处以 self 为例,用以响应直播间的显示、隐藏等事件。
    livePullVC.actionProvider = self;
    // 4. (可选)配置直播间。
    [self configLivePullViewController:livePullVC];
    // 5. 显示直播间。此处以 present 方式显示直播间为例。
    // 如需通过 UINavigationController 的 push 方式显示直播间,详见以 push 方式显示直播间。
    [self showLivePullViewController:livePullVC];
} failure:^(NSError * _Nonnull error) {
    // 处理错误信息。在该示例中,错误信息将打印至控制台,以便调试与排查问题。
    NSLog(@"%@", error.localizedDescription);
}];

/// 配置直播间,包括定制 UI。您可将功能代码复制到该方法内运行。
- (void)configLivePullViewController:(BDLLivePullViewController *)livePullVC {
}

/// 6. 实现 actionProvider 所需的方法。
/// 6.1 实现直播间显示的方法。
/// 显示直播间。当需要显示完整直播间时,SDK 会调用该方法。此处以 present 方式显示直播间为例。
/// 如需通过 UINavigationController 的 push 方式显示直播间,详见以 push 方式显示直播间。
- (void)showLivePullViewController:(BDLLivePullViewController *)livePullVC {
    [self presentViewController:livePullVC animated:NO completion:nil];
}

/// 6.2 实现直播间隐藏的方法。
/// 隐藏直播间。当需要隐藏完整直播间时,SDK 会调用该方法。
- (void)hideLivePullViewController:(BDLLivePullViewController *)livePullVC {
    [self dismissViewControllerAnimated:YES completion:nil];
}

以 push 方式显示直播间

如需通过 UINavigationControllerpush 方式显示完整直播间,可参考以下流程。

说明

仅 SDK 1.29.1 及以上版本支持 push 方式。

  1. 在获取完整直播间实例后,配置浮窗播放器(即 InApp 画中画)的显示逻辑。

    1. 配置是否显示浮窗播放器。

      /// 在直播状态发生变化时,触发该回调并向 App 传入完整直播间实例、直播状态、是否关闭直播间页面。
      livePullVC.config.shouldShowInAppPipIfAvailable = ^BOOL(BDLLivePullViewController * _Nonnull viewController, BDLActivityStatus status, BOOL isClose) {
          /// 根据直播状态和是否关闭直播间页面,判断是否显示浮窗播放器。
          switch (status) {
              case BDLActivityStatusLive: // 如果直播状态是直播中,执行以下逻辑。
                  return isClose ? YES : NO; // 此处以通过 pop 或 dismiss 操作关闭直播间页面时显示浮窗播放器(isClose 为 YES 时返回 YES)、通过 push 或 present 方式显示商品详情页等新页面时不显示浮窗播放器(isClose 为 NO 时返回 NO)为例。
              case BDLActivityStatusReplay: // 如果直播状态是回放,执行以下逻辑。
                  return isClose ? YES : NO; // 此处以通过 pop 或 dismiss 操作关闭直播间页面时显示浮窗播放器(isClose 为 YES 时返回 YES)、通过 push 或 present 方式显示商品详情页等新页面时不显示浮窗播放器(isClose 为 NO 时返回 NO)为例。
              case BDLActivityStatusPreview: // 如果直播状态是预告且在播放预告片,执行以下逻辑。
                  return isClose ? YES : NO; // 此处以通过 pop 或 dismiss 操作关闭直播间页面时显示浮窗播放器(isClose 为 YES 时返回 YES)、通过 push 或 present 方式显示商品详情页等新页面时不显示浮窗播放器(isClose 为 NO 时返回 NO)为例。
              default:
                  return NO; // 不显示浮窗播放器。正常情况下不会触发该逻辑,但为避免报错,需设置该默认返回值。
          }
      };
      
    2. 配置在 viewDidAppear 时(即完整直播间对应的 View 已经显示时)是否自动关闭正在显示的浮窗播放器。
      以下示例代码将自动关闭正在显示的浮窗播放器:

      livePullVC.config.autoCloseFloatingPlayerWhenAppear = YES;
      

      如果取值为 NO,则需在合适的时机调用关闭浮窗播放器的方法。
      以下示例代码在关闭浮窗播放器的同时,显示完整直播间。

      [livePullVC hideFloatingPlayerIfAvailable:YES]
      
  2. 显示完整直播间。
    示例代码如下所示。

    - (void)showLivePullViewController:(BDLLivePullViewController *)livePullVC {
        if (self.livePullVC.navigationController) { // 已通过 push 方式显示完整直播间,但完整直播间上存在其他页面(ViewController)。
            [self.navigationController popToViewController:livePullVC animated:YES]; // 通过 pop 操作移除完整直播间上的其他页面(ViewController)。
            return;
        }
        [self.navigationController pushViewController:livePullVC animated:YES]; // 以 push 方式显示完整直播间。
    }
    
  3. (可选)如果您在步骤 1.a 设置 isCloseNO 时返回 YES,即通过 pushpresent 方式显示商品详情页等新页面时显示浮窗播放器,需要修改是否执行浮窗播放器关闭按钮的默认点击行为。
    示例代码如下所示。

    __weak typeof(self) weakSelf = self;
        livePullVC.onFloatingPlayerCloseTapped = ^BOOL(BDLLivePullViewController * _Nonnull viewController, BDLFloatingPlayer * _Nonnull floatingPlayer) {
            if (viewController.navigationController) {
                // 通过 push 或 present 方式显示商品详情页等新页面时,点击浮窗播放器的关闭按钮,SDK 关闭浮窗播放器、不显示完整直播间,但不离开直播间。
                [viewController hideFloatingPlayerIfAvailable:NO];
                return NO;
            }
            else {
                // 通过 pop 或 dismiss 操作关闭直播间页面时,点击浮窗播放器的关闭按钮,SDK 会执行默认的点击行为,即关闭浮窗播放器并离开直播间。
                return YES;
            }
        };
    
  4. (可选)由于完整直播间除全屏模式外仅支持竖屏显示,如果 App 页面支持横屏显示,请完成以下配置:

    • 确保在显示完整直播间页面时,前置页面(进入直播间页面前的 App 页面)仅支持竖屏显示。
      示例代码如下所示。

      // 在 ViewController 中添加以下代码。
      @interface ViewController : UIViewController
      @property (nonatomic, assign) BOOL visible;
      @end
      
      // 在 viewDidAppear 时(即前置页面对应的 View 已经显示时),将 visible 设置为 YES,表示当前视图可见。
      - (void)viewDidAppear:(BOOL)animated {
          [super viewDidAppear:animated];
          self.visible = YES;
      }
      // 在 viewDidDisappear 时(即前置页面对应的 View 已经消失时),将 visible 设置为 NO,表示当前视图不可见。
      - (void)viewDidDisappear:(BOOL)animated {
          [super viewDidDisappear:animated];
          self.visible = NO;
      }
      
      // 指定当前视图支持的页面方向。
      - (UIInterfaceOrientationMask)supportedInterfaceOrientations {
          if (!self.visible) { // 当前视图不可见时,直播间内仅支持竖屏,避免侧滑返回前置页面导致显示异常。
              return UIInterfaceOrientationMaskPortrait;
          }
          // 当前视图可见时,前置页面支持的页面方向。此处以前置页面支持除 UpsideDown 以外的所有方向为例。
          return UIInterfaceOrientationMaskAllButUpsideDown;
      }
      
    • 在横屏展示直播间页面时(即全屏模式时)禁用侧滑返回,防止页面显示异常。

      // 在 ViewController 中添加以下代码。
      // 在横竖屏即将切换时,系统会调用该方法。
      - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
          if (size.width > size.height) { // 宽大于高,即横屏显示页面。
              self.navigationController.interactivePopGestureRecognizer.enabled = NO; // 禁用侧滑返回。
          }
          else {
              self.navigationController.interactivePopGestureRecognizer.enabled = YES; // 启用侧滑返回。
          }
      }
      
    • 确保在横竖屏切换时,将浮窗播放器的显示方向与 App 的当前页面方向保持一致。

      // 在 NavigationController 中或者 UIViewController 中添加以下代码。
      
      #import <BDLive/BDLLiveEngine.h>
      @interface ViewController : UIViewController
      //NOTE: 需要在获取完整直播间实例时对 livePullViewController 赋值。
      @property (nonatomic, weak) BDLLivePullViewController *livePullViewController;
      @end
      
      // 在横竖屏即将切换时,系统会调用该方法。
      - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
          [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
      // 获取 App 的当前页面方向。    
          UIInterfaceOrientation orientation = UIInterfaceOrientationUnknown;
          if (@available(iOS 13, *)) {
              // 如果使用 self.view.window,则会在 ViewController 不可见时返回 nil,因此请使用 self.navigationController.view.window。
              orientation = self.navigationController.view.window.windowScene.interfaceOrientation;
          } else {
              orientation = UIApplication.sharedApplication.statusBarOrientation;
          }
          // 先显示完整直播间再显示浮窗播放器,需要调整 livePullViewController.floatingPlayerOrientation,将浮窗播放器的显示方向与 App 的当前页面方向保持一致。
          if (self.livePullViewController.isFloating) {
              self.livePullViewController.floatingPlayerOrientation = orientation;
          }
          // 直接显示浮窗播放器时,需要调整 floatingPlayer,将浮窗播放器的显示方向与 App 的当前页面方向保持一致。
          if (self.floatingPlayer) {
              [self.floatingPlayer setUIOrientation:orientation];
          }
      }
      

离开直播间

当需要让观众离开直播间页面时,例如观众观看权限不足时,可通过以下示例代码实现。

- (void)leaveLiveRoom {
    [[BDLLiveEngine sharedInstance] leaveLiveRoom];
}

完整示例代码

以下示例展示了以 present 的方式显示直播间活动 ID(activityId)为 167808997736****tokenJQ****、鉴权模式(authMode)为公开模式的竖屏直播间。您可以按需修改相关参数值。

说明

- (void)joinLiveRoom {    
    BDLActivity *activity = [[BDLActivity alloc] init];
    activity.activityId = @(167808997736****);
    activity.token = @"JQ****";
    activity.isPortrait = YES;
    activity.authMode = BDLActivityAuthModePublic;
    
    [[BDLLiveEngine sharedInstance] joinLiveRoomWithActivity:activity
                                                     success:^{
        BDLLivePullViewController *livePullVC = [[BDLLiveEngine sharedInstance] getLivePullViewController];
        livePullVC.modalPresentationStyle = UIModalPresentationFullScreen;
        livePullVC.actionProvider = self;
        [self configLivePullViewController:livePullVC];
        [self showLivePullViewController:livePullVC];
    } failure:^(NSError * _Nonnull error) {
        NSLog(@"%@", error.localizedDescription);
    }];
}

- (void)leaveLiveRoom {
    [[BDLLiveEngine sharedInstance] leaveLiveRoom];
}

- (void)configLivePullViewController:(BDLLivePullViewController *)livePullVC {
}

- (void)showLivePullViewController:(BDLLivePullViewController *)livePullVC {
    [self presentViewController:livePullVC animated:NO completion:nil];
}

- (void)hideLivePullViewController:(BDLLivePullViewController *)livePullVC {
    [self dismissViewControllerAnimated:YES completion:nil];
}

完整播放器

如果您具备自有的观看页面,并且对播放器的控制界面无自定义需求,可以选择只接入完整播放器。
Image

进入直播间

您可以通过以下示例代码,进入直播间并创建完整播放器。

@interface ViewController ()
@property (nonatomic, strong) BDLPlayerView *playerView;
@end

    ...
    [[BDLLiveEngine sharedInstance] joinLiveRoomWithActivity:activity
                                                     success:^{
        // 创建一个带控制界面的播放器,即播放器内包含播放按钮等互动按钮。此处以竖屏模式初始化播放器为例。
        self.playerView =[[BDLPlayerView alloc] initWithPortrait:YES];
        // 将 popupSuperView 设置为当前 view。SDK 内部默认实现了倍速、清晰度选择等弹窗效果,弹窗会加到 popupSuperView 上面。 
        self.playerView.popupSuperView = self.view;
        // 将 playerView 作为子 view 添加到当前 view 上。
        [self.view addSubview:self.playerView];
        // 设置 playerView 充满其父 view,即当前 view。
        [self.playerView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.edges.equalTo(self.view);
        }];
    } failure:^(NSError * _Nonnull error) {
     // 处理错误信息。在该示例中,错误信息将打印至控制台,以便调试与排查问题。
        NSLog(@"%@", error.localizedDescription);
    }];

离开直播间

在观众退出您的观看页面时,您可以通过以下示例代码,离开直播间并释放完整播放器的引用。

- (void)leaveLiveRoom {
    [[BDLLiveEngine sharedInstance] leaveLiveRoom];
    [self.playerView removeFromSuperview];
    self.playerView = nil;
}

完整示例代码

以下示例以直播间的活动 ID(activityId)为 167808997736****tokenJQ****、鉴权模式(authMode)为公开模式的竖屏直播间为例。您可以按需修改相关参数值。

说明

您可以通过调用 CreateActivityAPIV2ListActivityAPI 接口获取直播间的活动 ID,调用 GetSDKTokenAPI 接口获取公开模式(Mode=1)的授权 Token。

@interface ViewController ()
@property (nonatomic, strong) BDLPlayerView *playerView;
@end

- (void)joinLiveRoom {    
    BDLActivity *activity = [[BDLActivity alloc] init];
    activity.activityId = @(167808997736****);
    activity.token = @"JQ****";
    activity.isPortrait = YES;
    activity.authMode = BDLActivityAuthModePublic;
    
    [[BDLLiveEngine sharedInstance] joinLiveRoomWithActivity:activity
                                                     success:^{
        self.playerView =[[BDLPlayerView alloc] initWithPortrait:YES];
        self.playerView.popupSuperView = self.view;
        [self.view addSubview:self.playerView];
        [self.playerView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.edges.equalTo(self.view);
        }];
    } failure:^(NSError * _Nonnull error) {
        NSLog(@"%@", error.localizedDescription);
    }];
}

- (void)leaveLiveRoom {
    [[BDLLiveEngine sharedInstance] leaveLiveRoom];
    [self.playerView removeFromSuperview];
    self.playerView = nil;
}

独立播放器

独立播放器不包含控制界面,即播放器内无播放按钮等互动按钮。如果您具备自有的观看页面,且对播放器的控制界面有自定义需求,可选择只接入独立播放器。在接入独立播放器后,您可自行添加自定义的控制界面。
Image

进入直播间

您可以通过以下示例代码,进入直播间并创建独立播放器。

@interface ViewController () <BDLBasePlayerViewDelegate>
@property (nonatomic, strong) BDLBasePlayerView *playerView;
@end

    ...
    [[BDLLiveEngine sharedInstance] joinLiveRoomWithActivity:activity
                                                     success:^{
        // 创建独立播放器。
        self.playerView =[[BDLBasePlayerView alloc] init];
        // 设置当前 ViewController 为 playerView 的代理,用于接收和处理 playerView 的事件。
        self.playerView.delegate = self;
        // 将 playerView 作为子 view 添加到 ViewController 的 view 中。
        [self.view addSubview:self.playerView];
        // 设置 playerView 充满其父 view,即 ViewController 的 view。
        [self.playerView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.edges.equalTo(self.view);
        }];
    } failure:^(NSError * _Nonnull error) {
    // 处理错误信息。在该示例中,错误信息将打印至控制台,以便调试与排查问题。
        NSLog(@"%@", error.localizedDescription);
    }];
    ...

处理 Delegate

您可以通过处理 Delegate,在以下情况发生时,向您的 App 传入相关回调信息,用于定制控制界面。

  • 直播封面、播放内容、播放状态、视频尺寸或卡顿状态发生变化
  • 进入或退出画中画
  • 首帧加载成功

以下示例代码中,当视频卡顿状态发生变化时会打印日志信息。

// 视频开始卡顿
- (void)basePlayerViewStallStart:(BDLBasePlayerView *)basePlayerView {
    NSLog(@"%s", __func__);
}

// 视频结束卡顿
- (void)basePlayerViewStallEnd:(BDLBasePlayerView *)basePlayerView {
    NSLog(@"%s", __func__);
}

离开直播间

在观众退出您的观看页面时,您可以通过以下示例代码,离开直播间并释放独立播放器的引用。

- (void)leaveLiveRoom {
    [[BDLLiveEngine sharedInstance] leaveLiveRoom];
    [self.playerView removeFromSuperview];
    self.playerView = nil;
}

完整示例代码

以下示例以直播间的活动 ID(activityId)为 167808997736****tokenJQ****、鉴权模式(authMode)为公开模式的竖屏直播间为例。您可以按需修改相关参数值。

说明

您可以通过调用 CreateActivityAPIV2ListActivityAPI 接口获取直播间的活动 ID,调用 GetSDKTokenAPI 接口获取公开模式(Mode=1)的授权 Token。

@interface ViewController () <BDLBasePlayerViewDelegate>
@property (nonatomic, strong) BDLBasePlayerView *playerView;
@end

- (void)joinLiveRoom {    
    BDLActivity *activity = [[BDLActivity alloc] init];
    activity.activityId = @(167808997736****);
    activity.token = @"JQ****";
    activity.isPortrait = YES;
    activity.authMode = BDLActivityAuthModePublic;
    
    [[BDLLiveEngine sharedInstance] joinLiveRoomWithActivity:activity
                                                     success:^{
        self.playerView =[[BDLBasePlayerView alloc] init];
        self.playerView.delegate = self;
        [self.view addSubview:self.playerView];
        [self.playerView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.edges.equalTo(self.view);
        }];
    } failure:^(NSError * _Nonnull error) {
        NSLog(@"%@", error.localizedDescription);
    }];
}

- (void)leaveLiveRoom {
    [[BDLLiveEngine sharedInstance] leaveLiveRoom];
    [self.playerView removeFromSuperview];
    self.playerView = nil;
}

- (void)basePlayerViewStallStart:(BDLBasePlayerView *)basePlayerView {
    NSLog(@"%s", __func__);
}

- (void)basePlayerViewStallEnd:(BDLBasePlayerView *)basePlayerView {
    NSLog(@"%s", __func__);
}

浮窗播放器

浮窗播放器,即 InApp 画中画。通过 popdismiss 操作关闭直播间页面后,即可显示浮窗播放器。
接入完整直播间后,即可同时具备浮窗播放器功能。但如需先展示浮窗播放器,再展示完整直播间,例如观众先进入您的商品详情页查看商品,再点击浮窗播放器进入完整直播间,则需接入浮窗播放器。
Image

进入直播间

您可以通过以下示例代码,进入直播间并显示浮窗播放器(InApp 画中画)。

@interface ViewController ()
@property (nonatomic, strong) BDLFloatingPlayer *floatingPlayer;
@end

    ...
    [[BDLLiveEngine sharedInstance] joinLiveRoomWithActivity:activity
                                                     success:^{
       
        // 创建浮窗播放器。此处以竖屏模式初始化浮窗播放器为例。
        // 参数值仅与获取浮窗播放器加载中图片及其大小的方法有关,不影响浮窗的展示。浮窗的宽高比与视频的宽高比一致。
        self.floatingPlayer = [[BDLFloatingPlayer alloc] initWithPortrait:YES];
        // 显示浮窗播放器。此处以显示浮窗播放器右上方的关闭按钮为例。
        self.floatingPlayer.delegate = self;
        [self.floatingPlayer showWithCloseButton:YES];
    } failure:^(NSError * _Nonnull error) {
     // 处理错误信息。在该示例中,错误信息将打印至控制台,以便调试与排查问题。
        NSLog(@"%@", error.localizedDescription);
    }];

离开直播间

您可以通过以下示例代码,关闭浮窗播放器并离开直播间。

// 在点击浮窗播放器的关闭按钮时,关闭浮窗播放器并离开直播间。
- (void)floatingPlayerWillClose:(BDLFloatingPlayer *)floatingPlayer {
    [self leaveLiveRoom]
}

// 在需要关闭浮窗播放器时,关闭浮窗播放器、离开直播间并释放浮窗播放器的引用。
- (void)leaveLiveRoom {
    [[BDLLiveEngine sharedInstance] leaveLiveRoom];
    [self.floatingPlayer hide];
    self.floatingPlayer = nil;
}

自动旋转浮窗播放器方向

您可以通过以下示例代码,在横竖屏切换时,将浮窗播放器的显示方向与 App 的当前页面方向保持一致。

// 在横竖屏即将切换时,系统会调用该方法。
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
// 获取 App 的当前页面方向。        
    UIInterfaceOrientation orientation = UIInterfaceOrientationUnknown;
    if (@available(iOS 13, *)) {
        // 如果使用 self.view.window,则会在 ViewController 不可见时返回 nil,因此请使用 self.navigationController.view.window。
        orientation = self.navigationController.view.window.windowScene.interfaceOrientation;
    } else {
        orientation = UIApplication.sharedApplication.statusBarOrientation;
    }
    // 将浮窗播放器的显示方向与 App 的当前页面方向保持一致。
    [self.floatingPlayer setUIOrientation:orientation];
}

返回完整直播间后继续播放视频

为避免在观众点击浮窗播放器返回完整直播间后视频播放出现中断,您可以通过以下示例代码,确保视频内容能够继续播放。

// MARK: - BDLFloatingPlayerDelegate
// 点击浮窗播放器时触发该回调。
- (void)floatingPlayerDidSingleTap:(BDLFloatingPlayer *)floatingPlayer {
    // 隐藏浮窗播放器。
    [self.floatingPlayer hide];
    // 获取浮窗播放器中的 basePlayerView。
    BDLBasePlayerView *basePlayerView = [floatingPlayer removeBasePlayerView];
    // 创建完整直播间并传入获取的 basePlayerView。
    BDLLivePullViewController *vc = [[BDLLiveEngine sharedInstance] getLivePullViewControllerWithBasePlayerView:basePlayerView];
    vc.delegate = self;
    vc.actionProvider = self;
    self.livePullViewController = vc;
    self.floatingPlayer = nil;
    // 按需选择以 push 或 present 的方式显示完整直播间。
    [self.navigationController pushViewController:self.livePullViewController animated:YES];
}

完整示例代码

以下示例以直播间的活动 ID(activityId)为 167808997736****tokenJQ****、鉴权模式(authMode)为公开模式的竖屏直播间为例。您可以按需修改相关参数值。

说明

您可以通过调用 CreateActivityAPIV2ListActivityAPI 接口获取直播间的活动 ID,调用 GetSDKTokenAPI 接口获取公开模式(Mode=1)的授权 Token。

@interface ViewController ()
@property (nonatomic, strong) BDLFloatingPlayer *floatingPlayer;
@end


- (void)joinLiveRoom {    
    BDLActivity *activity = [[BDLActivity alloc] init];
    activity.activityId = @(167808997736****);
    activity.token = @"JQ****";
    activity.isPortrait = YES;
    activity.authMode = BDLActivityAuthModePublic;
    
    [[BDLLiveEngine sharedInstance] joinLiveRoomWithActivity:activity
                                                     success:^{
        self.floatingPlayer = [[BDLFloatingPlayer alloc] initWithPortrait:YES];
        self.floatingPlayer.delegate = self;
        [self.floatingPlayer showWithCloseButton:YES];
    } failure:^(NSError * _Nonnull error) {
        NSLog(@"%@", error.localizedDescription);
    }];
}

- (void)leaveLiveRoom {
    [[BDLLiveEngine sharedInstance] leaveLiveRoom];
    [self.playerView removeFromSuperview];
    self.playerView = nil;
}

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
    
    UIInterfaceOrientation orientation = UIInterfaceOrientationUnknown;
    if (@available(iOS 13, *)) {
        orientation = self.navigationController.view.window.windowScene.interfaceOrientation;
    } else {
        orientation = UIApplication.sharedApplication.statusBarOrientation;
    }
    [self.floatingPlayer setUIOrientation:orientation];
}

- (void)floatingPlayerDidSingleTap:(BDLFloatingPlayer *)floatingPlayer {
    [self.floatingPlayer hide];
    BDLBasePlayerView *basePlayerView = [floatingPlayer removeBasePlayerView];
    BDLLivePullViewController *vc = [[BDLLiveEngine sharedInstance] getLivePullViewControllerWithBasePlayerView:basePlayerView];
    vc.delegate = self;
    vc.actionProvider = self;
    self.livePullViewController = vc;
    self.floatingPlayer = nil;
    [self.navigationController pushViewController:self.livePullViewController animated:YES];
}