tencent cloud

实时音视频

动态与公告
产品动态
产品近期公告
关于 TRTC Live 正式上线的公告
关于TRTC Conference 正式版上线的公告
Conference 商业化版本即将推出
关于多人音视频 Conference 开启内测公告
关于音视频通话 Call 正式版上线的公告
关于腾讯云音视频终端 SDK 播放升级及新增授权校验的公告
关于 TRTC 应用订阅套餐服务上线的相关说明
产品简介
产品概述
基本概念
产品功能
产品优势
应用场景
性能数据
购买指南
计费概述
免费时长说明
月订阅
现收现付
TRTC 逾期与暂停政策
常见问题解答
退款说明
新手指引
Demo 体验
视频通话 SDK
组件介绍
开通服务
跑通 Demo
快速接入
离线唤醒
会话聊天
云端录制
AI 降噪
界面定制
Chat 集成通话能力
更多特性
无 UI 集成
服务端 API
客户端 API
解决方案
错误码表
发布日志
常见问题
视频会议 SDK
组件介绍(TUIRoomKit)
开通服务(TUIRoomKit)
跑通 Demo(TUIRoomKit)
快速接入(TUIRoomKit)
屏幕共享(TUIRoomKit)
预定会议(TUIRoomKit)
会中呼叫(TUIRoomKit)
界面定制(TUIRoomKit)
虚拟背景(TUIRoomKit)
会议控制(TUIRoomKit)
云端录制(TUIRoomKit)
AI 降噪(TUIRoomKit)
会中聊天(TUIRoomKit)
机器人推流(TUIRoomKit)
更多特性(TUIRoomKit)
客户端 API(TUIRoomKit)
服务端 API(TUIRoomKit)
常见问题(TUIRoomKit)
错误码 (TUIRoomKit)
SDK更新日志(TUIRoomKit)
直播与语聊 SDK
Live 视频直播计费说明
组件介绍
开通服务(TUILiveKit)
跑通 Demo
无 UI 集成
UI 自定义
直播监播
视频直播
语聊房
高级功能
客户端 API
服务端 API
错误码
发布日志
常见问题
RTC Engine
开通服务
SDK 下载
API-Example
接入指引
API-参考手册
高级功能
AI 集成
概述
MCP 配置
Skills 配置
集成指南
常见问题
RTC RESTFUL API
History
Introduction
API Category
Room Management APIs
Stream mixing and relay APIs
On-cloud recording APIs
Data Monitoring APIs
Pull stream Relay Related interface
Web Record APIs
AI Service APIs
Cloud Slicing APIs
Cloud Moderation APIs
Making API Requests
Call Quality Monitoring APIs
Usage Statistics APIs
Data Types
Appendix
Error Codes
控制台指南
应用管理
套餐包管理
用量统计
监控仪表盘
开发辅助
解决方案
实时合唱
常见问题
迁移指南
计费相关
功能相关
UserSig 相关
应对防火墙限制相关
缩减安装包体积相关
Andriod 与 iOS 相关
Web 端相关
Flutter 相关
Electron 相关
TRTCCalling Web 相关
音视频质量相关
其他问题
旧版文档
RTC RoomEngine SDK(旧)
集成 TUIRoom (Web)
集成 TUIRoom (Android)
集成 TUIRoom (iOS)
集成 TUIRoom (Flutter)
集成 TUIRoom (Electron)
TUIRoom API 查询
实现云端录制与回放(旧)
监控仪表盘计费(旧)
协议与策略
安全合规认证
安全白皮书
信息安全说明
服务等级协议
苹果隐私策略:PrivacyInfo.xcprivacy
TRTC 政策
隐私协议
数据处理和安全协议
词汇表

接入离线推送

PDF
聚焦模式
字号
最后更新时间: 2026-03-05 17:29:11
本文档将指导您如何基于 TIMPush 服务实现 VoIP 推送功能,适用于使用 AtomicXCore 进行无 UI 集成的场景。
注意:
使用 VoIP 推送功能首先需要 开通 TIMPush 服务。
LiveCommunicationKit 需要在 iOS 17.4 及以上系统中使用。
VoIP Push 无法复用 APNs 普通推送证书,需要单独在苹果开发者网站上 申请 VoIP Push 证书

集成效果

按照本文档接入 Apple LiveCommunicationKit 后,您的 App 将瞬间拥有微信同款的原生通话能力,在进程关闭或锁屏状态下,也能无差别唤醒系统级全屏接听界面:
接听前效果
接听后效果





准备条件

开通服务

进入 Chat > 接入设置,单击立即购买免费试用(每个应用可免费试用一次,有效期7天)。

注意:
推送插件试用或购买到期后,将自动停止提供推送服务(包括普通消息离线推送、全员/标签推送等服务)。为避免影响您业务的正常使用,请提前 购买/续费

