iOS 直播观看 SDK 开发指南

发布于 2021-02-21 21:55:09 字数 38825 浏览 1320 评论 0

1.概述

1.1 阅读对象

本文档为技术文档,需要阅读者:

  • 具备基本的iOS开发能力
  • 准备接入CC视频的直播SDK相关功能
  • 对CC云直播产品使用方法有基础的了解,使用帮助地址

1.2 功能特性

功能描述
直播视频观看直播视频
文档展示能够观看当前直播文档,文档添加水印
线路更换观看卡顿请换个线路
清晰度支持直播多清晰度切换播放
答题卡支持实时检测课堂学生的掌握程度
问答能够发送问题和接受回答信息
简介支持对直播间的信息展示
问卷支持对观看直播的人进行信息采集
广播支持发送全体消息
连麦支持与直播人员进行音视频沟通
签到支持签到功能
抽奖支持抽奖功能
随堂测支持随堂测互动
修改昵称支持自定义昵称
聊天互动支持与房间内的其他人聊天互动和一对一私聊
跑马灯支持直播防录屏功能

2.开发准备

2.1 开发环境

  • Xcode : Xcode 开发IDE
  • Version 10.0 及以上

2.2 SDK配置

2.2.1 CocoaPods集成

已安装CocoaPods

如果是有连麦的SDK:
pod 'CCLivePlaySDK', '~> 3.8.0'
如果是无连麦的SDK:
pod 'CCLivePlaySDK', :podspec => 'https://raw.githubusercontent.com/CCVideo/Live_iOS_Play_SDK/3.8.0/CCLivePlaySDK.podspec'

注:3.8.0为版本号,修改为自己想要的版本号即可

未安装CocoaPods

  1. 安装CocoaPods打开终端:>_ 1、查看当前Ruby版本
    ruby -v
    

    2、升级Ruby环境,首先需要安装rvm(第一步要下载一些东西等两分钟左右)

    curl -L get.rvm.io | bash -s stable 
    source ~/.bashrc
    source ~/.bash_profile
    

    3、查看rvm版本

    rvm -v 
    
    显示如下(或者是其他版本)
    rvm 1.29.3 (latest) by Michal Papis, Piotr Kuczynski, Wayne E. Seguin [https://rvm.io]
    

    4、列出ruby可安装的版本信息

    rvm list known
    
    显示如下
    # MRI Rubies
    [ruby-]1.8.6[-p420]
    [ruby-]1.8.7[-head] # security released on head
    [ruby-]1.9.1[-p431]
    [ruby-]1.9.2[-p330]
    [ruby-]1.9.3[-p551]
    [ruby-]2.0.0[-p648]
    [ruby-]2.1[.10]
    [ruby-]2.2[.10]
    [ruby-]2.3[.7]
    [ruby-]2.4[.4]
    [ruby-]2.5[.1]  // 重点在这里 重点在这里 重点在这里
    [ruby-]2.6[.0-preview2]   // 测试版
    ruby-head
    .....
    

    5、安装一个ruby版本

    rvm install 2.5.1
    // 注意:安装过程中需要两次按下 Enter 键, 第二次按下后需要输入电脑访问密码(不可见,只管输入就行);
    // 如果你电脑没有安装Xcode和Command Line Tools for Xcode以及Homebrew 会自动下载安装,建议提前安装这三者.
    
    
    这里很多小伙伴会遇到错误,大部分是因为没有安装Homebrew造成,所以所以所以要提前安装比较好
    /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    

    6、设置为默认版本

    rvm use 2.5.1 --default
    

    7、更换源

    sudo gem update --system
    
    gem sources --remove https://rubygems.org/
    
    gem sources --add https://gems.ruby-china.com/
    

    8、为了验证你的Ruby镜像是并且仅是ruby-china,执行以下命令查看

    gem sources -l
    
    
    如果是以下结果说明正确,如果有其他的请自行百度解决
    *** CURRENT SOURCES ***
    
    https://gems.ruby-china.com/
    

    9、这时候才正式开始安装CocoaPods

    sudo gem install -n /usr/local/bin cocoapods
    

    10、如果安装了多个Xcode使用下面的命令选择(一般需要选择最近的Xcode版本)

    sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer
    

    11、安装本地库

    pod setup
    

    12、执行以上命令后

    Setting up CocoaPods master repo
      $ /usr/bin/git clone https://github.com/CocoaPods/Specs.git master --progress
      Cloning into 'master'...
      remote: Counting objects: 1879515, done.        
      remote: Compressing objects: 100% (321/321), done.        
      Receiving objects:  21% (404525/1879515), 73.70 MiB | 22.00 KiB/
      然后就是漫长的等待,当然,网络好的情况下会更快
    
  2. 在Podfile文件中添加
    如果是有连麦的SDK:
    pod 'CCLivePlaySDK', '~> 3.8.0'
    如果是无连麦的SDK:
    pod 'CCLivePlaySDK', '~> 3.8.0', :podspec => 'https://raw.githubusercontent.com/CCVideo/Live_iOS_Play_SDK/master/CCLivePlaySDK.podspec'
    
  3. 在终端中执行
    pod install
    

ps:目前CocoaPods集成仅支持3.8.0及以后的版本,旧版本暂不支持CocoaPods集成

2.2.2 手动集成

1.将SDK文件夹内的所有文件拖到项目中

 command + b 编译,如果报错" file '...xxx/IJKMediaFramework.framework/IJKMediaFramework' for architecture arm64 "
 解决方案:
 Targets ->  Build Settings -> 搜索 "Enable Bitcode" 设置为 "NO"

2.command + r 运行

如果报错" dyld: Library not loaded: @rpath/XXX.framework "
解决方案:
Targets -> Build Phases  ->
点击左上角 "+" 按钮 ->
选择 "New Copy Files Phase" ->
点击新添加的 Copy Files 前面的下拉箭头 ->
Destination 选择 "Frameworks" ->
点击当前目录下的 "+" 将SDK包含的.framework 包添加即可

2.3 日志存储

在AppDelegate.m文件导入头文件

#import "CCSDK/SaveLogUtil.h"

在启动方法中添加日志存储

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
/**
 *  @brief  是否存储日志
 */
    [[SaveLogUtil sharedInstance]isNeedToSaveLog:YES];
    return YES;
}

