Podfile 中为主 App target 添加 TIMPush 依赖。Podfile 示例:target 'YourAppName' douse_frameworks!use_modular_headers!pod 'TIMPush', 'VERSION'end
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
pod repo update 更新本地 CocoaPods 仓库列表后再 pod install。businessIDbusinessID 是控制台上传 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#>;}
applicationGroupID(可选)// 在 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#>";}
registrationID;服务端、控制台接入测试和排查工具可以使用该标识向这台设备下发离线推送。若 App 同时接入 Chat 并完成登录,也可以使用 userID 向该用户已建立推送关系的设备下发离线推送。appKey 的取值会影响注册方式和可用的推送标识:appKey = Push Key:注册 TIMPush 独立推送能力。Push Key 为控制台 > Push > 概览中的客户端密钥。appKey = nil:复用 Chat 登录态注册推送,必须在 Chat login 成功后调用。场景 | 调用顺序 | 后台可用推送标识 | 说明 |
仅使用 TIMPush | App 每次冷启动后调用 registerPush(appKey = Push Key) | registrationID | 适用于营销 / 活动 / 通知推送,不接入 Chat SDK。 |
Chat SDK + TIMPush 先注册 Push 再登录 | registerPush(appKey = Push Key)→ Chat login | 登录前: registrationID;登录后: registrationID + userID | 适用于希望用户未登录时也能收到营销推送的场景。 |
Chat SDK + TIMPush 先登录再注册 Push | Chat login→ registerPush(appKey = null) | 登录后: userID注册后: userID + registrationID,此时 registrationID = userID | 适用于希望用户登录后能收到 Chat 离线消息和营销推送的场景。 |
userID 与 registrationID 推送关系都会失效,需要重新完成对应注册。registerPush 的 appKey。registerPush(appKey = Push Key)。建议在 registerPush 成功回调里调用 getRegistrationID 打印 registrationID,方便后续根据 registrationID 发送离线推送消息。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")TIMPushManager.getRegistrationID { registrationID inprint(">>>>> TIMPush registrationID: \\(registrationID)")}}, 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");[TIMPushManager getRegistrationID:^(NSString * _Nonnull registrationID) {NSLog(@">>>>> TIMPush registrationID: %@", registrationID);}];} fail:^(int code, NSString * _Nonnull desc) {NSLog(@">>>>> TIMPush register failed, code:%d, desc:%@", code, desc);}];}
login 成功回调中调用 registerPush(appKey = nil)。建议在 registerPush 成功回调里调用 getRegistrationID 打印 registrationID,方便后续根据 registrationID 发送离线推送消息。import TIMPushimport ImSDK_Plusfunc loginIMAndRegisterPush() {// TODO: Replace 0 with your SDKAppID.let sdkAppID: Int32 = 0let userID = "<#YOUR_USER_ID#>"let userSig = "<#YOUR_USER_SIG#>"let initSuccess = V2TIMManager.sharedInstance().initSDK(sdkAppID, config: V2TIMSDKConfig())if !initSuccess {print(">>>>> IM SDK init failed")return}V2TIMManager.sharedInstance().login(userID: userID, userSig: userSig) {TIMPushManager.registerPush(sdkAppID, appKey: "", succ: { deviceToken inprint(">>>>> TIMPush register success")TIMPushManager.getRegistrationID { registrationID inprint(">>>>> TIMPush registrationID: \\(registrationID)")}}, 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#>";V2TIMSDKConfig *config = [[V2TIMSDKConfig alloc] init];BOOL initSuccess = [[V2TIMManager sharedInstance] initSDK:sdkAppID config:config];if (!initSuccess) {NSLog(@">>>>> IM SDK init failed");return;}[[V2TIMManager sharedInstance] login:userID userSig:userSig succ:^{[TIMPushManager registerPush:sdkAppIDappKey:nilsucc:^(NSData * _Nonnull deviceToken) {NSLog(@">>>>> TIMPush register success");[TIMPushManager getRegistrationID:^(NSString * _Nonnull registrationID) {NSLog(@">>>>> TIMPush registrationID: %@", registrationID);}];} 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);}];}
registerPush。否则 SDK 可能会按独立推送场景注册 Push 类型账号,并产生对应的 Push DAU。Push DAU 超出套餐额度后,可能会产生额外费用。registrationID 必须与 Chat 登录使用的 userID 完全一致,否则会产生账号互踢导致推送丢失。mutable-contentPodfile 中为 Extension target 添加 TIMPush 依赖:target 'YourNotificationServiceExtensionTarget' douse_frameworks!use_modular_headers!pod 'TIMPush', 'VERSION'end
pod install。TIMPush,在 NotificationService 中 import TIMPush 或 #import <TIMPush/TIMPushManager.h> 会失败。mutable-contentmutable-content 是 APNs payload 字段,由发送方在推送内容中设置。只有 payload 中开启 mutable-content,iOS 10 及以上系统才会在送达前调用 Notification Service Extension,触达统计才能生效。mutable-content:mutable-content 相关选项。"mutable-content": 1。group.<#YOUR_APP_GROUP_ID#> 替换为您在 Apple Developer Center 和 Xcode 中配置的 App Group ID。主 App 和 Extension 必须使用同一个 App Group ID。// 在 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
businessID;registrationID 或 userID 发送离线推送测试。V2TIMOfflinePushInfo 设置离线推送参数,再交由 V2TIMManager 发送消息。具体方法签名以您接入的 IMSDK 版本头文件为准。import ImSDK_Pluslet pushInfo = V2TIMOfflinePushInfo()pushInfo.title = "推送标题"pushInfo.desc = "推送内容"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 = @"推送内容";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 初始化、登录和消息发送流程。
ext 字段携带跳转所需的业务信息(如目标页面、会话 ID 等)。ext 是一个字符串,结构由业务自定义,推荐使用 JSON 格式便于客户端解析。下文示例统一使用如下结构演示:// conversationType 为 1 表示单聊(conversationID 填消息发送方 userID),为 2 表示群聊(conversationID 填 groupID)。{"conversationID":"user_A","conversationType":1}
Ext 字段中设置 JSON 字符串:{"MsgBody": [],"OfflinePushInfo": {"PushFlag": 0,"Title": "离线推送标题","Desc": "离线推送内容","Ext": "{\\"conversationID\\":\\"user_A\\",\\"conversationType\\":1}"}}
Ext 字段,填入 JSON 字符串即可。OfflinePushExtInfo 组装 ext,无需手动设置。下方示例适用于自行调用 Chat 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);}];
didFinishLaunchingWithOptions 中调用 addPushListener 注册监听器,并在 onNotificationClicked 中解析 ext 后跳转到业务页面。如果您接入了 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
文档反馈