厂商配置

步骤1:申请 VoIP Push 证书

在申请 VoIP Push 证书之前,请先登录 苹果开发者中心 网站开启 App 的远程推送功能。当您的 AppID 具备了 Push Notification 能力后,按照如下步骤申请并配置 VoIP Push 证书:
1. 登录 苹果开发者中心 网站,单击 Certificates, IDs & Profiles 选项卡,进入 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 应用,进入应用的接入设置。

2. 接入设置中,切换到 iOS, 点击添加证书按钮,然后在悬浮页面中选择证书类型,上传 iOS 证书(p12),设置证书密码,单击确认

说明:
添加证书时,推送类型默认为 APNs,不影响 VoIP 证书的上传和使用。
VoIP Push 证书本身不区分生产环境和测试环境,生产环境和开发环境使用的是同一份 VoIP Push 证书,请分别上传。
上传证书名最好使用全英文(尤其不能使用括号等特殊字符)。
上传证书需要设置密码,无密码收不到推送。
发布 App Store 的证书需要设置为生产环境,否则无法收到推送。
上传的 p12 证书必须是自己申请的真实有效的证书。
3. 上传完成后,记录不同环境下的证书 ID。

说明:
开发环境和生产环境下的证书 ID 要严格区分,请根据实际环境填写。

功能接入

步骤1:完成工程配置

1. 如下图,请在您工程的 Capability 中添加 Push Notification 能力。



2. 如下图,请您在工程 Capability 的 Background Modes 中,开启 Voice over IP 选项。




步骤2: 添加依赖

1. 添加 Pod 依赖:在您项目的 Podfile 文件中添加 pod 'TUICore' 依赖。
pod 'TUICore'
2. 安装组件:在终端进入到 Podfile 文件所在的目录,然后执行以下命令安装组件。
pod install --repo-update

步骤3:初始化 PushKit 并设置证书 ID

1. 创建一个类来管理 VoIP 推送,初始化 PushKit 用于接收 VoIP 推送通知。
import PushKit
import ImSDK_Plus
import LiveCommunicationKit

class VoIPPushManager: NSObject {
private let pushRegistry: PKPushRegistry
private var certificateID: Int = 0
private var voipToken: Data? // 保存 Token,等待 TUILogin 成功后上报
// 存储当前通话的 UUID
private var currentCallUUID: UUID?
// ConversationManager 用于展示系统来电界面(步骤 7)
private lazy var conversationManager: ConversationManager = {
let configuration = ConversationManager.Configuration(
ringtoneName: "phone_ringing.mp3", // 来电铃声文件名
iconTemplateImageData: nil, // 来电图标(可选)
supportsVideo: true // 是否支持视频通话
)
let manager = ConversationManager(configuration: configuration)
manager.delegate = self
return manager
}()
override init() {
pushRegistry = PKPushRegistry(queue: DispatchQueue.main)
super.init()
pushRegistry.delegate = self
pushRegistry.desiredPushTypes = [.voIP]
// 监听 TUILogin 成功的通知
NotificationCenter.default.addObserver(
self,
selector: #selector(onTUILoginSuccess),
name: NSNotification.Name("TUILoginSuccess"),
object: nil
)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
// 设置证书 ID
func setCertificateID(_ certificateID: Int) {
self.certificateID = certificateID
}
// TUILogin 成功后上报 Token
@objc private func onTUILoginSuccess() {
// 收到 TUILogin 成功通知,开始上报 VoIP Token
uploadVoIPToken()
}
// 上报 VoIP Token 到 Chat 后台
private func uploadVoIPToken() {
guard let token = voipToken else {
// VoIP Token 尚未获取
return
}
guard certificateID != 0 else {
// 证书 ID 未设置
return
}
let config = V2TIMVOIPConfig()
config.certificateID = certificateID
config.token = token
V2TIMManager.sharedInstance().setVOIP(config: config, succ: {
// VoIP Token 上报成功
}, fail: { code, desc in
// VoIP Token 上报失败
})
}
}

2. AppDelegate 中初始化并设置证书 ID
class AppDelegate: UIResponder, UIApplicationDelegate {
private lazy var voipPushManager: VoIPPushManager = {
let manager = VoIPPushManager()
manager.setCertificateID(1234) // 替换为您在 Chat 控制台获取的证书 ID
return manager
}()
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 触发 voipPushManager 的初始化
_ = voipPushManager
return true
}
}

注意:
certificateID 是您在 Chat 控制台上传证书 后获取的证书 ID。
开发环境和生产环境的证书 ID 要严格区分,请根据实际环境填写。

步骤4:获取并保存 VoIP Token

实现 PKPushRegistryDelegate 代理方法,在获取到 VoIP Token 后先保存,等待 TUILogin 成功后再上报。
import PushKit
import ImSDK_Plus