2.4 错误码

服务错误类型

 ERROR_SERVICE_TYPE 
 
 ERROR_ROOM_STATE = 1001 		直播间状态不可用,可能没有开始推流
 ERROR_USELESS_INFO = 1002		没有获取到有用的视频信息
 ERROR_PASSWORD = 1003			密码错误

系统错误类型

 ERROR_SYSTEM_TYPE 
 
 ERROR_RETURNDATA = 1004		返回内容格式错误
 ERROR_PARAMETER = 1005			直播间信息填写错误
 ERROR_NETWORK = 1006			网络异常
 ERROR_LOGINDATA = 1007			登录
 ERROR_PLAYERURL = 1008			视频播放地址
 ERROR_QUESTIONLIST = 1009		问卷列表
 ERROR_STATISTICAL = 1010		问卷统计
 ERROR_DOCLIST = 1011			文档列表
 ERROR_HISTORY = 1012			历史信息
 PRACTICE_LIST = 1013			随堂测试
 PRACTICECOMMIT = 1014			提交随堂测试
 PRACTICESTATIS = 1015			获取随堂测统计
 PRACTICERANK = 1016			获取随堂测排名
 ERROR_SOCKET = 1017			socket加载失败
 ERROR_PUNCH = 1018				获取打卡信息失败
 ERROR_PUNCHCOMMIT = 1019		获取打卡提交结果失败
 ERROR_DRMURL = 1020			获取加密地址失败

3.快速集成

3.1 配置参数

3.1.1 调用方法

/**
 *	@brief	登录房间
 *	@param 	parameter   配置参数信息
 *  必填参数 userId; //用户ID
 *  必填参数 roomId; //房间ID 
 *  必填参数 viewerName; //用户名
 *  必填参数 token; //房间密码
 *  (已弃用!) security //是否使用https
 * (选填参数) viewercustomua; //用户自定义参数,需和后台协商,没有定制传@""
 */
- (id)initLoginWithParameter:(PlayParameter *)parameter;
/**
 *	@brief	进入房间,并请求画图聊天数据并播放视频(可以不登陆,直接从此接口进入直播间)
 *	@param 	parameter   配置参数信息
 *  必填参数 userId; //用户ID
 *  必填参数 roomId; //房间ID 
 *  必填参数 viewerName; //用户名称
 *  必填参数 token; //房间密码 
 *  必填参数 docParent; //文档父类窗口
 *  必填参数 docFrame; //文档区域
 *  必填参数 playerParent; //视频父类窗口
 *  必填参数 playerFrame; //视频区域
 *  必填参数 scalingMode; //屏幕适配方式
 *  (已弃用!) security //是否使用https
 *  必填参数 defaultColor; //ppt默认底色,不写默认为白色
 *  必填参数 PPTScalingMode; //PPT适配方式  PPT适配模式分为四种,1.一种是全部填充屏幕,可拉伸变形,2.第二种是等比缩放,横向或竖向贴住边缘,另一方向可以留黑边,3.第三种是等比缩放,横向或竖向贴住边缘,另一方向出边界,裁剪PPT,不可以留黑边,4.根据直播间文档显示模式的返回值进行设置(推荐)(The New Method)
 *  必填参数 pauseInBackGround; //后台是否继续播放,注意:如果开启后台播放需要打开 xcode->Capabilities->Background Modes->on->Audio,AirPlay,and Picture in Picture
 * (选填参数)viewercustomua; //用户自定义参数,需和后台协商,没有定制传@""
 */
- (id)initWithParameter:(PlayParameter *)parameter;

代理方法

/**
 *    @brief    登录成功
 */
- (void)loginSucceedPlay;
/**
 *    @brief    登录失败
 */
-(void)loginFailed:(NSError *)error reason:(NSString *)reason;

/**
 *    @brief    请求成功
 */
-(void)requestSucceed;
/**
 *    @brief    登录请求失败
 */
-(void)requestFailed:(NSError *)error reason:(NSString *)reason;

3.1.2 集成

导入头文件

#import "CCSDK/RequestData.h"//SDK

声明变量

@property (nonatomic,strong)RequestData              * requestData;//sdk

配置参数:PlayParameter的属性如下

/**
 *  @brief 用户ID
 */
@property(nonatomic, copy)NSString                      *userId;//用户ID
/**
 *  @brief 房间ID
 */
@property(nonatomic, copy)NSString                      *roomId;//房间ID
/**
 *  @brief 用户名称
 */
@property(nonatomic, copy)NSString                      *viewerName;//用户名称
/**
 *  @brief 房间密码
 */
@property(nonatomic, copy)NSString                      *token;//房间密码
/**
 *  @brief 用户自定义参数,需和后台协商,没有定制传@""
 */
@property(nonatomic, copy)NSString                      *viewerCustomua;//用户自定义参数,需和后台协商,没有定制传@""
/**
 * json格式字符串,可选,自定义用户信息,该信息会记录在用户访问记录中,用于统计分析使用(长度不能超过1000个字符,若直播间启用接口验证则该参数无效)如果不需要的话就不要传值
 * 格式如下:
 * viewercustominfo: '{"exportInfos": [ {"key": "城市", "value": "北京"}, {"key": "姓名", "value": "哈哈"}]}'
 */
@property(nonatomic, copy)NSString                      *viewercustominfo;
/**
 *  @brief 文档父类窗口
 */
@property(nonatomic,strong)UIView                       *docParent;//文档父类窗口
/**
 *  @brief 文档区域
 */
@property(nonatomic,assign)CGRect                       docFrame;//文档区域
/**
 *  @brief 视频父类窗口
 */
@property(nonatomic,strong)UIView                       *playerParent;//视频父类窗口
/**
 *  @brief 视频区域
 */
