快速开始
1. 前提条件
支持 iOS 8.0 或以上版本的 iOS 真机设备
有效的菊风开发者账号 免费注册
2. 准备工作
开始之前,请先做好如下准备工作。
2.1 SDK 下载
点击 iOS SDK 进行下载。如果已经下载了 SDK,请直接进行 SDK 配置。
2.2 AppKey 获取
AppKey 是应用在 菊风云平台 中的唯一标识。需要在 SDK 初始化的时候使用,AppKey 获取请参考 创建应用 。
2.3 SDK 配置
您可以在工程中使用静态库或者动态库,此处介绍使用静态库的配置方法。如果想使用动态库,请参考动态库的配置说明文档 iOS 导入动态库 。
只有完成 SDK 的配置之后,您才可以集成 JC SDK 提供的功能,请按以下操作完成静态库的配置。
2.3.1 导入静态库
在 Mac 环境下打开下载的 iOS SDK,在 sdk 文件夹内包含了 lib、JCSDKOC.framework 和 include 三个文件。

将 sdk 文件夹拷贝到您工程所在的目录下。
2.3.1.1 导入 SDK
打开 Xcode,进入 TARGETS > Project Name > Build Phases > Link Binary with Libraries 菜单,点击 ‘+’ 符号,导入 sdk 文件夹下的 JCSDKOC.framework、lib 文件夹下的两个 .a 文件,如下图

2.3.1.2 导入 SDK 依赖的库
继续点击 ‘+’ 符号,导入下图红框中的库

2.3.1.3 设置路径
点击 ‘Build Settings’,找到 Framework Search Paths 、Header Search Paths(头文件路径) 和 Library Search Paths(库文件路径)。并设置 Framework Search Paths、Header Search Paths 和 Library Search Paths,如下图

2.3.1.4 设置 Enable Bitcode 为 NO
点击 ‘Build Settings’,找到 Enable Bitcode 设置为 NO,如下图

2.3.1.5 设置 Other Linker Flags 的参数为 -ObjC
点击 ‘Build Settings’,找到 Other Linker Flags 并添加参数 -ObjC,如下图

2.3.1.6 设置预处理宏定义
点击 ‘Build Settings’,找到 Preprocessor Macros,在右侧输入 ZPLATFORM=ZPLATFORM_IOS,如下图

如果设置了 VoIP 推送,则还需要在 Preprocessor Macros 下的 Debug 中输入 VOIP_PUSH_DEBUG,如下图

2.3.1.7 设置 Documentation Comments 为 NO
点击 ‘Build Settings’,找到 Documentation Comments 并设置为 NO,如下图

2.3.1.8 设置后台运行模式
点击 ‘Capabilities’,找到 Background Modes,勾选红框内的 Audio, AirPlay, and Picture in Picture ,如下图

2.3.2 权限设置
2.3.2.1 设置麦克风和摄像头权限
点击 ‘Info’,然后添加麦克风和摄像头的权限,如下图