extension VoIPPushManager: PKPushRegistryDelegate {
// 获取到 VoIP Token 后保存(不立即上报)
func pushRegistry(_ registry: PKPushRegistry,
didUpdate pushCredentials: PKPushCredentials,
for type: PKPushType) {
guard type == .voIP else { return }
// 保存 token
voipToken = pushCredentials.token
// 将 token 转换为字符串(用于日志)
let tokenString = pushCredentials.token.map { String(format: "%02.2hhx", $0) }.joined()
// VoIP Token 已获取:
// 如果 TUILogin 已经完成,立即上报;否则等待 TUILoginSuccess 通知
uploadVoIPToken()
}
// Token 失效
func pushRegistry(_ registry: PKPushRegistry,
didInvalidatePushTokenFor type: PKPushType) {
// VoIP Token 已失效
}
}
注意:
VoIP Token 的上报必须在 Chat SDK 登录成功后才能进行,因此不能在获取 Token 时立即上报。

步骤5:Token 上报

在用户登录时,需要先登录 Chat SDK,再登录 TUICore。TUICore 登录成功后会发送 TUILoginSuccess 通知,VoIPPushManager 监听到该通知后会自动上报 VoIP Token。
import TUICore
import AtomicXCore

// 步骤1:登录 Chat SDK(AtomicXCore 的 LoginStore)
LoginStore.shared.login(
sdkAppID: sdkAppID,
userID: userID,
userSig: userSig
) { result in
switch result {
case .success:
// Chat SDK 登录成功
// 步骤2:登录 TUICore
TUILogin.login(
sdkAppID,
userID: userID,
userSig: userSig
) {
// TUICore 登录成功
// 发送通知,触发 VoIP Token 上报
NotificationCenter.default.post(
name: NSNotification.Name("TUILoginSuccess"),
object: nil
)
} fail: { code, message in
// TUICore 登录失败
}
case .failure(let error):
// Chat SDK 登录失败
}
}

步骤6:接收 VoIP 推送通知

extension VoIPPushManager: PKPushRegistryDelegate {
// 收到 VoIP 推送
func pushRegistry(_ registry: PKPushRegistry,
didReceiveIncomingPushWith payload: PKPushPayload,
for type: PKPushType) {
guard type == .voIP else { return }
// 必须在 5 秒内向系统报告来电,否则会 crash
showIncomingCall(with: payload) // 步骤 7
}
}

步骤7:展示来电通知

使用 LiveCommunicationKit 向系统报告来电,系统自动展示原生来电界面
import LiveCommunicationKit

extension VoIPPushManager {
// 向系统报告来电
private func showIncomingCall(with payload: PKPushPayload) {
// 解析推送数据
let payloadDict = payload.dictionaryPayload
// 1. 获取来电者名称(必需字段)
guard let callerName = payloadDict["voip_caller_name"] as? String else {
// 缺少 voip_caller_name 字段
return
}
// 2. 解析 ext 字段获取通话类型(音频/视频)
var isVideoCall = false
if let extString = payloadDict["ext"] as? String,
let extData = extString.data(using: .utf8),
let extDic = try? JSONSerialization.jsonObject(with: extData) as? [String: Any],
let voipExtDic = extDic["voip_ext"] as? [String: String],
let mediaType = voipExtDic["voip_media_type"] {
isVideoCall = (mediaType == "video")
}
// 创建来电通知内容
let uuid = UUID()
currentCallUUID = uuid // 保存 UUID,用于后续操作
var update = Conversation.Update(
members: [Handle(type: .generic, value: callerName, displayName: callerName)]
)
update.capabilities = isVideoCall ? .video : .playingTones
// 向系统报告来电(系统自动展示原生来电界面)
Task {
do {
try await conversationManager.reportNewIncomingConversation(uuid: uuid, update: update)
// 报告成功
} catch {
// 报告失败
}
}
}
}

// MARK: - ConversationManagerDelegate
extension VoIPPushManager: ConversationManagerDelegate {
func conversationManager(_ manager: ConversationManager, perform action: ConversationAction) {
if action is JoinConversationAction {
// 用户点击"接听",调用 CallStore 接听通话
CallStore.shared.accept { result in
switch result {
case .success:
// 接听成功,可以在这里跳转到通话页面
case .failure(let error):
}
}
} else if action is EndConversationAction {
// 用户点击"挂断",调用 CallStore 挂断通话
CallStore.shared.hangup { result in
switch result {
case .success:
case .failure(let error):
}
}
}
// 必须调用 fulfill() 通知系统操作已完成
action.fulfill()
}
}
您可以通过配置 Conversation.Update 的以下参数,自定义来电界面显示的来电者信息、通话类型等内容:
参数
类型
是否必需
说明
members
[Handle]
必需
来电者信息数组,支持多人通话场景。
每个 Handle 包含:
type:通常使用 .generic
value:来电者唯一标识(建议使用用户 ID)
displayName:显示在来电界面的名称
capabilities
Conversation.Capabilities
必需
通话类型:
.video:视频通话(显示视频图标)
.playingTones:语音通话(显示语音图标)
说明:
用户点击"接听"或"挂断"后,系统会回调 ConversationManagerDelegate 的方法,您需要在回调中处理接听/挂断的业务逻辑(如跳转到通话页面、调用 CallStore API 等)