@property(nonatomic,assign)CGRect                       playerFrame;//视频区域
/**
 *  @brief
 * 0:IJKMPMovieScalingModeNone
 * 1:IJKMPMovieScalingModeAspectFit
 * 2:IJKMPMovieScalingModeAspectFill
 * 3:IJKMPMovieScalingModeFill
 */
@property(assign, nonatomic)NSInteger                   scalingMode;//屏幕适配方式,含义见上面
/**
 *  @brief ppt默认底色,不写默认为白色
 */
@property(nonatomic,strong)UIColor                      *defaultColor;//ppt默认底色,不写默认为白色
/**
 *  @brief /后台是否继续播放,注意:如果开启后台播放需要打开 xcode->Capabilities->Background Modes->on->Audio,AirPlay,and Picture in Picture
 */
@property(nonatomic,assign)BOOL                         pauseInBackGround;//后台是否继续播放,注意:如果开启后台播放需要打开 xcode->Capabilities->Background Modes->on->Audio,AirPlay,and Picture in Picture
/**
 *  @brief PPT适配模式分为四种,
 * 1.一种是全部填充屏幕,可拉伸变形,
 * 2.第二种是等比缩放,横向或竖向贴住边缘,另一方向可以留黑边,
 * 3.第三种是等比缩放,横向或竖向贴住边缘,另一方向出边界,裁剪PPT,不可以留黑边
 * 4.根据直播间文档显示模式的返回值进行设置(推荐) 
 */
@property(assign, nonatomic)NSInteger                   PPTScalingMode;//PPT适配方式,含义见上面
/**
 *  @brief PPT是否允许滚动 
 */
@property(nonatomic, assign)BOOL                        pptInteractionEnabled;
/**
 *  @brief 设置当前的文档模式,
 * 1.切换至跟随模式(默认值)值为0,
 * 2.切换至自由模式;值为1,
 */
@property(assign, nonatomic)NSInteger                   DocModeType;//设置当前的文档模式
/**
 *  @brief 聊天分组id
 *         使用聊天分组功能时传入,不使用可以不传
 */
@property(copy, nonatomic)NSString                      *groupid;

开始配置

 第一步:实例化参数类
 PlayParameter *parameter = [[PlayParameter alloc] init];
 //配置PlayParameter里面的属性,如userId,roomId等!
 第二步实例化RequestData类
 _requestData = [[RequestData alloc] initWithParameter:parameter];
 第三步添加代理
 _requestData.delegate = self;

添加代理

@interface 您的控制器 ()<RequestDataDelegate>

实现代理

/**
 *    @brief    请求成功
 */
-(void)requestSucceed {

}
/**
 *    @brief    登录请求失败
 */
-(void)requestFailed:(NSError *)error reason:(NSString *)reason {

}

至此您的项目已经可以运行了,并且已经集成好了视频和文档基本功能;如果不需要文档功能则不配置文档相关属性即可

3.2 观看直播

3.2.1 代理方法(可选)

/**
 *	@brief  主讲开始推流
 */
- (void)onLiveStatusChangeStart;

/**
 *	@brief  停止直播,endNormal表示是否异常停止推流,这个参数对观看端影响不大
 */
- (void)onLiveStatusChangeEnd:(BOOL)endNormal;

/**
 *	@brief  收到踢出消息,停止推流并退出播放(被主播踢出)(change)
 *    		 dictionary[@"kick_out_type"] 踢出类型
 *    		 dictionary[@"viewerid"] 用户ID
 *		 	 kick_out_type: 踢出类型
 *			 				   10 在允许重复登录前提下,后进入者会登录会踢出先前登录者
 *			 					20 讲师、助教、主持人通过页面踢出按钮踢出用户
  *	
 */
- (void)onKickOut:(NSDictionary *)dictionary;

/**
 *	@brief  收到播放直播状态 0直播 1未直播
 */
- (void)getPlayStatue:(NSInteger)status;

/**
 *    @brief     直播间被禁
 */
- (void)theRoomWasBanned;

/**
 *    @brief     直播间解禁
 */
- (void)theRoomWasCleared;

/**
 *    @brief     客户端关闭摄像头
 数据源类型    数据源值    数据源类型描述       数据源类型描述值
 source_type    0     source_type_desc    数据源类型:默认值,
 source_type    10    source_type_desc    数据源类型:摄像头打开
 source_type    11    source_type_desc    数据源类型:摄像头关闭
 source_type    20    source_type_desc    数据源类型:图片
 source_type    30    source_type_desc    数据源类型:插播视频
 source_type    40    source_type_desc    数据源类型:区域捕获
 source_type    50    source_type_desc    数据源类型:桌面共享
 source_type    60    source_type_desc    数据源类型:自定义场景
 
 ps:
 source_type 参数 0 值 应用场景:
 1. 文档模式下 0 默认值
 2. 非文档模式下 0 无意义
 3. 低版本客户端 0 无意义
 source_type 参数 60 值 应用场景:
 当以上场景无法满足要求时,主播可自定义场景,用户不需要关心自定义场景细节内容
 */
- (void)receivedSwitchSource:(NSDictionary *)dic;

/**
 *  @brief  视频或者文档大窗
 *  isMain 1为视频为主,0为文档为主"
 */
- (void)onSwitchVideoDoc:(BOOL)isMain;
/**
 *  @brief  加载视频失败
 */
- (void)play_loadVideoFail;
/**
 *    @brief    视频状态
 *    rseult    playing/paused/loading/buffing
 */
-(void)videoStateChangeWithString:(NSString *) result;

3.2.2 主动方法(可选)

/**
 *	@brief  改变播放器frame
 */
- (void)changePlayerFrame:(CGRect) playerFrame;

/**
 *    @brief  改变播放器父窗口
 */
- (void)changePlayerParent:(UIView *) playerParent;

/**
 *	@brief  播放器暂停
 */
- (void)pausePlayer;

/**
 *	@brief  播放器播放
 */
- (void)startPlayer;

/**
 *	@brief  播放器关闭并移除
 */
- (void)shutdownPlayer;

/**
 *	@brief  播放器停止
 */
