tencent cloud

文档反馈

最后更新时间:2024-12-13 17:06:23
    VoIP(Voice over IP)Push 是 Apple 提供的用于响应 VoIP calls 的通知机制。结合 Apple 提供的 PushKit.framework 和 CallKit.framework 能够实现系统级的通话效果。
    由于 TIMPush 插件目前尚不支持 iOS 的 VoIP 通知,我们为您提供了一个免费的替代方案以帮助您在 iOS 设备上实现 VoIP 推送。
    说明:
    Apple 要求,VoIP Push 在 iOS 13.0 以后需要搭配 CallKit.framework 使用,否则 App 运行后会 crash。
    VoIP Push 无法复用 APNs 普通推送证书,需要单独在苹果开发者网站上 申请 VoIP Push 证书

    集成效果

    锁屏时的效果
    应用在后台的效果
    应用在后台展开的效果
    
    
    
    
    
    
    
    
    

    配置 VoIP Push

    如果想要接收 VoIP Push,需要遵循如下几个步骤:
    1. 申请 VoIP Push 证书。
    2. 上传证书到 Chat 控制台。
    3. 完成工程配置。
    4. 接入 TUICallKitVoIPExtension 组件。

    步骤1:申请 VoIP Push 证书

    在申请 VoIP Push 证书之前,请先登录 苹果开发者中心 网站,开启 App 的远程推送功能。当您的 AppID 具备了 Push Notification 能力后,按照如下步骤申请并配置 VoIP Push 证书:
    1. 登录 苹果开发者中心 网站,单击 Certificates, IDs & Profiles 选项卡中的 Certificates,进入 Certificates, Identifiers & Profiles 页面。
    
    
    
    2. 单击 Certificates 右侧的 +
    
    
    
    3. Create a New Certificate 选项卡中,选择 VoIP Services Certificate,并单击 Continue
    4. Select an App ID for your VoIP Service Certificate 选项卡中,选择您当前的 App 的 BundleID,并单击 Continue
    5. 
    接着,系统提示我们需要一个 Certificate Signing Request(CSR)。
    6. 我们接下来制作 CSR 文件。首先在 Mac 上打开 钥匙串访问工具(Keychain Access),在菜单中选择 钥匙串访问 > 证书助理 > 从证书颁发机构请求证书Keychain Access > Certificate Assistant > Request a Certificate From a Certificate Authority)。
    
    
    
    7. 输入用户电子邮件地址(您的邮箱)、常用名称(您的名称或公司名),选择 存储到磁盘,单击继续,系统将生成一个 *.certSigningRequest 文件。
    返回上述 步骤5 中 Apple Developer 网站刚才的页面,单击 Choose File 上传生成的*.certSigningRequest文件。
    
    
    
    8. 单击 Continue 后生成证书,点击 Download 下载对应的证书到本地。
    9. 双击打开刚才下载的 voip_services.cer,系统会将其导入钥匙串中。
    10. 打开钥匙串应用,在登录 > 我的证书,右键导出刚创建的 VoIP Services 的 P12 文件。
    说明:
    保存P12文件时,请务必要为其设置密码。
    
    
    

    步骤2:上传证书到 Chat 控制台

    打开 Chat 控制台,选择您创建的 Chat 应用,并按照如下步骤上传证书:
    1. 选择您的 Chat 应用,进入应用的基础配置页面,在 Offline Push Certificate Configuration 选项卡中,点击 Go now。
    
    2. Manufacturer configuration 中,切换到 iOS,单击 Add Certificate,然后在悬浮页面中选择证书类型,上传 iOS 证书(p.12),设置证书密码,单击 Confirm
    
    说明:
    VoIP Push 证书本身不区分生产环境和测试环境,生产环境和开发环境使用的是同一份 VoIP Push 证书。
    上传证书名最好使用全英文(尤其不能使用括号等特殊字符)。
    上传证书需要设置密码,无密码收不到推送。
    发布 App Store 的证书需要设置为生产环境,否则无法收到推送。
    上传的 p12 证书必须是自己申请的真实有效的证书。
    3. 上传完成后,记录不同环境下的证书 ID。
    
    说明:
    开发环境和生产环境下的证书 ID 要严格区分,并在 步骤4:接入TUICallKitVoIPExtension 组件 时根据实际环境填写。

    步骤3:完成工程配置

    1. 如下图,确认您工程的 Capability 中是否添加 Push Notification 能力。
    
    2. 如下图,请检查您工程 Capability 的 Backgrounds Modes 中,是否开启了 Voice over IP 选项。
    

    步骤4:接入 TUICallKitVoIPExtension 组件

    使用 CocoaPods 导入组件,具体步骤如下:
    1. 在您的 Podfile 文件中添加以下依赖。
    pod 'TUIVoIPExtension'
    注意:
    请在您的Podfile文件中确保为TUICallKit_SwiftTUICallKitVoIPExtension组件指定相同的Subspec
    2. 执行以下命令,安装组件。
    pod install
    Swift
    Objective-C
    import TUIVoIPExtension
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // 上报证书 ID
    TUIVoIPExtension.setCertificateID(1234)
    return true
    }
    #import <TUIVoIPExtension/TUIVoIPExtension.h>
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 上报证书 ID
    [TUIVoIPExtension setCertificateID:1234];
    return YES;
    }
    说明:
    如果无法安装 TUICallKit 最新版本,执行以下命令更新本地的 CocoaPods 仓库列表。
    pod repo update

    拨打 VoIP 通话

    如果您需要拨打 VoIP 通话,需要在调用 call 的时候设置 OfflinePushInfo 中的 iOSPushType 字段为TUICallIOSOfflinePushTypeVoIP,默认为 TUICallIOSOfflinePushTypeAPNs
    Swift
    Java
    Dart
    Objective-C
    import TUICallKit_Swift
    import TUICallEngine
    
    let pushInfo: TUIOfflinePushInfo = TUIOfflinePushInfo()
    pushInfo.title = ""
    pushInfo.desc = "您有一个新的通话"
    pushInfo.iOSPushType = .voip
    pushInfo.ignoreIOSBadge = false
    pushInfo.iOSSound = "phone_ringing.mp3"
    pushInfo.androidSound = "phone_ringing"
    // OPPO必须设置ChannelID才可以收到推送消息,这个channelID需要和控制台一致
    // OPPO must set a ChannelID to receive push messages. This channelID needs to be the same as the console.
    pushInfo.androidOPPOChannelID = "tuikit"
    // FCM channel ID, you need change PrivateConstants.java and set "fcmPushChannelId"
    pushInfo.androidFCMChannelID = "fcm_push_channel"
    // VIVO message type: 0-push message, 1-System message(have a higher delivery rate)
    pushInfo.androidVIVOClassification = 1
    // HuaWei message type: https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/message-classification-0000001149358835
    pushInfo.androidHuaWeiCategory = "IM"
    
    let params = TUICallParams()
    params.userData = "User Data"
    params.timeout = 30
    params.offlinePushInfo = pushInfo
    
    TUICallKit.createInstance().call(userId: "123456", callMediaType: .audio, params: params) {
    
    } fail: { code, message in
    
    }
    TUICallDefine.OfflinePushInfo offlinePushInfo = new TUICallDefine.OfflinePushInfo();
    offlinePushInfo.setTitle("");
    offlinePushInfo.setDesc("You have receive a new call");
    // OPPO必须设置ChannelID才可以收到推送消息,这个channelID需要和控制台一致
    // OPPO must set a ChannelID to receive push messages. This channelID needs to be the same as the console.
    offlinePushInfo.setAndroidOPPOChannelID("tuikit");
    offlinePushInfo.setIgnoreIOSBadge(false);
    offlinePushInfo.setIOSSound("phone_ringing.mp3");
    offlinePushInfo.setAndroidSound("phone_ringing"); //Note:don't add suffix
    //VIVO message type: 0-push message, 1-System message(have a higher delivery rate)
    offlinePushInfo.setAndroidVIVOClassification(1);
    //FCM channel ID, you need change PrivateConstants.java and set "fcmPushChannelId"
    offlinePushInfo.setAndroidFCMChannelID("fcm_push_channel");
    //Huawei message type
    offlinePushInfo.setAndroidHuaWeiCategory("IM");
    //IOS push type: if you want user VoIP, please modify type to TUICallDefine.IOSOfflinePushType.VoIP
    offlinePushInfo.setIOSPushType(TUICallDefine.IOSOfflinePushType.VoIP);
    
    TUICallDefine.CallParams params = new TUICallDefine.CallParams();
    params.offlinePushInfo = offlinePushInfo;
    
    TUICallKit.createInstance(context).call("mike", TUICallDefine.MediaType.Video, params, null);
    TUIOfflinePushInfo offlinePushInfo = TUIOfflinePushInfo();
    offlinePushInfo.title = "Flutter TUICallKit";
    offlinePushInfo.desc = "This is an incoming call from Flutter TUICallkit";
    offlinePushInfo.ignoreIOSBadge = false;
    offlinePushInfo.iOSSound = "phone_ringing.mp3";
    offlinePushInfo.androidSound = "phone_ringing";
    offlinePushInfo.androidOPPOChannelID = "Flutter TUICallKit";
    offlinePushInfo.androidVIVOClassification = 1;
    offlinePushInfo.androidFCMChannelID = "fcm_push_channel";
    offlinePushInfo.androidHuaWeiCategory = "Flutter TUICallKit";
    offlinePushInfo.iOSPushType = TUICallIOSOfflinePushType.VoIP;
    
    TUICallParams params = TUICallParams(offlinePushInfo: offlinePushInfo);
    TUICallKit.instance.call(callUserId, TUICallMediaType.audio, params);
    #import <TUICallKit_Swift/TUICallKit_Swift-Swift.h>
    #import <TUICallEngine/TUICallEngine.h>
    
    - (TUICallParams *)getCallParams {
    TUIOfflinePushInfo *offlinePushInfo = [self createOfflinePushInfo];
    TUICallParams *callParams = [TUICallParams new];
    callParams.offlinePushInfo = offlinePushInfo;
    callParams.timeout = 30;
    return callParams;
    }
    
    - (TUIOfflinePushInfo *)createOfflinePushInfo {
    TUIOfflinePushInfo *pushInfo = [TUIOfflinePushInfo new];
    pushInfo.title = @"";
    pushInfo.desc = @"您有一个新的通话";
    pushInfo.iOSPushType = TUICallIOSOfflinePushTypeVoIP;
    pushInfo.ignoreIOSBadge = NO;
    pushInfo.iOSSound = @"phone_ringing.mp3";
    pushInfo.AndroidSound = @"phone_ringing";
    // OPPO必须设置ChannelID才可以收到推送消息,这个channelID需要和控制台一致
    // OPPO must set a ChannelID to receive push messages. This channelID needs to be the same as the console.
    pushInfo.AndroidOPPOChannelID = @"tuikit";
    // FCM channel ID, you need change PrivateConstants.java and set "fcmPushChannelId"
    pushInfo.AndroidFCMChannelID = @"fcm_push_channel";
    // VIVO message type: 0-push message, 1-System message(have a higher delivery rate)
    pushInfo.AndroidVIVOClassification = 1;
    // HuaWei message type: https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/message-classification-0000001149358835
    pushInfo.AndroidHuaWeiCategory = @"IM";
    return pushInfo;
    }
    
    [[TUICallKit createInstance] callWithUserId:@"123456"
    callMediaType:TUICallMediaTypeAudio
    params:[self getCallParams] succ:^{
    
    } fail:^(int code, NSString * _Nullable errMsg) {
    
    }];

    通过系统通话记录拨打通话

    如果需要实现点击系统电话 > 最近通话列表中的通话记录,直接发起单人音视频通话,您需要在 Application 的生命周期回调函数使用 TUICallKitVoIPExtension 组件中的 callWith 接口,具体示例如下:
    说明:
    仅支持单人音视频通话的直接拨打。
    登录账户必须为同一个账户。
    1. 在iOS 13(及以后版本)上,使用了 SceneDelegate,且最低兼容版本到iOS 13以下,需分别在 AppDelegateSceneDelegate 中实现如下方法。
    Swift
    Objective-C
    import TUIVoIPExtension
    
    /// AppDelegate 中的实现,iOS 13 以前版本的处理
    func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([any UIUserActivityRestoring]?) -> Void) -> Bool {
    TUIVoIPExtension.call(with: userActivity)
    return true
    }
    
    /// SceneDelegate 中的实现
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    for userActivity in connectionOptions.userActivities {
    TUIVoIPExtension.call(with: userActivity);
    }
    }
    
    func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
    TUIVoIPExtension.call(with: userActivity);
    }
    #import <TUIVoIPExtension/TUIVoIPExtension.h>
    
    /// AppDelegate 中的实现,iOS 13 以前版本的处理
    - (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
    [TUIVoIPExtension callWith:userActivity];
    return YES;
    }
    
    /// SceneDelegate 中的实现
    - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)sessionptions:(UISceneConnectionOptions *)connectionOptions {
    [connectionOptions.userActivities enumerateObjectsUsingBlock:^(NSUserActivity * _Nonnull userActivity, BOOL * _Nonnull stop) {
    [TUIVoIPExtension callWith:userActivity];
    }];
    }
    
    - (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity {
    [TUIVoIPExtension callWith:userActivity];
    }
    2. 在iOS 13(及以后版本)上,未使用 SceneDelegate,只需要在 AppDelegate 实现如下方法。
    Swift
    Objective-C
    import TUIVoIPExtension
    
    func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([any UIUserActivityRestoring]?) -> Void) -> Bool {
    TUIVoIPExtension.call(with: userActivity)
    return true
    }
    #import <TUIVoIPExtension/TUIVoIPExtension.h>
    
    - (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
    [TUIVoIPExtension callWith:userActivity];
    return YES;
    }

    常见问题

    获取不到 VoIP Push ?

    1. 首先检查下 App 的运行环境和证书的环境是否一致,证书 ID 是否匹配,如果不一致,无法收到推送。
    2. 请确认当前您登录的账号是否处于离线状态:按 home 键切后台、登录后主动杀进程退出。VoIP Push 目前只支持离线状态下的推送。
    3. 检查 步骤3:完成工程配置 是否正确。
    4. 尝试重启测试手机来清除系统缓存和内存(非常重要)。
    联系我们

    联系我们,为您的业务提供专属服务。

    技术支持

    如果你想寻求进一步的帮助,通过工单与我们进行联络。我们提供7x24的工单服务。

    7x24 电话支持