实现1对1呼叫(不含UI集成V2)
更新时间: 2024/08/23 10:16:57
本文介绍如何通过集成呼叫组件(NERTCCallkit)基础包(不含 UI),实现 1 对 1 呼叫(点对点呼叫)相关业务逻辑。根据业务需求,您需要自行实现相关 UI 界面。
注意事项
- 呼叫组件默认使用调试模式。应用正式上线前,请在 网易云信控制台 中将指定应用的鉴权方式改回 安全模式。安全模式下需要使用 Token 加入房间,详细说明请参考 Token 鉴权。
- 针对组件中的回调信息,开发者要做好相应回调数据的上报及存储,以便于后期上线之后排查问题。
开发环境
在开始运行工程之前,请您准备以下开发环境:
- Xcode 10 及以上版本。
- iOS 9.0 及以上版本的 iOS 设备。
- 已安装 CocoaPods。
准备工作
集成呼叫组件
步骤 1:集成 IM SDK
-
在 SDK 下载页面查看 IM SDK 的最新版本,并查询本地仓库中对应的版本是否为最新版本。
若不是最新版本,建议先更新本地仓库,以确保可以集成最新的 SDK 版本。
pod search NIMSDK_LITE //本地仓库中查询 NIMSDK_LITE 信息 pod repo update //更新本地仓库
-
在项目根目录下的
Podfile
文件中写入以下内容。pod 'NIMSDK_LITE'
-
执行以下命令安装 IM SDK。
pod install
步骤 2:初始化 IM SDK
将 IM SDK 集成到客户端后,需要先完成 IM SDK 的初始化才能使用其他功能。
- 在项目文件中引入头文件
NIMSDK.h
。
#import <NIMSDK/NIMSDK.h>
- 调用
registerWithOption:
方法初始化 SDK。
Objective-C- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
...
//推荐在程序启动的时候初始化 NIMSDK
NSString *appKey = @"your app key";//网易云信分配的 appKey
NIMSDKOption *option = [NIMSDKOption optionWithAppKey:appKey];
option.apnsCername = @"your APNs cer name";//APNs 推送证书名
option.pkCername = @"your pushkit cer name";//PushKit 推送证书名
[[NIMSDK sharedSDK] registerWithOption:option];
...
}
以上提供了一个简化的初始化示例,更多初始化信息请参考 初始化 SDK。
步骤 3:引入呼叫组件
建议使用 CocoaPods 进行管理。呼叫组件内部没有引入 NERTC,请在 Podfile
中添加以下内容,单独引入 NERTC SDK。
CocoaPodspod 'NERtcCallKit', '2.0.0'
pod 'NERtcSDK', '4.6.50', :subspecs => ['RtcBasic'] // subspecs => ['RtcBasic']用于指定使用 RTC 基础版本,不包含美颜功能。若要使用美颜功能,此行请修改为 pod 'NERtcSDK', '4.6.50'
SDK 版本限制:
-
呼叫组件与 NIM SDK、NERTC SDK 之间存在映射关系,使用呼叫组件时,必须使用指定版本的 NIM SDK 和 NERTC SDK。如果您在集成呼叫组件之前,已经集成了 NIM SDK 和 NERTC SDK,请确认 SDK 版本为指定版本。
-
不同版本的呼叫组件适配不同版本的 NIM SDK 和 NERTC SDK,具体版本的适配关系请参考 更新日志。
步骤 4:初始化呼叫组件
呼叫组件的实现为单实例,通过接口 NECallEngine.sharedInstance
获取此实例,调用实例方法 setup:
完成初始化。
setup:
方法为使用组件前必须调用的方法,若未初始化直接调用其他组件方法,会发生不可预知的问题或故障。
Objective-C#import <NERtcCallKit/NERtcCallKit.h>
@interface SomeViewController()<NECallEngineDelegate>
@end
@implementation SomeViewController
- (void)viewDidLoad {
[self setupSDK];
}
- (void)setupSDK {
NESetupConfig *config = [[NESetupConfig alloc] initWithAppkey:@"your app key"];
[[NECallEngine sharedInstance] setup:config];
}
@end
步骤 5:登录和登出 IM
若已经在 App 内实现了 NIMSDK 登录和登出逻辑,则不必调用相应的登录、登出接口,直接跳过此步骤即可。
使用组件的 NIMSDK login
进行登录,使用 NIMSDK logout
进行登出,登出或未进行登录则不能进行呼叫。
Objective-C[NIMSDK.sharedSDK.loginManager login:@"accid" token:@"token" completion:^(NSError * _Nullable error) {
}];
[NIMSDK.sharedSDK.loginManager logout:^(NSError * _Nullable error) {
}];
(可选)设置预览的分辨率
在初始化呼叫组件之后,调用 RTC 的 setLocalVideoConfig
接口,通过 width
和 height
参数设置采集分辨率。默认预览分辨率为 640*480。
Objective-CNERtcEngine *coreEngine = [NERtcEngine sharedEngine];
NERtcVideoEncodeConfiguration *config = [[NERtcVideoEncodeConfiguration alloc] init];
config.width = 640;
config.height = 360;
[coreEngine setLocalVideoConfig:config];
实现一对一呼叫
您也可以调用呼叫组件的 API,自己实现呼叫相关功能,实现方法如下:
实现方法
呼叫组件的典型应用场景为 1 对 1 呼叫场景,即用户 A 发起视频呼叫用户 B,用户 B 同意呼叫,通话接通、两人进行实时音视频通信。
-
用户 A 以及用户 B 均完成网易云信 IM SDK 的登录,并成功初始化呼叫组件。
-
用户 A 获取到自己以及用户 B 登录网易云信 IM SDK 的账号(AccId)。
-
(可选)配置自定义推送(发起呼叫时携带下文参数,具体可参考 API 文档)。
Objective-C
@interface NECallPushConfig : NSObject /// 推送标题 @property(nonatomic, strong) NSString *pushTitle; /// 推送内容 @property(nonatomic, strong) NSString *pushContent; /// 推送自定义字段 @property(nonatomic, strong) NSMutableDictionary *pushPayload; /// 是否计入未读计数,默认 YES @property(nonatomic, assign) BOOL needBadge; /// 是否需要推送,YES 表示推送,NO 表示不推送,默认 YES @property(nonatomic, assign) BOOL needPush; @end
推送参数需要在
pushPayload
的内层推送参数apsField
中设置。详细的配置方法请参考 [KB0198] 关于 IM 提供的推送配置 apsField 字段。pushPayload
的外层推送参数中只支持 iOS 部分属性的设置,例如 sound、自定义参数等。 -
用户 A 通过如下代码触发呼叫用户 B 的操作。
Objective-C
NECallParam *callParam = [[NECallParam alloc] initWithAccId:@"callee accid" withCallType:NECallTypeVideo]; [[NECallEngine sharedInstance] call:callParam completion:^(NSError * _Nullable error) { }];
如果需要实现音视频录制,请在调用
call
方法之前,调用 setParameters 方法,设置kNERtcKeyRecordAudioEnabled
和kNERtcKeyRecordVideoEnabled
的值为YES
。 -
用户 B 实现呼叫组件监听并且在有呼叫回调发生时候调用
accept
方法即可实现通话。-
被叫通话页面的前置页面监听。
Objective-C
- (void)onReceiveInvited:(NEInviteInfo *)info { [NIMSDK.sharedSDK.userManager fetchUserInfos:@[info.callerAccId] completion:^(NSArray<NIMUser *> * _Nullable users, NSError * _Nullable error) { if (error) { NSLog(@"fetchUserInfo failed : %@", error); }else { //调起通话页面(根据业务自己实现或者参考示例工程中的通话页面 NECallViewController ) } }]; }
-
被叫通话页面中接受通话邀请。
Objective-C
- (void)acceptCall { __weak typeof(self) weakSelf = self; [[NECallEngine sharedInstance] accept:^(NSError * _Nullable error) { if (error) { NSLog(@"接听失败 : %@", error); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 销毁当前通话页面 }); }else { //设置通话页面相关显示或者参考示例工程中的通话页面 NECallViewController } }]; }
-
-
通话完成后单击挂断即可。
Objective-C
- (void)hangup{ NEHangupParam *hangupParam = [[NEHangupParam alloc] init]; [[NECallEngine sharedInstance] hangup:hangupParam completion:^(NSError * _Nullable error) { }]; }
示例代码
由于完成一次视频通话还需要预览视图设置等复杂调用,如果要接入工程并完成视频呼叫流程还需参考如下代码,如果需要实现一些复杂操作请参考 呼叫组件示例 GitHub 项目源码。
1 对 1 通话在呼叫或收到呼叫邀请时需要设置相应的回调监听,用于接收对应通话的控制消息。首先在需要收到监听的地方实现 NERtcCallKitDelegate
。
Objective-C#import <NERtcCallKit/NERtcCallKit.h>
@interface SomeViewController: UIViewController <NECallEngineDelegate>
- (void)dealloc {
[NECallEngine.sharedInstance removeCallDelegate:self];
}
- (void)viewDidLoad {
[super viewDidLoad];
[NECallEngine.sharedInstance addCallDelegate:self];
}
#pragma mark - NERtcVideoCallDelegate
// 被叫实现监听回调
- (void)onReceiveInvited:(NEInviteInfo *)info {
[NIMSDK.sharedSDK.userManager fetchUserInfos:@[info.callerAccId] completion:^(NSArray<NIMUser *> * _Nullable users, NSError * _Nullable error) {
if (error) {
NSLog(@"fetchUserInfo failed : %@", error);
}else {
NIMUser *imUser = users.firstObject;
NECallViewController *callVC = [[NECallViewController alloc] init];
//callVC.isCaller = NO;
//callVC.remoteImAccid = imUser.userId;
[self.navigationController presentViewController:callVC animated:YES completion:nil];
}
}];
}
@end
SomeViewController
为通话页面的前置页面,可能是通讯录 IM 消息等页面,通话页面的使用参考下文代码或者示例工程。
Objective-C@interface NECallViewController : UIViewController<NECallEngineDelegate>
@property(strong,nonatomic) UIView *smallVideoView;
@property(strong,nonatomic) UIView *bigVideoView;
@end
@implementation NECallViewController {
- (void)dealloc {
[[NECallEngine.sharedInstance removeCallDelegate:self];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUI];
[self setupSDK];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[[NECallEngine sharedInstance] setupLocalView:nil];
}
- (void)setupUI {
[self.view addSubview:self.bigVideoView];
self.bigVideoView.frame = self.view.bounds;
[self.view addSubview:self.smallVideoView];
self.smallVideoView.frame = CGRectMake(0, 0, 100, 100);
}
- (void)setupSDK {
[NECallEngine.sharedInstance addCallDelegate:self];
[[NECallEngine sharedInstance] setTimeout:30];
[[NERtcEngine sharedEngine] setLoudspeakerMode:YES];
[[NERtcEngine sharedEngine] enableLocalVideo:YES];
}
// 主叫发起呼叫
- (void)didCall {
NECallParam *callParam = [[NECallParam alloc] initWithAccId:@"callee accid" withCallType:NECallTypeVideo];
[[NECallEngine sharedInstance] call:callParam completion:^(NSError * _Nullable error) {
NSLog(@"call error code : %@", error);
[[NECallEngine sharedInstance] setupLocalView:self.bigVideoView.videoView];
if (error) {
/// 对方离线时 通过 APNS 推送 UI 不弹框提示
if (error.code == 10202 || error.code == 10201) {
return;
}
if (error.code == 21000 || error.code == 21001) {
//呼叫失败销毁当前通话页面
}
}else {
}
}];
}
// 当被叫 onInvited 回调发生,调用 accept 接听呼叫
- (void)acceptCall {
__weak typeof(self) weakSelf = self;
[NECallEngine sharedInstance] accept:^(NSError * _Nullable error) {
if (error) {
NSLog(@"接听失败 : %@", error);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 销毁当前通话页面
});
}else {
[[NECallEngine sharedInstance] setupLocalView:weakSelf.smallVideoView];
[[NECallEngine sharedInstance] setupRemoteView:weakSelf.bigVideoView];
}
}];
}
// 主叫被叫结束通话
- (void)hangup{
NEHangupParam *hangupParam = [[NEHangupParam alloc] init];
[[NECallEngine sharedInstance] hangup:hangupParam completion:^(NSError * _Nullable error) {
}];
}
- (UIView *)bigVideoView {
if (!_bigVideoView) {
_bigVideoView = [[UIView alloc] init];
_bigVideoView.backgroundColor = [UIColor darkGrayColor];
}
return _bigVideoView;
}
- (UIView *)smallVideoView {
if (!_smallVideoView) {
_smallVideoView = [[UIView alloc] init];
_smallVideoView.backgroundColor = [UIColor darkGrayColor];
}
return _smallVideoView;
}
#pragma mark - NERtcVideoCallDelegate
- (void)onUserEnter:(NSString *)userID {
// 被叫加入可以进行视频通话,设置本地音视频相关 API
[[NECallEngine sharedInstance] setupLocalView:self.smallVideoView];
[[NECallEngine sharedInstance] setupRemoteView:self.bigVideoView];
}