- (void)stopPlayer;

/**
 *  @brief 重新加载视频,参数force表示是否强制重新加载视频,
 * 一般重新加载视频的时间间隔应该超过3秒,如果强制重新加载视频,时间间隔可以在3S之内
 */
-(void)reloadVideo:(BOOL)force;

/**
 *	@brief  播放器是否播放
 */
- (BOOL)isPlaying;

/**
 *	@brief  设置后台是否可播放
 */
- (void)setpauseInBackGround:(BOOL)pauseInBackGround;
/**
 *	@brief	销毁文档和视频,清除视频和文档的时候需要调用,退出播放页面的时候也需要调用
 */
- (void)requestCancel;
/**
 *  @brief  获取直播开始时间和直播时长
 *  liveDuration 直播持续时间,单位(s),直播未开始返回-1"
 *  liveStartTime 新增开始直播时间(格式:yyyy-MM-dd HH:mm:ss),如果直播未开始,则返回空字符串
 */
- (void)startTimeAndDurationLiveBroadcast:(NSDictionary *)dataDic;
/**
 获取已播放时长,调用后会响应onLivePlayedTime方法,调用间隔三秒
 */
- (void)getLivePlayedTime;
/**
 *    @brief    回调已播放时长, 如果未开始,则time为-1
 *              触发此方法需要调用getLivePlayedTime
*/
- (void)onLivePlayedTime:(NSDictionary *)dic;

3.3 文档功能

3.3.1 代理方法(可选)

/**
 *	@brief  获取文档内白板或者文档本身的宽高,来进行屏幕适配用的
 */
- (void)getDocAspectRatioOfWidth:(CGFloat)width height:(CGFloat)height;

/**
 *  @brief  获取ppt当前页数和总页数(The new method)
 *
 *  回调当前翻页的页数信息
 *  白板docTotalPage一直为0, pageNum从1开始
 *  其他文档docTotalPage为正常页数,pageNum从0开始
 *  @param dictionary 翻页信息
 *  dictionary :{docId 文档ID
 *               docName 文档名
 *               docTotalPage 文档总页数
 *               pageNum 文档页码}
 */
- (void)onPageChange:(NSDictionary *) dictionary;

/**
 *    @brief     双击ppt
 */
- (void)doubleCllickPPTView;

/**
 *    @brief     获取所有文档列表
  *       @param  listDic   [{ 	docId     //文档ID
    			docName             		//文档名称
    			docTotalPage        		//文档总页数
    			iconSrc             			//图标地址
    			pages      [{   pageIndex   //当前页位置
                   			 src         	//当前页地址
                   			 title       //当前页标题 }]}]
 */
- (void)receivedDocsList:(NSDictionary *)listDic;

/**
 *  @brief  视频或者文档大窗
 *  isMain 1为视频为主,0为文档为主"
 */
- (void)onSwitchVideoDoc:(BOOL)isMain;
/**
 *    @brief    文档加载状态
 *    index
 *      0 文档组件初始化完成
 *      1 动画文档加载完成
 *      2 非动画文档加载完成
 *      3文档组件加载失败
 *      4文档图片加载失败
 *      5文档动画加载失败
 *      6画板加载失败
 */
- (void)docLoadCompleteWithIndex:(NSInteger)index;

3.3.2 主动方法(可选)

/**
 *	@brief  获取文档区域内白板或者文档本身的宽高比,返回值即为宽高比,做屏幕适配用
 */
- (CGFloat)getDocAspectRatio;

/**
 *	@brief  改变文档区域大小,主要用在文档生成后改变文档窗口的frame
 */
- (void)changeDocFrame:(CGRect) docFrame;

/**
 *    @brief  改变文档父窗口
 */
- (void)changeDocParent:(UIView *) docParent;

/**
 *    @brief     切换当前的文档模式
 *    1.切换至跟随模式(默认值)值为0,
 *    2.切换至自由模式;值为1,
 */
- (void)changeDocMode:(NSInteger)mode;

/**
 *    @brief     查找并获取当前文档的信息
 *    @param     docId  文档的docId
 *    @param     pageIndex  跳转的页数
 */
- (void)changePageToNumWithDocId:(NSString *)docId pageIndex:(NSInteger)pageIndex;
/**
重新加载文档
*/
- (void)docReload;
/**
 改变文档背景颜色

 @param hexColor 字符串,传颜色的HEXColor 如:#000000
 */
- (void)changeDocWebColor:(NSString *)hexColor;
/**
 * 获取ppt列表(只能在登陆成功后调用)
 */
- (void)getDocsList;

3.4 房间信息

代理方法(可选)

/**
 *	@brief  获取房间信息,主要是要获取直播间模版来类型,根据直播间模版类型来确定界面布局
 *	房间简介:dic[@"desc"];
 *	房间名称:dic[@"name"];
 *	房间模版类型:[dic[@"templateType"] integerValue];
 *	模版类型为1: 聊天互动: 无 直播文档: 无 直播问答: 无
 *	模版类型为2: 聊天互动: 有 直播文档: 无 直播问答: 有
 *	模版类型为3: 聊天互动: 有 直播文档: 无 直播问答: 无
 *	模版类型为4: 聊天互动: 有 直播文档: 有 直播问答: 无
 *	模版类型为5: 聊天互动: 有 直播文档: 有 直播问答: 有
 *	模版类型为6: 聊天互动: 无 直播文档: 无 直播问答: 有
 */
-(void)roomInfo:(NSDictionary *)dic;

/**
 *    @brief    服务器端给自己设置的信息 
 *    viewerId 服务器端给自己设置的UserId
 *    groupId 分组id
 *    name 用户名
 */
-(void)setMyViewerInfo:(NSDictionary *) infoDic;
/**
 *    @brief    房间设置信息
 *    dic{
      "allow_chat" = true;//是否允许聊天
      "allow_question" = true;//是否允许问答
      "room_base_user_count" = 0;//房间基础在线人数
      "source_type" = 0;//对应receivedSwitchSource方法的source_type
}
 *ps:当房间类型没有聊天或者问答时,对应的字段默认为true
*/
-(void)roomSettingInfo:(NSDictionary *)dic;
/**
 *	@brief	服务器端给自己设置的UserId
 */
