# 一、IOS接入流程

# 1.直播入口检测 (在登录后执行)

- (void)liveCheckSupport {
      NSDictionary *userDic = @{@"openid":_openId,
                                @"appid":_wxAppId,
                                @"renderer":_gpuModel};
      NSData *userData = [NSJSONSerialization dataWithJSONObject:userDic options:0 error:nil];
      NSString *userString = [[NSString alloc] initWithData:userData encoding:NSUTF8StringEncoding];

      [[WXGameLive shareInstance] checkSupport:userString testEnv:_testEnv source:(_launchFromWeChat ? 1 : 0) onSupport:^(WXCheckSupportResult result, NSString* message){
        if (result == WXLiveSupport) {
          // 显示直播入口
          // 初始化SDK
          [[WXGameLive shareInstance] initLiveWithGameName:@"游戏中文名" gameAppId:@"wx..." ilinkAppId:@"ilinkappId..." viewController: gameViewCtrl renderingApi:kRenderingAPI_xxx];
          [WXGameLive shareInstance].supportStartChannelLive = YES;
          if (_launchFromWeChat) {
            // 如果是从微信拉起开播的场景,此时需要拉起挂件,挂件会自动进入开播倒计时
            [self launchLiveWidget];
            _launchFromWeChat = false;
          }
        } else {
            NSLog(@"CheckSupport result: %ld  message: %@", result, message);
        }
        _checkSupported = true;
      }];
}

# 2.拉起直播挂件(包含初始化,直播事件注册)

-(void) launchLiveWidget {
  // 注册直播事件回调
  [WXGameLive shareInstance].liveEventDelegate = self; // 所在Class实现WXLiveEventDelegate
  // 加载直播挂件
  [[WXGameLive shareInstance] loadLiveWebViewWithUserId:_userId];
}

// WXLiveEventDelegate回调接口实现
#pragma mark WXLiveEventDelegate
- (void)onRequireAuthorize:(int)taskid {
  //需要保存下taskId,授权同意后作为第一个参数传入authorizeFinish接口
  _authTaskId = taskid;
  // 调用MSDK的ChannelPermissionAuth接口实现跳转微信完成视频号授权
  MSDKLogin::ChannelPermissionAuth(MSDKChannel.WeChat, "snsapi_channels_livestream","","")
}

- (void)onStartChannelLive:(nonnull NSString *)liveJsonInfo {
  // 使用MSDK完成跳转微信操作
  MSDKFriendReqInfo reqInfo = new MSDKFriendReqInfo();
  reqInfo.type = kMSDKFriendReqTypeWXChannelStartLive;
  reqInfo.extraJson = liveJsonInfo;
  MSDKFriend::SendMessage(reqInfo,MSDKChannel.WeChat);
}

- (void)onOpenUrl:(nonnull NSString *)url screenType:(int)screenType isFullScreen:(bool)isFullScreen isBrowser:(bool)isBrowser {
  // 使用MSDKWebView 打开挂件内链接
  MSDKWebView::OpenUrl(url, screenType, isFullScreen, true, "", isBrowser);
}

- (void)onStartLive:(BOOL)isAudioPermissionGranted {
  // 开始直播回调,需要这里执行启动音频采集相关逻辑,比如启动gvoice的pcm回调
  if (isAudioPermissionGranted) {
  // 已获得麦克风权限,设置GVoice的PCM回调逻辑
   mVoiceEngine.invoke(4, 1, 0, null);     // 启用OnRecordingData回调,务必在同意麦克风权限后调用
   mVoiceEngine.SetMode(Mode.RealTime);
   mVoiceEngine.EnableMultiRoom(true);
  // 加入直播专用的语音房间,mLiveRoomName命名可以是前缀+时戳,确保每个房间名都是唯一的
   mVoiceEngine.JoinTeamRoom(mLiveRoomName, 5000);
  } else {
  // 如果没有设置innerAudioPermissionAuth=true, 此时需要申请麦克风权限,等用户同意麦克风权限后再调用mVoiceEngine.invoke(4, 1, 0, null)
  // 如果已经设置了EnableInnerAudioPermissionAuth(true),说明用于拒绝了麦克风权限,需要提示用户无法采集主播语音
  }
}

