实现1对1呼叫(不含UI集成V3)

更新时间: 2025/02/14 10:58:04

本文介绍如何通过集成呼叫组件(NERTCCallkit)基础包(不含 UI),实现 1 对 1 呼叫相关业务逻辑。根据业务需求,您需要自行实现相关 UI 界面。本文介绍呼叫组件 V3 版本 的集成和实现方法。

注意事项

  • 呼叫组件默认使用调试模式。应用正式上线前,请在 网易云信控制台 中将指定应用的鉴权方式改回 安全模式。安全模式下需要使用 Token 加入房间,详细说明请参考 Token 鉴权
  • 针对呼叫组件中的回调信息,开发者要做好相应回调数据的上报及存储,以便于后期上线之后排查问题。

开发环境

在开始运行工程之前,请您准备以下开发环境:

  • Xcode 10 及以上版本。
  • iOS 9.0 及以上版本的 iOS 设备。
  • 已安装 CocoaPods。

准备工作

集成呼叫组件

V3 版本 的呼叫组件(NERTCCallkit)基于网易云信 NIM SDK(V10)和 NERTC SDK 实现通话呼叫。

第一步:集成 IM SDK

单击查看集成 NIM SDK 的操作步骤。如果您的项目中已经集成了 NIM SDK,请忽略该步骤。
  1. 安装 CocoaPods 后,在项目所在目录下执行以下命令,创建 Podfile 文件。

    CocoaPodspod init
    
  2. 在 Podfile 文件中添加对应的资源。

    CocoaPods 集成资源关键词说明:

    关键词 所含资源
    NIMSDK_LITE IM 即时通讯,默认引入网易对象存储(NetEase Object Storage,NOS)文件存储能力
    NIMSDK_LITE/FCS IM 即时通讯,默认引入 S3 文件存储能力

    现以只需要集成即时通讯功能(NOS)为例,您可在 Podfile 中写入:

    CocoaPodspod 'NIMSDK_LITE'
    
  3. 执行以下命令更新本地仓库,查看版本信息。最新版本信息请参考 更新日志

    CocoaPodspod search NIMSDK_LITE   //本地仓库中查询资源的版本信息
    pod repo update          //更新本地仓库
    
  4. 执行以下命令安装 SDK:

    CocoaPodspod install
    

SDK 版本限制:

呼叫组件与 NIM SDK、NERTC SDK 之间存在映射关系,使用呼叫组件时,必须使用指定版本的 NIM SDK 和 NERTC SDK。当前最新版本 V3.3.0 适配 NIM SDK V10.6.0 和 NERTC SDK V5.6.50,其他版本的适配关系请参考 更新日志

第二步:初始化 IM SDK

将 IM SDK 集成到客户端后,需要先完成 IM SDK 的初始化才能使用其他功能。

  1. 在项目文件中引入头文件 NIMSDK.h

    Objective-C#import <NIMSDK/NIMSDK.h>
    
  2. 调用 registerWithOptionV2 方法初始化 SDK,推荐在应用程序启动时初始化,目的是配置 SDK 并准备进行登录和即时通讯功能。

    Objective-CNIMSDKOption *option = [NIMSDKOption optionWithAppKey:appKey];
    option.apnsCername = @"your apns certificate";
    option.pkCername = @"your push kit certificate";
    // 配置 useV1Login
    V2NIMSDKOption *v2Option = [[V2NIMSDKOption alloc] init];
    //激活 V10 所有 API,默认使用 V10 的登录接口登录 IM
    v2Option.useV1Login = NO;
    //若仍使用 V9 的登录接口登录 IM
    //v2Option.useV1Login = YES;
    [[NIMSDK sharedSDK] registerWithOptionV2:option v2Option:v2Option];
    

    以上提供了一个简化的初始化示例,更多初始化信息请参考 初始化 SDK

第三步:实现登录 IM

调用 login 方法登录 IM。

本文以实现 静态 Token 登录为例,动态 Token 登录以及自动登录的实现方法请参考 登录 IM

示例代码如下:

Objective-C- (void)login
{
    NSString *accountId = @"accountId";
    NSString *token = @"token";
    [[NIMSDK sharedSDK].v2LoginService login:accountId token:token
            option:nil
              success:^{
        NSLog(@"login succ");
    }
              failure:^(V2NIMError * _Nonnull error) {
        NSLog(@"login fail: error = %@", error);
    }];
}

第四步:引入呼叫组件

建议使用 CocoaPods 进行管理。呼叫组件内部没有引入 NERTC,请在 Podfile 中添加以下内容,单独引入 NERTC SDK。

CocoaPodspod 'NERtcCallKit', '3.3.0'
pod 'NERtcSDK', '5.6.50', :subspecs => ['RtcBasic']    // subspecs => ['RtcBasic']用于指定使用 RTC 基础版本,不包含美颜功能。若要使用美颜功能,此行请修改为 pod 'NERtcSDK', '5.6.50'

SDK 版本限制:

呼叫组件与 NIM SDK、NERTC SDK 之间存在映射关系,使用呼叫组件时,必须使用指定版本的 NIM SDK 和 NERTC SDK。当前最新版本 V3.3.0 适配 NIM SDK V10.6.0 和 NERTC SDK V5.6.50,其他版本的适配关系请参考 更新日志

第五步:初始化呼叫组件

呼叫组件的实现为单实例,通过接口 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

(可选)设置预览的分辨率

在初始化呼叫组件之后,调用 RTC 的 setLocalVideoConfig 接口,通过 widthheight 参数设置采集分辨率。默认预览分辨率为 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 同意呼叫,通话接通、两人进行实时音视频通信。

  1. 用户 A 以及用户 B 均完成网易云信 IM SDK 的登录,并成功初始化呼叫组件。

  2. 用户 A 获取到自己以及用户 B 登录网易云信 IM SDK 的账号。

  3. (可选)配置自定义推送(发起呼叫时携带下文参数,具体可参考 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、自定义参数等。
  4. 用户 A 通过如下代码触发呼叫用户 B 的操作。

    Objective-CNECallParam *callParam = [[NECallParam alloc] initWithAccId:@"callee accid" withCallType:NECallTypeVideo];
    [[NECallEngine sharedInstance] call:callParam completion:^(NSError * _Nullable error) {
    
    }];
    

    如果需要实现音视频录制,请在调用 call 方法之前,调用 setParameters 方法,设置 kNERtcKeyRecordAudioEnabledkNERtcKeyRecordVideoEnabled 的值为 YES

  5. 用户 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
              }
          }];
      }
      
  6. 通话完成后单击挂断即可。

    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];
}
此文档是否对你有帮助?
有帮助
去反馈
  • 注意事项
  • 开发环境
  • 准备工作
  • 集成呼叫组件
  • 第一步:集成 IM SDK
  • 第二步:初始化 IM SDK
  • 第三步:实现登录 IM
  • 第四步:引入呼叫组件
  • 第五步:初始化呼叫组件
  • (可选)设置预览的分辨率
  • 实现一对一呼叫
  • 实现方法
  • 示例代码