-(void)setMyViewerId:(NSString *)viewerId;

##3.5 聊天功能

代理方法(可选)

/**
 *    @brief  历史聊天数据
 *    @param  chatLogArr [{ chatId         //聊天ID
                           content         //聊天内容
                           groupId         //聊天组ID
                           time            //时间
                           userAvatar      //用户头像
                           userId          //用户ID
                           userName        //用户名称
                           userRole        //用户角色}]
 */
- (void)onChatLog:(NSArray *)chatLogArr;
/*
 *  @brief  收到公聊消息
   @param  message {   groupId         //聊天组ID
                       msg             //消息内容
                       time            //发布时间
                       useravatar      //用户头像
                       userid          //用户ID
                       username        //用户名称
                       userrole        //用户角色}
 */
- (void)onPublicChatMessage:(NSDictionary *)message;
/**
 *    @brief    收到私聊信息
 *    @param    dic {fromuserid         //发送者用户ID
 *                   fromusername       //发送者用户名
 *                   fromuserrole       //发送者角色
 *                   msg                //消息内容
 *                   time               //发送时间
 *                   touserid           //接受者用户ID
 *                   tousername         //接受者用户名}    
 */
- (void)OnPrivateChat:(NSDictionary *)dic;
/*
 *  @brief  收到自己的禁言消息,如果你被禁言了,你发出的消息只有你自己能看到,其他人看不到
   @param  message {   groupId         //聊天组ID
                       msg             //消息内容
                       time            //发布时间
                       useravatar      //用户头像
                       userid          //用户ID
                       username        //用户名称
                       userrole        //用户角色}
 */
- (void)onSilenceUserChatMessage:(NSDictionary *)message;
/**
 *	@brief	当主讲全体禁言时,你再发消息,会出发此代理方法,information是禁言提示信息
 */
- (void)information:(NSString *)information;
/**
 *  @brief  自定义消息
 */
- (void)customMessage:(NSString *)message;
/**
 *    @brief    收到聊天禁言并删除聊天记录
 *    viewerId  禁言用户id,是自己的话别删除聊天历史,其他人需要删除该用户的聊天
 */
-(void)onBanDeleteChat:(NSDictionary *) viewerDic;
/**
 *    @brief    收到聊天禁言 
 *    mode 禁言类型 1:个人禁言  2:全员禁言
 */
-(void)onBanChat:(NSDictionary *) modeDic;
/**
 *    @brief    收到解除禁言事件 
 *    mode 禁言类型 1:个人禁言  2:全员禁言
 */
-(void)onUnBanChat:(NSDictionary *) modeDic;
/**
 *    @brief    聊天管理 
 *    status    聊天消息的状态 0 显示 1 不显示
 *    chatIds   聊天消息的id列列表
 */
-(void)chatLogManage:(NSDictionary *) manageDic;

主动方法(可选)

/**
 *	@brief	发送公聊信息
 *	@param 	message  发送的消息内容
 */
- (void)chatMessage:(NSString *)message;
/**
 *	@brief  发送私聊信息
 */
- (void)privateChatWithTouserid:(NSString *)touserid msg:(NSString *)msg;
/**
 *    @brief    发送公聊信息
 *    @param     message  发送的消息内容
 *               completion 发送回调 成功或者失败
 */
- (void)sendChatMessage:(NSString *)message completion:(void (^)(BOOL success))completion;

3.6 问答功能

代理方法(可选)

/**
 *    @brief  收到提问,用户观看时和主讲的互动问答信息
 *    @param  questionDic { groupId         //分组ID
                            content         //问答内容
                            userName        //问答用户名
                            userId          //问答用户ID
                            time            //问答时间
                            id              //问答主键ID
                            useravatar      //用户化身 }
 */
- (void)onQuestionDic:(NSDictionary *)questionDic;
/**
 *    @brief  收到回答
 *    @param  answerDic {content            //回复内容
                         userName           //用户名
                         questionUserId     //问题用户ID
                         time               //回复时间
                         questionId         //问题ID
                         isPrivate          //1 私聊回复 0 公聊回复 }
 */
- (void)onAnswerDic:(NSDictionary *)answerDic;
/**
 *    @brief  收到历史提问&回答
 *    @param  questionArr [{content             //问答内容
                            encryptId           //加密ID
                            groupId             //分组ID
                            isPublish           //1 发布的问答 0 未发布的问答
                            questionUserId      //问答用户ID
                            questionUserName    //问答用户名
                            time                //问答时间
                            triggerTime         //问答具体时间}]
 *    @param  answerArr  [{answerUserId         //回复用户ID
                           answerUserName       //回复名
                           answerUserRole       //回复角色(主讲、助教)
                           content              //回复内容
                           encryptId            //加密ID
                           groupId              //分组ID
                           isPrivate            //1 私聊回复 0 公共回复
                           time = 135;          //回复时间
                           triggerTime          //回复具体时间}]
 */
- (void)onQuestionArr:(NSArray *)questionArr onAnswerArr:(NSArray *)answerArr;
/**
 *  @brief  发布问题的ID
 */
- (void)publish_question:(NSString *)publishId;

主动方法(可选)

/**
 *	@brief	提问
 *	@param 	message 提问内容
 */
- (void)question:(NSString *)message;

3.7 连麦功能

代理方法(可选)

/**
 *  @brief 本房间为允许连麦的房间,会回调此方法,在此方法中主要设置UI的逻辑,
 *  在断开推流,登录进入直播间和改变房间是否允许连麦状态的时候,都会回调此方法
 */
- (void)allowSpeakInteraction:(BOOL)isAllow;
/**
 *  @brief WebRTC连接成功,在此代理方法中主要做一些界面的更改
 */
- (void)connectWebRTCSuccess;
/**
 *  @brief 当前是否可以连麦
 */