发起 VoIP 通话

发起通话

AtomicXCoreCallStore 已经默认使用 VoIP 推送,您不需要手动设置 offlinePushInfo 参数。CallStore 内部会自动配置以下推送信息:
推送类型:.voIP
推送标题:当前用户 ID
推送描述:"You have a new call"
iOS 铃声:phone_ringing.mp3
Swift
import AtomicXCore

// 构造通话参数(不需要设置 offlinePushInfo)
var params = CallParams()
params.timeout = 30 // 超时时间(秒)
params.userData = "自定义数据" // 扩展信息(可选)

// 发起通话
let userIdList = ["被叫用户的 userID"]
let mediaType = CallMediaType.video // .video 视频通话,.audio 语音通话

CallStore.shared.calls(
participantIds: userIdList,
callMediaType: mediaType,
params: params
) { result in
switch result {
case .success:
// 通话发起成功
// 此时可以跳转到您自己的通话页面
case .failure(let error):
// 通话失败处理
}
}
说明:
VoIP 推送降级策略
当使用 VoIP 推送时,后台会智能判断证书类型,保证用户仍然能收到推送通知:
上传的是 VoIP 证书:发送 VoIP Push。
上传的是 APNs 证书:自动降级为 APNs 推送。

接听通话

当被叫用户离线时收到 VoIP 推送并点击接听,系统会唤醒您的 App。此时需要监听通话事件并跳转到您自己实现的通话页面。
import AtomicXCore
import Combine

class YourViewController: UIViewController {
private var cancellables = Set<AnyCancellable>()
override func viewDidLoad() {
super.viewDidLoad()
// 监听来电事件
CallStore.shared.callEventPublisher
.receive(on: DispatchQueue.main)
.sink { [weak self] event in
guard let self = self else { return }
switch event {
case .onCallReceived(let callId, let mediaType, let userData):
// 收到来电,跳转到您自己的通话页面
self.showCallViewController(callId: callId, mediaType: mediaType, userData: userData)
case .onCallEnded(let callId, let mediaType, let reason, let userId):
// 通话结束,返回或更新 UI
self.dismissCallViewController()
case .onCallStarted(let callId, let mediaType):
// 通话已开始
break
}
}
.store(in: &cancellables)
}
private func showCallViewController(callId: String, mediaType: CallMediaType, userData: String) {
// 跳转到您自己实现的通话页面
let callVC = YourCallViewController()
callVC.callId = callId
callVC.mediaType = mediaType
callVC.userData = userData
callVC.modalPresentationStyle = .fullScreen
present(callVC, animated: true)
}
private func dismissCallViewController() {
// 关闭通话页面
dismiss(animated: true)
}
}

常见问题

获取不到 VoIP Push,如何处理?

1. 检查登录顺序:必须先登录 Chat SDK,再登录 TUICore,否则 VoIP Token 无法上报。参考 步骤 5
2. 首先检查下 App 的运行环境和证书的环境是否一致,证书 ID 是否匹配,如果不一致,无法收到推送。
3. 请确认当前您登录的账号是否处于离线状态:按 home 键切后台、登录后主动杀进程退出。VoIP Push 目前只支持离线状态下的推送。
4. 检查 完成工程配置 是否正确。
5. 尝试重启测试手机来清除系统缓存和内存(很重要)。
6. Chat 控制台提供推送排查工具,帮助您快速排查推送问题,使用方式详见:Push 排查工具。(很重要)

应用在收到 VoIP 推送后 crash 怎么办?

这通常是因为没有在 5 秒内向系统发送展示通知的请求。请确保在 didReceiveIncomingPushWith 回调中立即调用 reportNewIncomingConversation 方法。

如何自定义来电通知的内容?

您可以通过 Conversation.Update 来自定义来电通知的内容,包括:
来电者信息(displayName
通话类型(capabilities:.video.playingTones
其他自定义信息
具体用法请参考 Apple LiveCommunicationKit 官方文档。

交流与反馈

如果您在使用过程中,有什么建议或者意见,可以 联系我们,感谢您的反馈。

帮助和支持

本页内容是否解决了您的问题?

填写满意度调查问卷,共创更好文档体验。

文档反馈