本文将介绍如何在 Flutter 工程中集成 TIMPush。
前提条件
开始接入前,请先完成目标平台的推送前提配置,并准备好注册所需参数。按平台查看:
请确认已 开通 Push 服务,并按需完成 Android 厂商配置(小米 / 华为 / OPPO / vivo / 荣耀 / 魅族 / Google FCM)。Flutter Android 侧至少需要准备:
资源 | 用途 |
SDKAppID、客户端密钥(Push Key) | 调用 registerPush |
timpush-configs.json | 放入 Android 应用模块 assets |
目标厂商配置文件(如有) | 华为、荣耀、Google FCM 等按厂商要求放入工程 |
工程 applicationId | 与厂商平台应用包名一致 |
TIMPush 版本号 VERSION |
资源 | 用途 |
SDKAppID、Push Key | 调用 registerPush |
证书 ID( businessID / apnsCertificateID) | 腾讯云控制台上传 APNs 证书后生成,经 registerPush 传入 |
App Group ID(可选) | 仅触达统计需要,经 registerPush 的 applicationGroupID 传入 |
本文示例中的
VERSION、SDKAppID、AppKey、证书 ID、App Group ID 均为占位符,请勿在代码仓库中提交真实密钥。AI 集成
通过 npx 安装 @tencent-rtc/trtc-push-skill 到本地 AI IDE 中,辅助完成 TIMPush 离线推送集成。安装后,您可以直接向 AI 输入“集成 Flutter 离线推送”“帮我集成 Flutter TIMPush”等需求,AI 将根据项目类型引导您完成环境检测、厂商通道配置、凭据填写、代码接入和验证等步骤。详情可参考 AI Coding。
手动集成
步骤1:集成 TIMPush SDK
如果您想手动集成,请按顺序完成下述步骤。
集成 Flutter 插件
Flutter 工程需要先引入推送插件。您可以在
pubspec.yaml 中添加依赖,也可以执行以下命令自动安装:flutter pub add tencent_cloud_chat_push
配置原生工程
完成 Flutter 插件集成后,继续完成对应原生平台配置。
与原生 Android 的差异如下,请按下方完成:
1. 厂商通道包:Flutter 插件已处理 TIMPush 基础依赖,不要再添加
com.tencent.timpush:timpush / tuicore。只需按需引入目标厂商通道包。2. 自定义 Application:必须继承
TencentCloudChatPushApplication。在
android/app/build.gradle 或 android/app/build.gradle.kts 按需引入目标厂商的 TIMPush 通道包。只有引入对应厂商包,才能启用该厂商的原生推送能力。VERSION 请前往 更新日志 获取并替换为实际版本号。implementation 'com.tencent.timpush:xiaomi:VERSION'
implementation("com.tencent.timpush:xiaomi:VERSION")
implementation 'com.tencent.timpush:huawei:VERSION'
implementation("com.tencent.timpush:huawei:VERSION")
implementation 'com.tencent.timpush:oppo:VERSION'
implementation("com.tencent.timpush:oppo:VERSION")
implementation 'com.tencent.timpush:vivo:VERSION'
implementation("com.tencent.timpush:vivo:VERSION")
implementation 'com.tencent.timpush:honor:VERSION'
implementation("com.tencent.timpush:honor:VERSION")
implementation 'com.tencent.timpush:meizu:VERSION'
implementation("com.tencent.timpush:meizu:VERSION")
implementation 'com.tencent.timpush:fcm:VERSION'
implementation("com.tencent.timpush:fcm:VERSION")
Android 端还需要创建或复用自定义
Application 类,并继承 TencentCloudChatPushApplication。如果工程中已存在自定义 Application,直接改为继承该类,并确保 onCreate() 中调用 super.onCreate()。package com.example.pushdemoimport com.tencent.chat.flutter.push.tencent_cloud_chat_push.application.TencentCloudChatPushApplicationclass MyApplication : TencentCloudChatPushApplication() {override fun onCreate() {super.onCreate()}}
然后在
android/app/src/main/AndroidManifest.xml 的 <application> 标签中配置 android:name,指向上述自定义 Application 类。<applicationandroid:name=".MyApplication"...></application>
Flutter 插件会处理 TIMPush 相关依赖,不需要执行原生 iOS 文档中“主 App target 集成”步骤。您只需要在
ios/Runner/AppDelegate.swift 中补充 TIMPush 相关配置,用于返回推送证书 ID、App Group ID,以及转发离线推送点击事件。证书 ID 与 App Group ID 由 registerPush 传入,再经下列桥接方法返回给 TIMPush。import UIKitimport Flutter// Add these two import linesimport TIMPushimport tencent_cloud_chat_push// Add `, TIMPushDelegate` to the following line@UIApplicationMain@objc class AppDelegate: FlutterAppDelegate, TIMPushDelegate {override func application(_ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {GeneratedPluginRegistrant.register(with: self)return super.application(application, didFinishLaunchingWithOptions: launchOptions)}// Add this function@objc func businessID() -> Int32 {return TencentCloudChatPushFlutterModal.shared.businessID();}// Add this function@objc func applicationGroupID() -> String {return TencentCloudChatPushFlutterModal.shared.applicationGroupID()}// Add this function@objc func onRemoteNotificationReceived(_ notice: String?) -> Bool {TencentCloudChatPushPlugin.shared.tryNotifyDartOnNotificationClickEvent(notice)return true}}
步骤2:注册推送服务
registerPush 用于向 TIMPush 注册当前设备的推送 token。注册成功后,TIMPush 会为当前设备建立一个推送目标标识
registrationID;服务端、控制台接入测试和排查工具可以使用该标识向这台设备下发离线推送。若 App 同时接入 IM 并完成登录,也可以使用 userID 向该用户已建立推送关系的设备下发离线推送。appKey 的取值会影响注册方式和可用的推送标识:appKey = Push Key:注册 TIMPush 独立推送能力。Push Key 客户端密钥。appKey = null:复用 IM 登录态注册推送,必须在 IM login 成功后调用。注意:
如果用户退出 IM SDK,同时集成了 IM SDK + TIMPush 的场景下已建立的
userID 与 registrationID 推送关系都会失效,需要重新完成对应注册。Chat 应用的密钥仅用于 IM 登录,不能作为
registerPush 的 appKey。请注意,不要在 Flutter 程序入口的
main 方法中调用。建议在用户同意隐私政策后,并在业务侧合适时机调用。Future<void> registerTIMPush() async {final push = TencentCloudChatPush();final registerRes = await push.registerPush(// TODO: 替换为您的 SDKAppID。sdkAppId: 0,// TODO: 替换为 Push 客户端密钥。appKey: '<#YOUR_PUSH_APP_KEY#>',// iOS:替换为在腾讯云控制台生成的证书 ID;Android 不用传。apnsCertificateID: 0,// iOS 可选:如需统计推送触达,请替换为 Apple Developer Center 或 Xcode 中配置的 App Group ID;Android 不用传。// applicationGroupID: 'group.<#YOUR_APP_GROUP_ID#>',// 当前 Flutter API 仍要求传入该参数,但该回调待废弃。// 请不要在这里处理通知点击,统一使用 addPushListener。onNotificationClicked:({required String ext, String? userID, String? groupID}) {},);if (registerRes.code != 0) {debugPrint('registerPush failed: code=${registerRes.code}, ''msg=${registerRes.errorMessage}, deviceToken=${registerRes.data}',);return;}final ridRes = await push.getRegistrationID();debugPrint('registerPush success, registrationID=${ridRes.data}, ''code=${ridRes.code}, msg=${ridRes.errorMessage}',);}
Future<void> loginIMAndRegisterPush() async {final int sdkAppId = 0; // TODO: 替换为您的 SDKAppID。final String userID = '<#YOUR_USER_ID#>';final String userSig = '<#YOUR_USER_SIG#>';final initRes = await TencentImSDKPlugin.v2TIMManager.initSDK(sdkAppID: sdkAppId,);if (initRes.code != 0) {debugPrint('initSDK failed: code=${initRes.code}, desc=${initRes.desc}');return;}final loginRes = await TencentImSDKPlugin.v2TIMManager.login(userID: userID,userSig: userSig,);if (loginRes.code != 0) {debugPrint('login failed: code=${loginRes.code}, desc=${loginRes.desc}');return;}final push = TencentCloudChatPush();final registerRes = await push.registerPush(sdkAppId: sdkAppId,// iOS:替换为在腾讯云控制台生成的证书 ID;Android 不用传。apnsCertificateID: 0,// iOS 可选:如需统计推送触达,请替换为 Apple Developer Center 或 Xcode 中配置的 App Group ID;Android 不用传。// applicationGroupID: 'group.<#YOUR_APP_GROUP_ID#>',// 当前 Flutter API 仍要求传入该参数,但该回调待废弃。// 请不要在这里处理通知点击,后续章节会介绍推荐的监听方式。onNotificationClicked:({required String ext, String? userID, String? groupID}) {},);if (registerRes.code != 0) {debugPrint('registerPush failed: code=${registerRes.code}, ''msg=${registerRes.errorMessage}, deviceToken=${registerRes.data}',);return;}final ridRes = await push.getRegistrationID();debugPrint('registerPush after login success, registrationID=${ridRes.data}, ''code=${ridRes.code}, msg=${ridRes.errorMessage}',);}
警告:
如果您的业务仅使用即时通信 IM 聊天能力,请勿在 IM 登录前先调用
registerPush。否则 SDK 可能会按独立推送场景注册 Push 类型账号,并产生对应的 Push DAU。Push DAU 超出套餐额度后,可能会产生额外费用。步骤3:配置消息触达统计(可选)
触达统计主要涉及厂商控制台、回执地址、APNs Notification Service Extension、App Group 等平台专属配置。按平台完成:
Flutter 额外确认两点:
1. 调用
registerPush 时传入 applicationGroupID。2.
ios/Runner/AppDelegate.swift 中已实现 applicationGroupID()。步骤4:测试推送链路
完成上述集成步骤后,需要通过发送测试消息验证链路是否打通。
运行 App 后,过滤
TIMPush 关键字查看注册日志。注册成功后,调用 getRegistrationID() 获取当前设备推送标识。控制台或服务端发送测试消息时,可使用该值定位设备。发送消息前请确认:
1. App 已获得系统通知权限(含横幅、锁屏、声音等开关)。
2. App 已置于后台或杀掉进程(前台时离线推送可能不触发)。
发送测试消息可以采用下面几种方法:
仅集成 TIMPush 的用户,建议优先使用腾讯云控制台接入测试能力验证离线推送。
操作路径:腾讯云控制台 > 推送服务 Push > 接入测试。在接入测试页面,可以指定
registrationID 或 userID 发送离线推送测试。如果您的项目已接入 IM SDK,可通过 SDK API 发送一条带离线推送参数的消息进行验证。Flutter 侧示例如下:
Future<void> sendTestPushMessage({required String targetUserID,}) async {final createRes = await TencentImSDKPlugin.v2TIMManager.v2TIMMessageManager.createTextMessage(text: 'Hello TIMPush');final message = createRes.data?.messageInfo;if (createRes.code != 0 || message == null) {debugPrint('createTextMessage failed: code=${createRes.code}');return;}final sendRes = await TencentImSDKPlugin.v2TIMManager.v2TIMMessageManager.sendMessage(message: message,receiver: targetUserID,groupID: '',priority: MessagePriorityEnum.V2TIM_PRIORITY_NORMAL,onlineUserOnly: false,offlinePushInfo: OfflinePushInfo(title: '推送标题',desc: '推送内容',ext: '{"action":"open_chat","conversationID":"c2c_$targetUserID"}',),);debugPrint('sendMessage result: code=${sendRes.code}, desc=${sendRes.desc}, ''msgID=${sendRes.data?.msgID}',);}
验证:App 置于后台后发送测试消息,设备能收到离线推送通知。如果手机通知栏开启权限,通知栏会弹出离线推送消息弹框。
步骤5:处理通知点击跳转
发送推送时携带 ext
如果您的项目已接入 IM SDK,可在发送消息时通过
OfflinePushInfo.ext 携带跳转参数。示例代码如下:Future<void> sendMessageWithPushExt({required String targetUserID,}) async {final createRes = await TencentImSDKPlugin.v2TIMManager.v2TIMMessageManager.createTextMessage(text: 'Hello TIMPush');final message = createRes.data?.messageInfo;if (createRes.code != 0 || message == null) {debugPrint('createTextMessage failed: code=${createRes.code}');return;}final sendRes = await TencentImSDKPlugin.v2TIMManager.v2TIMMessageManager.sendMessage(message: message,receiver: targetUserID,groupID: '',priority: MessagePriorityEnum.V2TIM_PRIORITY_NORMAL,onlineUserOnly: false,offlinePushInfo: OfflinePushInfo(title: '推送标题',desc: '推送内容',ext: '{"conversationID":"$targetUserID","conversationType":1}',),);debugPrint('sendMessage result: code=${sendRes.code}, desc=${sendRes.desc}, ''msgID=${sendRes.data?.msgID}',);}
客户端注册监听并解析 ext
Flutter 客户端推荐使用
TencentCloudChatPush().addPushListener 监听通知点击事件,并在 onNotificationClicked 中解析 ext。示例代码如下:final TIMPushListener timPushListener = TIMPushListener(onRecvPushMessage: (TimPushMessage msg) {debugPrint('onRecvPushMessage: title=${msg.title}, desc=${msg.desc}, ''ext=${msg.ext}, msgID=${msg.messageID}',);},onRevokePushMessage: (String msgID) {debugPrint('onRevokePushMessage: msgID=$msgID');},onNotificationClicked: (String ext) {debugPrint('onNotificationClicked: ext=$ext');// 1. 解析 ext。JSON 结构由业务自定义,需与发送端约定一致。Map<String, dynamic>? extJson;try {extJson = jsonDecode(ext) as Map<String, dynamic>;} catch (e) {debugPrint('parse ext failed: $e');return;}final String? conversationID = extJson['conversationID'] as String?;final int? conversationType = extJson['conversationType'] as int?;if (conversationID == null || conversationType == null) {return;}// 2. TODO: 根据业务字段跳转到目标页面。// 若使用了 Chat / TUIKit,建议在用户登录成功后再跳转;// 冷启动场景可先把参数缓存起来,登录回调中再跳转。},);Future<void> addTIMPushListener() async {await TencentCloudChatPush().addPushListener(listener: timPushListener);}Future<void> removeTIMPushListener() async {await TencentCloudChatPush().removePushListener(listener: timPushListener);}
注意:
TencentCloudChatPush().registerPush 当前仍要求传入 onNotificationClicked 参数,但该参数待废弃。新接入业务请不要在 registerPush 的 onNotificationClicked 中处理跳转,统一使用 addPushListener。ext 是发送方写入的业务透传字段,建议使用 JSON 字符串,例如 {"conversationID":"user_A","conversationType":1}。若 App 冷启动后需要立即处理点击事件,建议尽早注册
listener,例如在登录流程完成后、业务首页初始化前完成注册。发送离线推送时如需设置 Android 厂商消息分类或通知渠道 ID,可通过 Flutter Chat SDK 的 OfflinePushInfo 设置;具体字段含义与厂商规则见 Android 厂商通道集成。
接入排查