- (void)whetherOrNotConnectWebRTCNow:(BOOL)connect;
/**
 *  @brief 主播端接受连麦请求,在此代理方法中,要调用DequestData对象的
 *  - (void)saveUserInfo:(NSDictionary *)dict remoteView:(UIView *)remoteView;方法
 *  把收到的字典参数和远程连麦页面的view传进来,这个view需要自己设置并发给SDK,SDK将要在这个view上进行渲染
 *
 *  @param dict {type               //audio 音频  audiovideo 音视频
 *               videosize          //视频尺寸
 *               viewerId           //申请连麦ID
 *               viewerName         //申请连麦名}
 */
- (void)acceptSpeak:(NSDictionary *)dict;
/**
 *  @brief 主播端发送断开连麦的消息,收到此消息后做断开连麦操作
 */
-(void)speak_disconnect:(BOOL)isAllow;

主动方法(可选)


/**
 *  @brief 设置远程连麦窗口的大小,连麦成功后调用才生效,连麦不成功调用不生效
 */
-(void)setRemoteVideoFrameA:(CGRect)remoteVideoFrame;
/**
 *  @brief 设置本地预览窗口的大小,连麦成功后调用才生效,连麦不成功调用不生效
 */
-(void)setLocalVideoFrameA:(CGRect)localVideoFrame;
/**
 *  @brief 当观看端主动申请连麦时,需要调用这个接口,并把本地连麦预览窗口传给SDK,SDK会在这个view上
 * 进行远程画面渲染
 * param localView:本地预览窗口,传入本地view,连麦准备时间将会自动绘制预览画面在此view上
 * param isAudioVideo:是否是音视频连麦,不是音视频即是纯音频连麦(YES表示音视频连麦,NO表示音频连麦)
 */
-(void)requestAVMessageWithLocalView:(UIView *)localView isAudioVideo:(BOOL)isAudioVideo;
/**
 *  @brief 当收到- (void)acceptSpeak:(NSDictionary *)dict;回调方法后,调用此方法
 * dict 正是- (void)acceptSpeak:(NSDictionary *)dict;接收到的的参数
 * remoteView 是远程连麦页面的view,需要自己设置并发给SDK,SDK将要在这个view上进行远程画面渲染
 */
- (void)saveUserInfo:(NSDictionary *)dict remoteView:(UIView *)remoteView;
/**
 *  @brief 将要连接WebRTC
 */
-(void)gotoConnectWebRTC;
/**
 *  @brief 观看端主动断开连麦时候需要调用的接口
 */
- (void)disConnectSpeak;

##3.8 切换线路和清晰度

代理方法(可选)


 /**
  *  @brief  切换线路
  *  @param  firRoadNum 线路
  *  @param  secRoadKeyArray 清晰度[@"标清",@"高清"]
  */
- (void)firRoad:(NSInteger)firRoadNum secRoadKeyArray:(NSArray *)secRoadKeyArray;

主动方法(可选)

/**
 *	@brief   切换播放线路和清晰度
 *  firIndex表示第几个线路
 *  key表示该线路对应的secRoadKeyArray里面的元素
 */
- (void)switchToPlayUrlWithFirIndex:(NSInteger)firIndex key:(NSString *)key;

3.9 答题卡功能

/**
 *  @brief  开始答题
 */
- (void)start_vote:(NSInteger)count singleSelection:(BOOL)single;
/**
 *  @brief  结束答题
 */
- (void)stop_vote;
/**
  *  @brief  答题结果
  *  @param  resultDic {answerCount         //参与回答人数
                        correctOption       //正确答案 (单选字符串,多选字符串数组)
                        statisics[{         //统计数组
                                    count   //选择当前选项人数
                                    option  //选项序号
                                    percent //正确率 }]
                        voteCount           //题目数量
                        voteId              //题目ID
                        voteType            //题目类型}   
  */
- (void)vote_result:(NSDictionary *)resultDic;
/**
 *    @brief    收到打卡提交结果
 *    dic{
     "success": true,
     "data": {
         "isRepeat": false//是否重复提交打卡
     }
 }
 */
-(void)hdReceivedPunchResultWithDict:(NSDictionary *)dic;
/**
 *    @brief    收到开始打卡
 *    dic {
     "punchId": "punchId",
     "expireTime": "2019-10-26 10:00:00",
     "remainDuration": 124
    }
 *    当没有设置时长,即无过期时间时
 *    {
     "punchId": "asasdasdasdasd",
     "remainDuration": -1 //其中-1表示剩余无限时间。
 }
 */
-(void)hdReceivedStartPunchWithDict:(NSDictionary *)dic;
/**
 *    @brief    收到结束打卡
 *    dic{
     "punchId": "punchId"
 }
 */
-(void)hdReceivedEndPunchWithDict:(NSDictionary *)dic;
/**
 *  @brief 答单选题
 */
-(void)reply_vote_single:(NSInteger)index;
/**
 *  @brief 答多选题
 	 @param  IndexArray [题目index,题目index] 例:[1,2]
 */
-(void)reply_vote_multiple:(NSMutableArray *)indexArray;

3.10 问卷功能

代理方法(可选)

/**
 *  @brief  发布问卷
 */
- (void)questionnaire_publish;
/**
 *  @brief  结束发布问卷
 */
- (void)questionnaire_publish_stop;
/**
 *  @brief  获取问卷详细内容
 *  @param  detailDic { forcibly               //1就是强制答卷,0为非强制答卷
           			    id                     //问卷主键ID
           				subjects               //包含的项目
            			submitedAction         //1提交后查看答案,0为提交后不查看答案
           				title                  //标题 }
 */
- (void)questionnaireDetailInformation:(NSDictionary *)detailDic;
/**
 *  @brief  获取问卷统计
 *  @param  staticsDic { forcibly               //1就是强制答卷,0为非强制答卷
            			 id                     //问卷主键ID
           				 subjects               //包含的项目
           				 submitedAction         //1提交后查看答案,0为提交后不查看答案
           				 title                  //标题 }
 */
- (void)questionnaireStaticsInformation:(NSDictionary *)staticsDic;
/**
 *  @brief  提交问卷结果(成功,失败)
 */