- (void)onStopLive {
  // 结束直播回调,需要这里执行停止音频采集相关逻辑,比如停止gvoice的pcm回调
  if (mAudioPermissionGranted)
  {
    mVoiceEngine.invoke(4, 0, 0, null);  // 禁用OnRecordingData回调
    mVoiceEngine.EnableRoomMicrophone(mLiveRoomName, false);
    mVoiceEngine.QuitRoom(mLiveRoomName, 5000);
  }
}

- (void)onWebViewLoaded {
  // 挂件加载完成回调
} 

// 挂件关闭回调
-(void) onWebViewClosed {
// 挂件关闭回调
}

// 其他扩展事件回调
-(void) onToastWithMessage:(NSString*)message {
// SDK内部提示回调,游戏侧可选择弹提示框
}
/**
 其他扩展事件回调
 @param params  传递给游戏的json字串
 */
-(void) onExtraEvent:(NSString*)params {
// 其他扩展事件回调
}

# 3.游戏生命周期埋点

- (void)applicationDidEnterBackground:(UIApplication*)application
  {
    ...
    // 游戏进入后台
    [[WXGameLive shareInstance]  appDidEnterBackground];
  }

- (void)applicationWillEnterForeground:(UIApplication*)application
  {
    ...
    // 游戏切回前台
    [[WXGameLive shareInstance]  appWillEnterForeground];
  }

- (void)applicationWillTerminate:(UIApplication*)application
  {
    ...
    // 游戏被杀进程退出
    [[WXGameLive shareInstance] uninitLive];
  }

# 4.微信拉起游戏开播流程

  1. 监听游戏被第三方应用拉起时,传递过来的参数,确认是被微信视频号拉起时,调用onMessageFromWeChat接口将相关参数传给直播SDK。
  2. 判断游戏是否已经登录
    a.如果已经登录,则判断当前挂件是否已经存在,如果不存在则拉起挂件,如果已经存在,则挂件会自动进入开播倒计时。
    b.如果游戏未登录,等待用户登录后,执行游戏内开播的流程。与游戏内开播的区别在于,不需要校验CheckSupport 的result回包,直接执行开播的流程。具体流程见流程图。

以MSDK为例,示例如下:

// 在MSDK的登录监听中增加如下逻辑
// 登录回调,包括 login、bind、autologin、switchuser 等
void OnLoginRetNotify(const MSDKLoginRet &loginRet) {
  if (loginRet.methodNameID == kMethodNameAutoLogin || loginRet.methodNameID == kMethodNameLogin) {
    // 如果是微信登录的话,记录下openid和accesstoken
    _openId = loginRet.channelInfo['openid'];
    _accessToken = loginRet.channelInfo['access_token'];
    // 登录成功后调用 CheckSupport 接口
    liveCheckSupport();        
  }
};

// 登出回调、应用唤醒回调
void OnBaseRetNotify(const MSDKBaseRet &baseRet) {
  if (baseRet.methodNameID == kMethodNameChannelPermissionAuth) {
    // 执行onRequireAuthorize回调之后的拿到视频号授权的票据
    // 提取baseRet.extraJson参数中“tdiAuthBuffer”字段
    // 再将该字段进行一次Base64的解码后,传入authorizeFinish接口,完成视频号的“一键登录”
    // 伪代码如下:
    string tdiAuthString = baseRet.extraJson['tdiAuthBuffer'];
    NSData* tdiAuthBuffer = Base64.decode(tdiAuthString);
    [[WXGameLive shareInstance] authorizeFinish:_authTaskId errcode:baseRet.retCode tdiAuthBuffer:tdiAuthBuffer];
  } else if (baseRet.methodNameID == kMethodNameWakeUp) {
    // 游戏被微信等第三方app拉起
    // 提取baseRet.extraJson参数中“params”字段
    // 解析params字段,提取其中的“openId”,“messageExt”字段,伪代码如下:
    dict params = baseRet.extraJson['params'];
    _openId = params['openId'];
    _messageFromWx = params['messageExt'];
    // 校验是否是被视频号拉起
    if (_messageFromWx.contains("WeChatLive_ShiPinHao")) {
      _launchFromWeChat = true;
      // 将微信的参数设置给SDK
      [[WXGameLive shareInstance] onMessageFromWeChat: _messageFromWx];			
      if ( _isLogined) {
        // 游戏已经登录, 调用CheckSupport
        liveCheckSupport();
      } else {
        // 等待用户执行游戏登录 
      }
    }
  }
};

# 二、一键开播完整流程图

flow_chart