2.3.2.2 编译运行
以上步骤进行完后,编译工程,如果提示 succeeded,恭喜您已经成功配置 SDK,可以进行 SDK 初始化了。
2.4 SDK 初始化
在使用 SDK 之前,需要进行 SDK 的初始化。
在 App 加载完成后(didFinishLaunchingWithOptions)初始化 SDK,具体接口如下
/**
* @brief 创建 JCClient 实例
* @param appKey 用户从 菊风云 平台上申请的 AppKey 字符串
* @param callback 回调接口,用于接收 JCClient 相关通知
* @param extraParams 额外参数,没有则填nil
* @return JCClient 对象
*/
+(JCClient*)create:(NSString*)appKey callback:(id<JCClientCallback>)callback extraParams:(NSDictionary*)extraParams;
示例代码
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// 初始化各模块,因为这些模块实例将被频繁使用,建议声明在单例中
JCClient *client = [JCClient create:@"your appkey" callback:self extraParams:nil];
return YES;
}
SDK 初始化之后,即可进行登录的集成。
3. 登录
登录涉及 JCClient 类及其回调 JCClientCallback 类,其主要作用是负责登录、登出管理及帐号信息存储。
登录之前,可以通过配置关键字进行登录的相关配置,如是否使用代理服务器登录以及服务器地址的设置,具体如下。
3.1 登录环境设置
服务器地址设置,包括国际环境服务器地址和国内环境服务器地址
/**
* @brief 设置配置相关参数
* JCClientConfigServer, JCClientConfigHttpsProxy 均需要在 login 之前调用
* @param key 参数关键字, 参见 JCClientConstants 中定义
* @param value 参数值
* @return 返回 true 表示设置成功,false 表示设置失败
*/
-(bool)setConfig:(NSString*)key value:(NSString*)value;
其中,配置关键字有
/// 服务器
extern NSString* const JCClientConfigServer;
/// 设备标识,用户可以自己传入设备标识
extern NSString* const JCClientConfigDeviceId;
/// https代理, 例如 192.168.1.100:3128
extern NSString* const JCClientConfigHttpsProxy;
示例代码
JCClient *client = [JCClient create:@"your appkey" callback:self extraParams:nil];
// 设置登录地址(国内环境)
[client setConfig:JCClientConfigServer value:@"http:cn.router.justalkcloud.com:8080"];
// 设置登录地址(国际环境)
[client setConfig:JCClientConfigServer value:@"http:intl.router.justalkcloud.com:8080"];
设置登录相关参数后,可以调用下面的方法获取相关的配置
/**
* @brief 获取配置相关参数
* @param key 参数关键字, 参见 JCClientConstants 中定义
* @return 成功返回字符串类型具体值, 失败返回 NULL
*/
-(NSString*)getConfig:(NSString*)key;
示例代码
// 获取登录配置
[client getConfig:JCClientConfigServer];
3.2 发起登录
登录参数设置之后,即可调用 login 接口发起登录操作
/**
* @brief 登录
* @param userId 用户名
* @param password 密码,免鉴权模式密码可以随意输入,但不能为空
* @return 返回 true 表示正常执行调用流程,false 表示调用异常,异常错误通过 JCClientCallback 通知
* @warning 目前只支持免鉴权模式,免鉴权模式下当账号不存在时会自动去创建该账号
* @warning 用户名为英文、数字和'+' '-' '_' '.',长度不要超过64字符,'-' '_' '.'不能作为第一个字符
*/
-(bool)login:(NSString*)userId password:(NSString*)password;
示例代码
// 登录
[client login:@"userId" password:@"your password"];
登录的结果通过 onlogin 回调接口上报
/**
* @brief 登录结果回调
* @param result true 表示登录成功,false 表示登录失败
* @param reason 当 result 为 false 时该值有效
* @see JCClientReason
*/
-(void)onLogin:(bool)result reason:(JCClientReason)reason;
其中,JCClientReason 有
/// 正常
JCClientReasonNone,
/// sdk 未初始化
JCClientReasonSDKNotInit,
/// 无效的参数
JCClientReasonInvalidParam,
/// 函数调用失败
JCClientReasonCallFunctionError,
/// 当前状态无法再次登录
JCClientReasonStateCannotLogin,
/// 超时
JCClientReasonTimeOut,
/// 网络异常
JCClientReasonNetWork,
/// appkey 错误
JCClientReasonAppKey,
/// 账号密码错误
JCClientReasonAuth,
/// 无该用户
JCClientReasonNoUser,
/// 被强制登出
JCClientReasonServerLogout,
/// 其他错误
JCClientReasonOther,
登录成功之后,SDK 会自动保持与服务器的连接状态,直到用户主动调用登出接口,或者因为帐号在其他设备登录导致该设备登出。
3.3 登出
登出调用下面的方法,登出后不能进行平台上的各种业务操作
/**
* 登出 菊风云 平台,登出后不能进行平台上的各种业务
* @return 返回 true 表示正常执行调用流程,false 表示调用异常,异常错误通过 JCClientCallback 通知
*/
-(bool)logout;
登出结果通过 onlogout 回调接口上报
/**
* @brief 登出回调
* @param reason 登出原因
* @see JCClientReason
*/
-(void)onLogout:(JCClientReason)reason;
当登录状态发生改变时,会通过 onClientStateChange 回调接口上报
/**
* @brief 登录状态变化通知
* @param state 当前状态值
* @param oldState 之前状态值
*/
-(void)onClientStateChange:(JCClientState)state oldState:(JCClientState)oldState;
JCClientState 有
// 未初始化
JCClientStateNotInit,
// 未登录
JCClientStateIdle,
// 登录中
JCClientStateLogining,
// 登录成功
JCClientStateLogined,
// 登出中
JCClientStateLogouting,
示例代码
-(void)onClientStateChange:(JCClientState)state oldState:(JCClientState)oldState
{
if (state == JCClientStateIdle) { // 未登录
...
} else if (state == JCClientStateLogining) { // 登录中
...
} else if (state == JCClientStateLogined) { // 登录成功
...
} else if (state == JCClientStateLogouting) { // 登出中
...
}
}
集成登录后,即可进行相关业务的集成。
/**
* @brief 设置是否是前台,当应用进入前台标志为true,进入后台标志为false
* @param foreground true 是前台,false 是后台
*/
-(void)setForeground:(bool)foreground;
完成以上步骤,就做好了基础工作,您可以开始集成业务了。
4. 业务集成
一对一语音通话涉及以下类
| 名称 | 描述 |
|---|---|
| JCCall | 一对一通话类,包含一对一语音和视频通话功能 |
| JCCallItem | 通话对象类,此类主要记录通话的一些状态,UI 可以根据其中的状态进行显示逻辑 |
| JCCallCallback | 通话模块回调代理 |
| JCMediaDevice | 设备模块,主要用于视频、音频设备的管理 |
| JCMediaDeviceCallback | 设备模块回调代理 |
更多接口的详细信息请参考 API 说明文档 。
接口调用逻辑和相关状态