- (void)commitQuestionnaireResult:(BOOL)success;
/**
 *  @brief  问卷功能
 */
- (void)questionnaireWithTitle:(NSString *)title url:(NSString *)url;

主动方法(可选)

/**
 *  @brief 提交问卷结果
 *  @param    dic{subjectsAnswer[{selectedOptionId      //选中选项ID
                   				 	 subjectId             //题目ID}]}
 */
-(void)commitQuestionnaire:(NSDictionary *)dic;
/**
 *  @brief 主动请求问卷
 */
-(void)getPublishingQuestionnaire;

3.11 广播功能

代理方法(可选)

/**
 *  @brief  接收到发送的广播
 *  @param  dic {content     //广播内容
                 userid      //发布者ID
                 username    //发布者名字
                 userrole    //发布者角色 }
 */
- (void)broadcast_msg:(NSDictionary *)dic;
/**
 *  @brief  接收到最后一条广播(直播中途进入,会返回最后一条广播)
 *  @param  array[{	content 			//广播内容
   						publisherId  		//发布者ID
    					publisherName 	//发布者名字
    					publisherRole 	//发布者角色
   						time 				//发布时间
}]
 */
- (void)broadcastLast_msg:(NSArray *)array;

3.12 签到功能

代理方法(可选)

/**
 *  @brief  开始签到
 */
- (void)start_rollcall:(NSInteger)duration;

主动方法(可选)

/**
 *  @brief 签到
 */
-(void)answer_rollcall;
/**
提交打卡

@param punchId 打卡id
*/
- (void)hdCommitPunchWithPunchId:(NSString *)punchId;
/**
查询打卡信息
*/
- (void)hdInquirePunchInformation;

3.13 抽奖功能

代理方法(可选)

/**
 *  @brief  开始抽奖
 */
- (void)start_lottery;
/**
 *  @brief  抽奖结果
 *  remainNum   剩余奖品数
 */
- (void)lottery_resultWithCode:(NSString *)code myself:(BOOL)myself winnerName:(NSString *)winnerName remainNum:(NSInteger)remainNum;
/**
 *  @brief  退出抽奖
 */
- (void)stop_lottery;

3.14 修改昵称

代理方法(可选)

/**
 *    @brief    修改昵称
 */
- (void)onChangeNickname:(NSString *)nickNime;

主动方法(可选)

/**
 *    @brief     修改昵称
 *    @param     nickName  修改后的昵称
 */
- (void)changeNickName:(NSString *)nickName;

3.15 在线人数

代理方法(可选)

/**
 *	@brief	收到在线人数
 */
- (void)onUserCount:(NSString *)count;
/**
收到老师列表
 teachers =     (
             {
         id = "";//老师id
         ip = "";//IP地址
         name = "";老师昵称
         role = teacher;//角色
     }
 );
*/
-(void)onOnlineTeachers:(NSDictionary *)dic;

主动放法(可选)

/**
 *	@brief  获取在线房间人数,当登录成功后即可调用此接口,登录不成功或者退出登录后就不可以调用了,如果要求实时性比较强的话,可以写一个定时器,不断调用此接口,几秒钟发一次就可以,然后在代理回调函数中,处理返回的数据,15秒响应一次
 */
- (void)roomUserCount;
/**
获取老师列表
*/
- (void)getOnlineTeachers;

3.16 随堂测功能

代理方法(可选)

/**
 *    @brief       接收到随堂测(The new method)
 *    rseultDic    随堂测内容
      resultDic    {isExist                         //1 随堂考存在 0随堂考不存在
                    practice {id                    //随堂考主键ID
                              isAnswered            //false 未回答过 true 回答过
                              options = ({ id       //选项主键ID
                                           index    //选项序号})
                              publishTime           //发布时间
                              status                //发布状态 1开启 0关闭
                              type                  //题目类型 0判断 1单选 2多选}
                    serverTime                      //分发时间}
 *
 */
-(void)receivePracticeWithDic:(NSDictionary *) resultDic;
/**
 *    @brief    随堂测提交结果(The new method)
 *    rseultDic    提交结果,调用commitPracticeWithPracticeId:(NSString *)practiceId options:(NSArray *)options后执行
 *
      resultDic {datas {practice                                 //随堂测
                             { answerResult                      //
                               id                                //随堂测主键ID
                               isRepeatAnswered                  //是否重置答案
                               options ({  count                 //参与人数
                                             id                  //选项主键ID
                                             index               //选项序号
                                             isCorrect           //是否正确
                                             percent             //选项占比})
                               submitRecord ({ optionId          //提交记录 提交选项ID
                                               optionIndex       //提交选项序号})
                               type                              //题型 0 判断 1单选 2多选}}}
 */
-(void)practiceSubmitResultsWithDic:(NSDictionary *) resultDic;
/**
 *    @brief    		随堂测统计结果(The new method)
 *    rseultDic     统计结果,调用getPracticeStatisWithPracticeId:(NSString *)practiceId后执行
      resultDic  {practice {                                //随堂测
                            answerPersonNum                 //回答人数
                            correctPersonNum                //回答正确人数
                            correctRate                     //正确率
                            id                              //随堂测主键ID
                            options ({                      //选项数组
                                        count               //选择人数
                                        id                  //选项ID
                                        index               //选项序号
                                        isCorrect           //是否正确
                                        percent             //选项选择率})
                            status                          //状态
                            type                            //题型 0判断 1单选 2多选}}
 */
-(void)practiceStatisResultsWithDic:(NSDictionary *) resultDic;
/**
 *    @brief       随堂测排名结果
 *    rseultDic    排名结果,调用getPracticeRankWithPracticeId:(NSString *)practiceId后执行
      ressult{practice {                        //随堂测
                        id                      //随堂测主键ID
                        ranking ({              //排名
                                costTime        //回答用时
                                viewerId        //用户ID
                                viewerName      //用户名})}}
 */
