本文将介绍如何在 iOS 工程中集成 TIMPush。
前提条件
资源 | 获取位置 | 用途 |
SDKAppID | 腾讯云控制台 > 即时通信 IM > 推送服务 Push > 概览 | 调用 registerPush。创建 Push 应用后,腾讯云控制台会自动创建相同 SDKAppID 的 Chat 应用。 |
Push Key | 腾讯云控制台 > 即时通信 IM > 推送服务 Push > 概览 > 客户端密钥 | 独立 Push 场景下,作为 registerPush 的 appKey 参数。 |
Chat Key | 腾讯云控制台 > 即时通信 IM > 消息服务 Chat > 概览 > 密钥 | Chat 登录使用。不要把 Chat Key 当作 registerPush 的 appKey 传入。 |
证书 ID | 腾讯云控制台上传 APNs 证书后生成 | 证书 ID 即 businessID,在 AppDelegate 中返回给 TIMPush。 |
App Group ID | Apple Developer Center / Xcode Capabilities | 仅在需要推送触达统计时使用。 |
Push 服务开通状态 | 腾讯云控制台 > 即时通信 IM > 推送服务 Push > 概览 | 创建 Push 应用不等于已开通 Push 服务,请确认 Push 服务已开通。 |
TIMPush iOS VERSION | VERSION 是 Podfile 中 TIMPush 依赖的版本号占位符,例如 8.9.7537、8.8.7357、8.7.7201 等,请以实际接入版本为准。 |
本文示例中的
VERSION、SDKAppID、AppKey、businessID、App Group ID 均为占位符,请勿在代码仓库中提交真实密钥。集成 TIMPush
请按顺序完成本文配置。
主 App target 集成
TIMPush 通过 CocoaPods 集成。请在
Podfile 中为主 App target 添加 TIMPush 依赖。Podfile 示例:target 'YourAppName' douse_frameworks!use_modular_headers!pod 'TIMPush', 'VERSION'end
如果您的工程已显式依赖 IMSDK,请保持
TIMPush 与 TXIMSDK_Plus_iOS_XCFramework 版本一致,否则执行 pod install 时可能出现依赖冲突:target 'YourAppName' douse_frameworks!use_modular_headers!pod 'TXIMSDK_Plus_iOS_XCFramework', 'VERSION'pod 'TIMPush', 'VERSION'end
保存
Podfile 后,在工程目录执行:pod install
如果无法安装 TIMPush 最新版本,可先执行
pod repo update 更新本地 CocoaPods 仓库列表后再 pod install。仓库更新可能耗时较长且影响依赖解析结果,建议在确认版本后执行。注意:
无论 Swift 还是 Objective-C 项目,都请集成 TXIMSDK_Plus_iOS_XCFramework。
验证:
pod install 输出 Installing TIMPush (VERSION),工程内可以 import TIMPush / #import <TIMPush/TIMPushManager.h> 且编译通过。配置推送参数
配置 businessID
businessID 是腾讯云控制台上传 APNs 证书后生成的证书 ID。TIMPush 通过该 ID 识别当前 App 使用控制台中的哪一份 iOS 推送证书。// 在 AppDelegate.swift 中添加import TIMPush// 注意:Swift 端需要添加 @objc 标注@objc func businessID() -> Int32 {// TODO: Replace <#YOUR_BUSINESS_ID#> with the certificate ID generated in the Tencent Cloud console.return <#YOUR_BUSINESS_ID#>}
// 在 AppDelegate.m 中添加#import <TIMPush/TIMPushManager.h>- (int)businessID {// TODO: Replace <#YOUR_BUSINESS_ID#> with the certificate ID generated in the Tencent Cloud console.return <#YOUR_BUSINESS_ID#>;}
验证:在
businessID 方法内打 log,启动 App 后观察该方法是否被调用,且返回值与腾讯云控制台显示的证书 ID 一致。配置 applicationGroupID(可选)
如果您需要统计推送触达率,需要配置 App Group ID 并实现 applicationGroupID() 方法 ,该 ID 应与您在厂商配置阶段准备的 App Group ID 保持一致。如果不需要推送触达统计,可以跳过本节。
// 在 AppDelegate.swift 中添加import TIMPush@objc func applicationGroupID() -> String {// TODO: Replace <#YOUR_APP_GROUP_ID#> with the App Group ID configured in Apple Developer Center / Xcode.return "group.<#YOUR_APP_GROUP_ID#>"}
// 在 AppDelegate.m 中添加#import <TIMPush/TIMPushManager.h>- (NSString *)applicationGroupID {// TODO: Replace <#YOUR_APP_GROUP_ID#> with the App Group ID configured in Apple Developer Center / Xcode.return @"group.<#YOUR_APP_GROUP_ID#>";}
验证:在 Apple Developer Center 和 Xcode 中确认主 App 与 Notification Service Extension 已绑定到同一个 App Group ID,且 AppDelegate 返回的
group.<#YOUR_APP_GROUP_ID#> 与之一致。注册推送
registerPush
registerPush 用于注册当前设备的推送 token。注册成功后,后台才能根据
registrationID 或 userID 向该设备下发离线推送。其中 appKey 的取值会影响注册方式:appKey = Push Key:注册 TIMPush 独立推送能力。Push Key 为腾讯云控制台 > 即时通信 IM > 推送服务 Push > 概览中的客户端密钥。appKey = nil:复用 IM 登录态注册推送,必须在 IM login 成功后调用。请先根据业务场景确认调用顺序:
场景 | 调用顺序 | 后台可用推送标识 | 说明 |
仅使用 TIMPush | App 每次冷启动后调用 registerPush(appKey = Push Key) | registrationID | 适用于营销 / 活动 / 通知推送,不接入 IM SDK。 |
IM SDK + TIMPush 先注册 Push 再登录 | registerPush(appKey = Push Key) → IM login | 登录前: registrationID;登录后: registrationID + userID | 适用于希望用户未登录时也能收到营销推送的场景。 |
IM SDK + TIMPush 先登录再注册 Push | IM login → registerPush(appKey = null) | 登录后: userID注册后: userID + registrationID,此时 registrationID = userID | 适用于希望用户登录后能收到 Chat 离线消息和营销推送的场景。 |
注意:
如果用户退出 IM SDK,同时集成了 IM SDK + TIMPush 的场景下已建立的
userID 与 registrationID 推送关系都会失效,需要重新完成对应注册。Chat 应用的密钥仅用于 IM 登录,不能作为
registerPush 的 appKey。App 冷启动、用户同意隐私政策后调用
registerPush(appKey = Push Key)。import TIMPushfunc registerTIMPush() {// TODO: Replace 0 with your SDKAppID.let sdkAppID: Int32 = 0// TODO: Replace "<#YOUR_PUSH_KEY#>" with your Push Key.let appKey = "<#YOUR_PUSH_KEY#>"TIMPushManager.registerPush(sdkAppID, appKey: appKey, succ: { deviceToken inprint(">>>>> TIMPush register success")}, fail: { code, desc inprint(">>>>> TIMPush register failed, code:\\(code), desc:\\(desc)")})}
#import <TIMPush/TIMPushManager.h>- (void)registerTIMPush {// TODO: Replace 0 with your SDKAppID.int sdkAppID = 0;// TODO: Replace @"<#YOUR_PUSH_KEY#>" with your Push Key.NSString *appKey = @"<#YOUR_PUSH_KEY#>";[TIMPushManager registerPush:sdkAppIDappKey:appKeysucc:^(NSData * _Nonnull deviceToken) {NSLog(@">>>>> TIMPush register success");} fail:^(int code, NSString * _Nonnull desc) {NSLog(@">>>>> TIMPush register failed, code:%d, desc:%@", code, desc);}];}
请在 IM
login 成功回调中调用 registerPush(appKey = nil)。import TIMPushimport ImSDK_Plusfunc loginIMAndRegisterPush() {// TODO: Replace 0 with your SDKAppID.let sdkAppID: Int32 = 0let userID = "<#YOUR_USER_ID#>"let userSig = "<#YOUR_USER_SIG#>"V2TIMManager.sharedInstance().login(userID: userID, userSig: userSig) {// Swift 桥接下 appKey 类型为非可选 String,IM 登录场景传空字符串等同于 OC 接口传 nil。TIMPushManager.registerPush(sdkAppID, appKey: "", succ: { deviceToken inprint(">>>>> TIMPush register success")}, fail: { code, desc inprint(">>>>> TIMPush register failed, code:\\(code), desc:\\(desc)")})} fail: { code, msg inprint(">>>>> IM login failed, code:\\(code), msg:\\(msg ?? "")")}}
#import <TIMPush/TIMPushManager.h>#import <ImSDK_Plus/ImSDK_Plus.h>- (void)loginIMAndRegisterPush {// TODO: Replace 0 with your SDKAppID.int sdkAppID = 0;NSString *userID = @"<#YOUR_USER_ID#>";NSString *userSig = @"<#YOUR_USER_SIG#>";[[V2TIMManager sharedInstance] login:userID userSig:userSig succ:^{[TIMPushManager registerPush:sdkAppIDappKey:nilsucc:^(NSData * _Nonnull deviceToken) {NSLog(@">>>>> TIMPush register success");} fail:^(int code, NSString * _Nonnull desc) {NSLog(@">>>>> TIMPush register failed, code:%d, desc:%@", code, desc);}];} fail:^(int code, NSString *msg) {NSLog(@">>>>> IM login failed, code:%d, msg:%@", code, msg);}];}Objective-C
验证:
1.
registerPush 的 onSuccess 回调被触发。2. 登录腾讯云控制台 > 即时通信 IM > 推送服务 Push > 推送排查,按当前场景输入
registrationID 或 userID,确认 token 已上传。3. 如触发
onError,可按 错误码 查询 code 含义。自定义 registrationID(可选)
注意:
混用场景下,自定义
registrationID 必须与 IM 登录使用的 userID 完全一致,否则会产生账号互踢导致推送丢失。配置消息触达统计(可选)
仅当您需要统计推送触达率时,才需要完成本节配置;如果只需要接收普通离线推送,可跳过本节。
完整流程包含:
1. 在 Xcode 中创建并配置 Notification Service Extension target
2. 确保 APNs payload 开启
mutable-content3. 在 Extension 中调用 TIMPush 处理通知。
创建并配置 Notification Service Extension target
1. 在 Xcode 中选择 File > New > Target。
2. 选择 Notification Service Extension。
3. 输入 Extension 名称。
4. 创建完成后,确认工程中出现新的 Extension target。
5. 在 Extension target 的 Signing & Capabilities 中配置与主 App 相同的 App Groups。
6. 在
Podfile 中为 Extension target 添加 TIMPush 依赖:target 'YourNotificationServiceExtensionTarget' douse_frameworks!use_modular_headers!pod 'TIMPush', 'VERSION'end
7. 执行
pod install。注意:
Extension target 是独立 target,不能复用主 App target 的 Pod 依赖。若未在 Extension target 中添加
TIMPush,在 NotificationService 中 import TIMPush 或 #import <TIMPush/TIMPushManager.h> 会失败。开启 mutable-content
mutable-content 是 APNs payload 字段,由发送方在推送内容中设置。只有 payload 中开启 mutable-content,iOS 10 及以上系统才会在送达前调用 Notification Service Extension,触达统计才能生效。请确保通过以下任一方式开启
mutable-content:腾讯云控制台推送:在控制台推送测试或发送页面,勾选
mutable-content 相关选项。服务端 REST API:在 APNs payload 中设置
"mutable-content": 1。Chat SDK 发送:以 Chat SDK 离线推送配置文档为准。
在 Extension 中处理通知
请将
group.<#YOUR_APP_GROUP_ID#> 替换为您在 Apple Developer Center 和 Xcode 中配置的 App Group ID。主 App 和 Extension 必须使用同一个 App Group ID。以下 Swift 写法基于 OC 接口自动桥接,参数命名可能随 SDK 版本调整,请以 SDK 头文件 TIMPushManager.h 为准。// 在 NotificationService.swift 中添加import UserNotificationsimport TIMPushclass NotificationService: UNNotificationServiceExtension {var contentHandler: ((UNNotificationContent) -> Void)?var bestAttemptContent: UNMutableNotificationContent?override func didReceive(_ request: UNNotificationRequest,withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {self.contentHandler = contentHandlerself.bestAttemptContent = request.content.mutableCopy() as? UNMutableNotificationContentlet appGroupID = "group.<#YOUR_APP_GROUP_ID#>"TIMPushManager.handleNotificationServiceRequest(request: request, appGroupID: appGroupID) { [weak self] content inguard let self = self else {contentHandler(content)return}self.bestAttemptContent = content.mutableCopy() as? UNMutableNotificationContentcontentHandler(self.bestAttemptContent ?? content)}}override func serviceExtensionTimeWillExpire() {if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {contentHandler(bestAttemptContent)}}}
// 在 NotificationService.m 中添加#import "NotificationService.h"#import <TIMPush/TIMPushManager.h>@implementation NotificationService- (void)didReceiveNotificationRequest:(UNNotificationRequest *)requestwithContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {NSString *appGroupID = @"group.<#YOUR_APP_GROUP_ID#>";[TIMPushManager handleNotificationServiceRequest:requestappGroupID:appGroupIDcallback:^(UNNotificationContent *content) {contentHandler(content);}];}@end
验证:发送一条带
mutable-content 的测试推送,在 didReceive 内打断点或 log 确认 Extension 被调用;后续在腾讯云控制台触达统计页面应能看到上报数据。测试推送
完成上述集成步骤后,需要通过发送测试消息验证整体链路是否打通。发送消息前请确认:
1. App 已获得系统通知权限;
2. Xcode 主 App target 已开启 Push Notifications,AppDelegate 已正确返回
businessID;3. App 已置于后台或杀掉进程(前台时离线推送可能不触发)。
发送测试消息可以采用下面几种方法:
仅集成 TIMPush 的用户,建议优先使用腾讯云控制台接入测试能力验证离线推送。
操作路径:腾讯云控制台 > 即时通信 IM > 推送服务 Push > 接入测试。在接入测试页面,可以指定
registrationID 或 userID 发送离线推送测试。如果您的项目已接入 IM SDK,可在调用 sendMessage 发送消息时,通过
V2TIMOfflinePushInfo 设置离线推送参数,再交由 V2TIMManager 发送消息。具体方法签名以您接入的 IMSDK 版本头文件为准。import ImSDK_Pluslet pushInfo = V2TIMOfflinePushInfo()pushInfo.title = "推送标题"pushInfo.desc = "推送内容"pushInfo.ext = "{\\"action\\":\\"open_chat\\",\\"conversationID\\":\\"c2c_userA\\"}"let message = V2TIMManager.sharedInstance().createTextMessage("Hello TIMPush")V2TIMManager.sharedInstance().sendMessage(message: message,receiver: "<#TARGET_USER_ID#>",groupID: nil,priority: V2TIM_PRIORITY_DEFAULT,onlineUserOnly: false,offlinePushInfo: pushInfo,progress: nil,succ: { msg inprint(">>>>> sendMessage success, msgID = \\(msg?.msgID ?? "")")},fail: { code, desc inprint(">>>>> sendMessage failed, code:\\(code), desc:\\(desc ?? "")")})
#import <ImSDK_Plus/ImSDK_Plus.h>V2TIMOfflinePushInfo *pushInfo = [[V2TIMOfflinePushInfo alloc] init];pushInfo.title = @"推送标题";pushInfo.desc = @"推送内容";pushInfo.ext = @"{\\"action\\":\\"open_chat\\",\\"conversationID\\":\\"c2c_userA\\"}";V2TIMMessage *message = [[V2TIMManager sharedInstance] createTextMessage:@"Hello TIMPush"];[[V2TIMManager sharedInstance] sendMessage:messagereceiver:@"<#TARGET_USER_ID#>"groupID:nilpriority:V2TIM_PRIORITY_DEFAULTonlineUserOnly:NOofflinePushInfo:pushInfoprogress:nilsucc:^{NSLog(@">>>>> sendMessage success");} fail:^(int code, NSString *desc) {NSLog(@">>>>> sendMessage failed, code:%d, desc:%@", code, desc);}];
sendMessage 属于 IMSDK 消息发送能力。仅集成 TIMPush 的用户不需要为了验证离线推送而额外接入完整 Chat 初始化、登录和消息发送流程。验证:App 置于后台后发送测试消息,设备能收到离线推送通知。如果手机通知栏开启权限,通知栏会弹出离线推送消息弹框。如果收不到,请参见下文「收不到推送排障流程」逐步排查。
处理通知点击跳转
通知点击跳转需要三步配合完成:控制台配置点击动作、发送推送时携带跳转参数、客户端注册监听并解析参数。三步缺一则跳转不生效。
配置控制台点击动作
在腾讯云控制台配置推送证书的「点击后续动作」,勾选「打开应用内指定页面」:
操作路径:腾讯云控制台 > 即时通信 IM > 推送服务 Push > 推送设置 > 厂商配置 > iOS > 对应 APNs 证书 > 编辑 > 点击后续动作 > 打开应用内指定页面。
发送推送时携带 ext
发送离线推送时,通过
ext 字段携带跳转所需的业务信息(如目标页面、会话 ID 等)。ext 是一个字符串,结构由业务自定义,推荐使用 JSON 格式便于客户端解析。下文示例统一使用如下结构演示:// conversationType 为 1 表示单聊(conversationID 填消息发送方 userID),为 2 表示群聊(conversationID 填 groupID)。{"conversationID":"user_A","conversationType":1}
通过 REST API 发送推送时,在请求体的
Ext 字段中设置 JSON 字符串:{"MsgBody": [],"OfflinePushInfo": {"PushFlag": 0,"Title": "离线推送标题","Desc": "离线推送内容","Ext": "{\\"conversationID\\":\\"user_A\\",\\"conversationType\\":1}"}}
控制台接入测试页面同样支持设置
Ext 字段,填入 JSON 字符串即可。如果你接入了 TUIKit,TUIKit 内置的消息发送链路会自动用
OfflinePushExtInfo 组装 ext,无需手动设置。下方示例适用于自行调用 IM SDK 发送消息的场景。import ImSDK_Pluslet pushInfo = V2TIMOfflinePushInfo()pushInfo.title = "推送标题"pushInfo.desc = "推送内容"// TODO: ext 由业务自定义,按需替换为您的目标页面、会话 ID 等参数。pushInfo.ext = "{\\"conversationID\\":\\"user_A\\",\\"conversationType\\":1}"let message = V2TIMManager.sharedInstance().createTextMessage("Hello TIMPush")V2TIMManager.sharedInstance().sendMessage(message: message,receiver: "<#TARGET_USER_ID#>",groupID: nil,priority: V2TIM_PRIORITY_DEFAULT,onlineUserOnly: false,offlinePushInfo: pushInfo,progress: nil,succ: { msg inprint(">>>>> sendMessage success, msgID = \\(msg?.msgID ?? "")")},fail: { code, desc inprint(">>>>> sendMessage failed, code:\\(code), desc:\\(desc ?? "")")})
#import <ImSDK_Plus/ImSDK_Plus.h>V2TIMOfflinePushInfo *pushInfo = [[V2TIMOfflinePushInfo alloc] init];pushInfo.title = @"推送标题";pushInfo.desc = @"推送内容";// TODO: ext 由业务自定义,按需替换为您的目标页面、会话 ID 等参数。pushInfo.ext = @"{\\"conversationID\\":\\"user_A\\",\\"conversationType\\":1}";V2TIMMessage *message = [[V2TIMManager sharedInstance] createTextMessage:@"Hello TIMPush"];[[V2TIMManager sharedInstance] sendMessage:messagereceiver:@"<#TARGET_USER_ID#>"groupID:nilpriority:V2TIM_PRIORITY_DEFAULTonlineUserOnly:NOofflinePushInfo:pushInfoprogress:nilsucc:^(V2TIMMessage *msg) {NSLog(@">>>>> sendMessage success, msgID = %@", msg.msgID);} fail:^(int code, NSString *desc) {NSLog(@">>>>> sendMessage failed, code:%d, desc:%@", code, desc);}];
客户端注册监听并解析 ext
请在 AppDelegate 中遵循 TIMPushListener 协议,在
didFinishLaunchingWithOptions 中调用 addPushListener 注册监听器,并在 onNotificationClicked 中解析 ext 后跳转到业务页面。以下示例只演示解析
ext 的核心逻辑,跳转部分用 TODO 占位,请按自身业务补充。如果您接入了 TUIKit 并使用 OfflinePushExtInfo 组装的 ext,可改为 OfflinePushExtInfo.create(withExtString:) 解析后再跳转。import UIKitimport TIMPush@mainclass AppDelegate: UIResponder, UIApplicationDelegate, TIMPushListener {var window: UIWindow?func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {TIMPushManager.addPushListener(listener: self)return true}// MARK: - TIMPushListener@objc func onNotificationClicked(_ ext: String) {print(">>>>> TIMPush notification clicked, ext:\\(ext)")// 1. 解析 ext。JSON 结构由业务自定义,需与发送端约定一致。guard let data = ext.data(using: .utf8),let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {return}let conversationID = dict["conversationID"] as? String ?? ""let conversationType = dict["conversationType"] as? Int ?? 0// 2. TODO: 根据业务字段跳转到目标页面。// 若使用了 Chat / TUIKit,建议在用户登录成功后再跳转;// 冷启动场景可先把参数缓存起来,登录回调中再跳转。}// 协议要求实现,与点击跳转无关;如需感知收到 / 撤回离线推送,可按需补充。@objc func onRecvPushMessage(_ message: TIMPushMessage) {}@objc func onRevokePushMessage(_ messageID: String) {}}
// AppDelegate.h#import <UIKit/UIKit.h>#import <TIMPush/TIMPushManager.h>@interface AppDelegate : UIResponder <UIApplicationDelegate, TIMPushListener>@property (nonatomic, strong, nullable) UIWindow *window;@end// AppDelegate.m#import "AppDelegate.h"#import <TIMPush/TIMPushManager.h>@implementation AppDelegate- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {[TIMPushManager addPushListener:self];return YES;}#pragma mark - TIMPushListener- (void)onNotificationClicked:(NSString *)ext {NSLog(@">>>>> TIMPush notification clicked, ext:%@", ext);// 1. 解析 ext。JSON 结构由业务自定义,需与发送端约定一致。NSData *data = [ext dataUsingEncoding:NSUTF8StringEncoding];if (data.length == 0) {return;}NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];if (![dict isKindOfClass:[NSDictionary class]]) {return;}NSString *conversationID = dict[@"conversationID"];NSInteger conversationType = [dict[@"conversationType"] integerValue];// 2. TODO: 根据业务字段跳转到目标页面。// 若使用了 Chat / TUIKit,建议在用户登录成功后再跳转;// 冷启动场景可先把参数缓存起来,登录回调中再跳转。}// 协议要求实现,与点击跳转无关;如需感知收到 / 撤回离线推送,可按需补充。- (void)onRecvPushMessage:(TIMPushMessage *)message {}- (void)onRevokePushMessage:(NSString *)messageID {}@end
验证:点击通知后
onNotificationClicked 被调用,且 ext 内容与发送时设置的一致。如果回调未触发,请检查:控制台点击动作是否选择了「打开应用内指定页面」、监听器是否在 didFinishLaunchingWithOptions 中注册、发送消息时是否设置了 ext。收不到推送排障流程
如果发送测试消息后设备没有收到推送,请按以下流程逐步排查。每一步确认通过后再进入下一步,可以快速定位问题所在环节。不要只凭单条 APNs 配置成功日志判断接入成功;运行 App 后可过滤
TIMPush 关键字观察整体日志。步骤1:确认 APNs 权限和 Push Notifications 能力
App 是否已获得系统通知权限。
Xcode 主 App target 的 Signing & Capabilities 是否已开启 Push Notifications。
Apple Developer Center 对应 App ID 的 Capabilities 是否已勾选 Push Notifications。
通过后,进入第二步。
步骤2:确认 registerPush 是否成功
检查
registerPush 回调结果:succ 已触发:注册成功,进入第三步。fail 触发:注册失败。结合下文「错误码」表查询 code 含义,并按返回的 desc 排查 SDKAppID、appKey 取值(独立 Push 用 Push Key,Chat / TUIKit 用 nil)以及调用时机。步骤3:确认控制台排查工具能查到 token
在腾讯云控制台 即时通信 IM > 推送服务 Push 的排查工具中输入
registrationID 或 userID:能查到设备且 token 正常:进入第四步。
查不到设备 / 显示「没有上传成功 token」:常见原因是 Chat 场景未在 Chat 登录成功后调用
registerPush,或调用顺序错误。请重新核对调用时机。步骤4:确认 businessID / Bundle ID / APNs 环境匹配
控制台显示「不允许向该主题推送」或仅部分设备能收到推送时,通常是这一层出了问题:
Xcode 主 App target 的 Bundle Identifier 是否与 Apple App ID 一致。
腾讯云控制台上传的 APNs 证书是否绑定同一个 Bundle ID。
AppDelegate 返回的
businessID 是否为该 Bundle ID 对应的证书 ID。APNs 环境(开发 / 生产)是否与 App 安装包环境匹配。
p8 / p12 证书是否上传到正确应用。
步骤5:确认 Chat / TUIKit 场景登录顺序
仅 Chat / TUIKit 场景需要检查:
registerPush 是否在 Chat 登录成功回调(或 TUILogin.login 成功回调)之后调用。appKey 参数是否传 nil,而不是 Push Key 或 Chat Key。自定义
registrationID 是否与 Chat 登录使用的 userID 完全一致(不一致会产生账号互踢)。步骤6:确认测试消息发送目标和设备状态
测试消息发送给的
registrationID 或 userID 是否与 getRegistrationID: 返回值一致。App 是否处于后台或已杀进程(前台时离线推送可能不触发)。
设备是否处于可接收通知状态(勿扰模式、通知权限等)。
推送服务是否到期(试用到期后自动停止服务)。
仍无法解决