说明:蓝色和黄色字体表示接口,红色字体表示通话状态。
开始集成通话功能前,请先进行模块的初始化。
创建 JCCall 实例
/**
* @brief 创建 JCCall 实例
* @param client JCClient 实例
* @param mediaDevice JCMediaDevice 实例
* @param callback JCCallCallback 回调接口,用于接收 JCCall 相关回调事件
* @return 返回 JCCall 实例
*/
+(JCCall*)create:(JCClient*)client mediaDevice:(JCMediaDevice*)mediaDevice callback:(id<JCCallCallback>)callback;
创建 JCMediaDevice 实例
/**
* @brief 创建 JCMediaChannel 对象
* @param client JCClient 对象
* @param mediaDevice JCMediaDevice 对象
* @param callback JCMediaChannelCallback 回调接口,用于接收 JCMediaChannel 相关通知
* @return 返回 JCMediaChannel 对象
*/
+(JCMediaChannel*)create:(JCClient*)client mediaDevice:(JCMediaDevice*)mediaDevice callback:(id<JCMediaChannelCallback>)callback;
示例代码
// 初始化各模块,因为这些模块实例将被频繁使用,建议声明在单例中
JCMediaDevice *mediaDevice = [JCMediaDevice create:client callback:self];
JCCall *call = [JCCall create:client mediaDevice:mediaDevice callback:self];
4.1 拨打通话
主叫调用下面的接口发起视频通话,此时 video 传入值为 false
/**
* @brief 一对一呼叫
* @param userId 用户标识
* @param video 是否为视频呼叫
* @param extraParam 透传参数,被叫方可获取透传参数
* @return 返回 true 表示正常执行调用流程,false 表示调用异常
*/
-(bool)call:(NSString*)userId video:(bool)video extraParam:(NSString *)extraParam;
示例代码
// 发起语音呼叫
[call call:@"peer number" video:false extraParam:@"自定义透传字符串"];
通话发起后,主叫和被叫均会收到新增通话的回调,通话状态变为 JCCallStatePending
/**
* @brief 新增通话回调
* @param item JCCallItem 对象
*/
-(void)onCallItemAdd:(JCCallItem*)item;
示例代码
-(void)onCallItemAdd:(JCCallItem*)item {
// 收到新增通话回调
}
4.2 应答通话
主叫发起呼叫后,被叫会收到 onCallItemAdd 回调事件,并通过回调带上来的 JCCallItem 中的 video 属性以及 direction 属性值 JCCallDirectionIn 判断是视频呼入还是语音呼入,此时可以调用下面的接口进行应答,语音通话只能进行语音应答
/**
* @brief 接听
* @param item JCCallItem 对象
* @param video 针对视频呼入可以选择以视频接听还是音频接听
* @return 返回 true 表示正常执行调用流程,false 表示调用异常
*/
-(bool)answer:(JCCallItem*)item video:(bool)video;
示例代码
-(void)onCallItemAdd:(JCCallItem*)item {
// 如果是语音呼入且在振铃中
if (item && item.direction == JCCallDirectionIn && !item.video) {
// 应答通话
[call answer:item video:false];
}
}
通话应答后,通话状态变为 JCCallStateConnecting。
4.3 通话建立
被叫接听通话后,双方将建立连接,此时,主叫和被叫都将会收到通话更新的回调,连接成功之后,通话将建立。通话状态变为 JCCallStateTalking。
现在您可以进行一对一语音通话了。
如果已经在语音通话中,但又有新通话进来,可以选择接听或挂断,如果选择接听,则原来的一路通话将被保持。
4.4 挂断通话
主叫或者被叫均可以调用下面的方法挂断通话
/**
* @brief 挂断
* @param item JCCallItem 对象
* @param reason 挂断原因
* @param description 挂断描述
* @return 返回 true 表示正常执行调用流程,false 表示调用异常
* @see JCCallReason
*/
-(bool)term:(JCCallItem*)item reason:(JCCallReason)reason description:(NSString*)description;
示例代码
// 挂断通话
JCCallItem *item = call.callItems[0];
[call term:item reason:JCCallReasonNone description:@"test"];
通话挂断后,UI 会收到移除通话的回调,通话状态变为 JCCallStateOk。
/**
* @brief 移除通话
* @param item JCCallItem 对象
* @param reason 通话结束原因
* @param description 通话结束原因的描述,只有被动挂断的时候,才会收到这个值,其他情况下则返回空字符串
* @see JCCallReason
*/
-(void)onCallItemRemove:(JCCallItem*)item reason:(JCCallReason)reason description:(NSString *)description;
示例代码
-(void)onCallItemRemove:(JCCallItem*)item reason:(JCCallReason)reason description:(NSString *)description { //移除通话回调
// 界面处理
}
其中,reason 有以下几种
| 名称 | 描述 |
|---|---|
| JCCallReasonNone | 无异常 |
| JCCallReasonNotLogin | 未登录 |
| JCCallReasonCallFunctionError | 函数调用错误 |
| JCCallReasonTimeOut | 超时 |
| JCCallReasonNetWork | 网络错误 |
| JCCallReasonCallOverLimit | 超出通话上限 |
| JCCallReasonTermBySelf | 自己挂断 |
| JCCallReasonAnswerFail | 应答失败 |
| JCCallReasonBusy | 忙 |
| JCCallReasonDecline | 拒接 |
| JCCallReasonUserOffline | 用户不在线 |
| JCCallReasonNotFound | 无此用户 |
| JCCallReasonRejectVideoWhenHasCall | 已有通话拒绝视频来电 |
| JCCallReasonRejectCallWhenHasVideoCall | 已有视频通话拒绝来电 |
| JCCallReasonOther | 其他错误 |
如果拨打通话时,对方未在线,则对方再次上线时会收到未接来电的回调
/**
* @brief上报服务器拉取的未接来电
* @param item JCCallItem 对象
*/
-(void)onMissedCallItem:(JCCallItem *)item;
