iOS 直播观看 SDK 开发指南 - 文章教程

iOS 直播观看 SDK 开发指南

发布于 2021-02-21 字数 44798 浏览 1162 评论 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;
        }
    );
}

如果你对这篇文章有疑问,欢迎到本站 社区 发帖提问或使用手Q扫描下方二维码加群参与讨论,获取更多帮助。

扫码加入群聊

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

目前还没有任何评论,快来抢沙发吧!

关于作者

JSmiles

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

2583 文章
29 评论
84935 人气
更多

推荐作者

猫性小仙女

文章 1 评论 0

qq_VO6LhT

文章 0 评论 0

猿舌电影

文章 0 评论 0

7556275422

文章 0 评论 0

YYQ_139

文章 0 评论 0