-(void)practiceRankResultsWithDic:(NSDictionary *) resultDic;
/**
 *    @brief    停止随堂测(The new method)
 *    rseultDic    结果
 *    resultDic {practiceId //随堂测主键ID}
 */
-(void)practiceStopWithDic:(NSDictionary *) resultDic;
 /**
  *    @brief    关闭随堂测(The new method)
  *    rseultDic    结果
  *    resultDic {practiceId //随堂测主键ID}
  */
-(void)practiceCloseWithDic:(NSDictionary *) resultDic;
/**
 *    @brief    收到奖杯(The new method)
 *    dic       结果
 *    "type":  1 奖杯 2 其他
 *    "viewerName": 获奖用户名
 *    "viewerId": 获奖用户ID
 */
-(void)prize_sendWithDict:(NSDictionary *)dic;

主动方法(可选)

/**
 *      @brief     提交随堂测 
 *      @param     practiceId  随堂测ID
 *      @param     options   选项ID
 */
- (void)commitPracticeWithPracticeId:(NSString *)practiceId options:(NSArray *)options;
/**
 *      @brief     获取随堂测统计信息(可多次调用) 
 *      @param     practiceId  随堂测ID
 */
-(void)getPracticeStatisWithPracticeId:(NSString *)practiceId;
/**
 *      @brief     获取随堂测排名(可多次调用) 
 *      @param     practiceId  随堂测ID
 */
-(void)getPracticeRankWithPracticeId:(NSString *)practiceId;
/**
 *    @brief     获取随堂测
 *    @param     practiceId  随堂测ID(没有传@"")
 */
-(void)getPracticeInformation:(NSString *)practiceId;

3.17 公告

代理方法(可选)

/**
 *  @brief  公告
 */
- (void)announcement:(NSString *)str;
/**
 *  @brief  监听到有公告消息
 *  @dict   {action         //action 返回release 取出公告内容,action 返回remove 删除公告
             announcement   //公告内容}
 */
- (void)on_announcement:(NSDictionary *)dict;

3.18 跑马灯

代理方法(可选)

/**
 *    @brief    跑马灯
 *    @param    dic action  [{                      //事件
                                duration            //执行时间
                                end {               //结束位置
                                        alpha       //透明度
                                        xpos        //x坐标
                                        ypos        //y坐标 },
                                start {             //开始位置
                                        alpha       //透明度
                                        xpos        //x坐标
                                        ypos        //y坐标}]
                    image {                         //包含图片
                                height              //图片高度
                                image_url           //地址
                                width               //图片宽度}
                    loop                            //循环次数 -1 无限循环
                    text   {                        //文字信息
                                 color              //文字颜色
                                 content            //文字内容
                                 font_size          //字体大小}
                    type                            //当前类型 text 文本 image 图片
 */
-(void)receivedMarqueeInfo:(NSDictionary *)dic;

4.常见问题

4.1 旋转屏错误

常用的旋转屏方式

第一个方法决定是否支持多方向旋转屏,如果返回NO则后面的两个方法都不会再被调用,而且只会支持默认的UIInterfaceOrientationMaskPortrait方向;

第二个方法直接返回支持的旋转方向,该方法在iPad上的默认返回值是UIInterfaceOrientationMaskAll,iPhone上的默认返回值是UIInterfaceOrientationMaskAllButUpsideDown,官方文档有说明

第三个方法返回最优先显示的屏幕方向,比如同时支持Portrait和Landscape方向,但想优先显示Landscape方向,那软件启动的时候就会先显示Landscape,在手机切换旋转方向的时候仍然可以在Portrait和Landscape之间切换

HD云直播的页面跳转均是采用模态形式跳转

- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^ __nullable)(void))completion NS_AVAILABLE_IOS(5_0);

在每个控制器或者基类控制器设置旋转选项

#pragma mark - 屏幕旋转
- (BOOL)shouldAutorotate{
    return NO;//该旋转的页面自己变量控制
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return UIInterfaceOrientationPortrait;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

4.2 Swift实现代理错误

//初始化  
    let parameter = PlayParameter.init()
    /**
*配置各种参数
*/
    //守护代理
guard let player = RequestData else {
return}
player.delegate = self

4.3 查看手机日志

首先: 在AppDelegate中写如下代码(仅限CCSDK);

[[SaveLogUtil sharedInstance]isNeedToSaveLog:YES];

第一步:选择Windows下面的Devices and Simulators

第二步:点击Devices and Simulators 会出现手机信息以及测试的INSTALLED APPS, 点击设置(齿轮图标) 会出现三个选项, 选择Download Container...

第三步: 点击Download Container... 下载并保存日志文件,打开文件找到XXLog文件里面就是相关的打印日志

第四步:这里可以看到相关的请求信息和打印日志, 也可以判断错误原因

4.4 编译失败和打包上架打包失败

错误大意为

Failed to verify bitcode in xxxxx
error: Bundle only contains bitcode-marker /var/folders/s5/lnk362pd4cs0lmtn_43ppjzw0000gn/T/XcodeDistPipeline.2TS/Root/Payload/268YK.appxxxxxxxxxx (armv7)

解决办法:

第一步: xcode -> file -> Workspace Settings

第二步: Shared Workspace Settings:

第三步:Build System -> Legacy Build System

4.5 提交问卷的格式

主动提交问卷这个方法参数格式

-(void)commitQuestionnaire:(NSDictionary *)dic
{
    subjectsAnswer =     (
                {
//单选
            selectedOptionId = 6DBB147BC4EF99A7;
            subjectId = 5DEEA9F9FD1DDFAD;
        },
                {
//多选
            selectedOptionIds = "A2F4436135131236,1A8C59C6F3A774F5";
            subjectId = 658A573395F3E00D;
        },
                {
//问答
            answerContent = Qqq;
            subjectId = 10F9E9D82094F36C;
        }
    );
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84960 人气
更多

推荐作者

遂心如意

文章 0 评论 0

5513090242

文章 0 评论 0

巷雨优美回忆

文章 0 评论 0

junpengz2000

文章 0 评论 0

13郎

文章 0 评论 0

qq_xU4RDg

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文