
assets 目录。推荐存储路径:app/src/main/assets/timpush-configs.json,其中 app 是你项目的应用模块,可替换成实际名称。如果工程中没有 assets 目录,请在 src/main/ 下手动创建。google()、mavenCentral() 用于解析 Android 官方组件,腾讯云 Maven 仓库用于解析 TIMPush 等腾讯云依赖。文件 | DSL 类型 |
settings.gradle、build.gradle | Groovy DSL |
settings.gradle.kts、build.gradle.kts | Kotlin DSL |
gradle/wrapper/gradle-wrapper.properties 中查看 distributionUrl 对应的版本号。settings.gradle(Groovy DSL)或 settings.gradle.kts(Kotlin DSL)中,同时在 pluginManagement > repositories 和 dependencyResolutionManagement > repositories 中添加仓库。pluginManagement {repositories {gradlePluginPortal()google()mavenCentral()maven { url "https://mirrors.tencent.com/nexus/repository/maven-public/" }}}dependencyResolutionManagement {repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)repositories {google()mavenCentral()maven { url "https://mirrors.tencent.com/nexus/repository/maven-public/" }}}
pluginManagement {repositories {gradlePluginPortal()google()mavenCentral()maven { url = uri("https://mirrors.tencent.com/nexus/repository/maven-public/") }}}dependencyResolutionManagement {repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)repositories {google()mavenCentral()maven { url = uri("https://mirrors.tencent.com/nexus/repository/maven-public/") }}}
build.gradle 的 buildscript > repositories 中添加插件仓库。buildscript {repositories {google()mavenCentral()maven { url "https://mirrors.tencent.com/nexus/repository/maven-public/" }}}
settings.gradle 的 dependencyResolutionManagement > repositories 中添加依赖仓库。dependencyResolutionManagement {repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)repositories {google()mavenCentral()maven { url "https://mirrors.tencent.com/nexus/repository/maven-public/" }}}
build.gradle 的 buildscript > repositories 和 allprojects > repositories 中添加仓库。buildscript {repositories {google()mavenCentral()maven { url "https://mirrors.tencent.com/nexus/repository/maven-public/" }}}allprojects {repositories {google()mavenCentral()maven { url "https://mirrors.tencent.com/nexus/repository/maven-public/" }}}
build.gradle 或 build.gradle.kts 中添加 TIMPush 基础依赖。基础包提供 TIMPush 注册、监听和通用能力。dependencies {implementation 'com.tencent.timpush:timpush:VERSION'implementation 'com.tencent.liteav.tuikit:tuicore:VERSION'}
dependencies {implementation("com.tencent.timpush:timpush:VERSION")implementation("com.tencent.liteav.tuikit:tuicore:VERSION")}
timpush-configs.json,并放入应用模块 assets 目录;google-services.json,添加到应用模块根目录(与应用模块的 build.gradle / build.gradle.kts 同级):app/google-services.json
buildscript > dependencies > classpath 声明,因此项目级 build.gradle 或 build.gradle.kts 的 buildscript > repositories 中需包含 google() 等仓库,否则插件 classpath 可能解析失败。项目级已用 plugins {} 块声明 AGP 时保留原写法即可,无需迁移。buildscript {repositories {google()mavenCentral()gradlePluginPortal()maven { url "https://mirrors.tencent.com/nexus/repository/maven-public/" }}dependencies {// 请与项目当前 Android Gradle Plugin 版本保持一致。classpath 'com.android.tools.build:gradle:<AGP_VERSION>'// 如果项目使用 Kotlin Android 插件,请与项目当前 Kotlin Gradle Plugin 版本保持一致。classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:<KOTLIN_VERSION>'// Google FCM。4.4.2 要求 AGP 7.3.0 及以上,更低的 AGP 请改用 4.3.15。classpath 'com.google.gms:google-services:4.4.2'}}
buildscript {repositories {google()mavenCentral()gradlePluginPortal()maven { url = uri("https://mirrors.tencent.com/nexus/repository/maven-public/") }}dependencies {// 请与项目当前 Android Gradle Plugin 版本保持一致。classpath("com.android.tools.build:gradle:<AGP_VERSION>")// 如果项目使用 Kotlin Android 插件,请与项目当前 Kotlin Gradle Plugin 版本保持一致。classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:<KOTLIN_VERSION>")// Google FCM。4.4.2 要求 AGP 7.3.0 及以上,更低的 AGP 请改用 4.3.15。classpath("com.google.gms:google-services:4.4.2")}}
com.google.gms:google-services:4.4.2 要求 AGP 7.3.0 及以上;如果项目的 AGP 低于 7.3.0,请改用与当前 AGP 兼容的 Google Services Gradle Plugin 版本,例如 4.3.15。build.gradle 的 buildscript > dependencies 中追加:classpath 'com.google.gms:google-services:4.3.15'
build.gradle 或 build.gradle.kts 中启用 Google Services 插件。plugins {// Google FCM。id 'com.google.gms.google-services'}// 或:apply plugin: 'com.google.gms.google-services'
plugins {// Google FCM。id("com.google.gms.google-services")}// 或:apply(plugin = "com.google.gms.google-services")
build.gradle 或 build.gradle.kts 的 dependencies 中追加 FCM 通道包,VERSION 与基础包保持一致:implementation 'com.tencent.timpush:fcm:VERSION'
implementation("com.tencent.timpush:fcm:VERSION")
setAndroidFCMChannelID(String channelID) 设置 FCM 通道通知渠道 ID:V2TIMOfflinePushInfo pushInfo = new V2TIMOfflinePushInfo();pushInfo.setAndroidFCMChannelID("your_fcm_channel_id");
registrationID;服务端、控制台接入测试和排查工具可以使用该标识向这台设备下发离线推送。若 App 同时接入 Chat 并完成登录,也可以使用 userID 向该用户已建立推送关系的设备下发离线推送。appKey 的取值会影响注册方式和可用的推送标识:appKey = Push Key:注册 TIMPush 独立推送能力。Push Key 客户端密钥。appKey = null:复用 Chat 登录态注册推送,必须在 Chat login 成功后调用。userID 与 registrationID 推送关系都会失效,需要重新完成对应注册。registerPush 的 appKey。registerPush(appKey = Push Key)。建议在 registerPush 成功回调里调用 getRegistrationID 打印 registrationID,方便后续根据 registrationID 发送离线推送消息。import android.util.Log;import com.tencent.timpush.TIMPushCallback;import com.tencent.timpush.TIMPushManager;// 在用户同意隐私政策后调用private void registerTIMPush() {int sdkAppId = 0; // TODO: Replace with your SDKAppID.String appKey = "你的客户端密钥"; // TODO: Replace with your Push Key.TIMPushManager.getInstance().registerPush(this, sdkAppId, appKey, new TIMPushCallback<Object>() {@Overridepublic void onSuccess(Object data) {Log.d(TAG, ">>>>> registerPush success, data = " + data);TIMPushManager.getInstance().getRegistrationID(new TIMPushCallback<Object>() {@Overridepublic void onSuccess(Object data) {String registrationID = (String) data;Log.d(TAG, ">>>>> getRegistrationID success, registrationID = " + registrationID);}@Overridepublic void onError(int errCode, String errMsg, Object data) {Log.e(TAG, ">>>>> getRegistrationID failed, errCode = " + errCode+ ", errMsg = " + errMsg);}});}@Overridepublic void onError(int errCode, String errMsg, Object data) {Log.e(TAG, ">>>>> registerPush failed, errCode = " + errCode+ ", errMsg = " + errMsg);}});}
import android.util.Logimport com.tencent.timpush.TIMPushCallbackimport com.tencent.timpush.TIMPushManager// 在用户同意隐私政策后调用private fun registerTIMPush() {val sdkAppId = 0 // TODO: Replace with your SDKAppID.val appKey = "你的客户端密钥" // TODO: Replace with your Push Key.TIMPushManager.getInstance().registerPush(this, sdkAppId, appKey, object : TIMPushCallback<Any?>() {override fun onSuccess(data: Any?) {Log.d("TIMPush", ">>>>> registerPush success, data = $data")TIMPushManager.getInstance().getRegistrationID(object : TIMPushCallback<Any?>() {override fun onSuccess(data: Any?) {Log.d("TIMPush", ">>>>> getRegistrationID success, registrationID = $data")}override fun onError(errCode: Int, errMsg: String?, data: Any?) {Log.e("TIMPush", ">>>>> getRegistrationID failed, errCode = $errCode, errMsg = $errMsg")}})}override fun onError(errCode: Int, errMsg: String?, data: Any?) {Log.e("TIMPush", ">>>>> registerPush failed, errCode = $errCode, errMsg = $errMsg")}})}
login 成功回调中调用 registerPush(appKey = null)。建议在 registerPush 成功回调里调用 getRegistrationID 打印 registrationID,方便后续根据 registrationID 发送离线推送消息。import android.content.Context;import android.util.Log;import com.tencent.imsdk.v2.V2TIMCallback;import com.tencent.imsdk.v2.V2TIMManager;import com.tencent.imsdk.v2.V2TIMSDKConfig;import com.tencent.qcloud.tim.push.TIMPushCallback;import com.tencent.qcloud.tim.push.TIMPushManager;public void loginIMAndRegisterPush(Context context) {int sdkAppId = 0; // TODO: Replace with your SDKAppID.String userID = "<YOUR_USER_ID>";String userSig = "<YOUR_USER_SIG>";boolean initSuccess = V2TIMManager.getInstance().initSDK(context, sdkAppId, new V2TIMSDKConfig());if (!initSuccess) {Log.e("TIMPush", ">>>>> IM SDK init failed");return;}V2TIMManager.getInstance().login(userID, userSig, new V2TIMCallback() {@Overridepublic void onSuccess() {TIMPushManager.getInstance().registerPush(context, sdkAppId, null, new TIMPushCallback<Object>() {@Overridepublic void onSuccess(Object data) {Log.d("TIMPush", ">>>>> registerPush success, data = " + data);TIMPushManager.getInstance().getRegistrationID(new TIMPushCallback<Object>() {@Overridepublic void onSuccess(Object data) {String registrationID = (String) data;Log.d(TAG, ">>>>> getRegistrationID success, registrationID = " + registrationID);}@Overridepublic void onError(int errCode, String errMsg, Object data) {Log.e(TAG, ">>>>> getRegistrationID failed, errCode = " + errCode+ ", errMsg = " + errMsg);}});}@Overridepublic void onError(int errCode, String errMsg, Object data) {Log.e("TIMPush", ">>>>> registerPush failed, errCode = " + errCode+ ", errMsg = " + errMsg);}});}@Overridepublic void onError(int code, String desc) {Log.e("TIMPush", ">>>>> IM login failed, code = " + code + ", desc = " + desc);}});}
import android.content.Contextimport android.util.Logimport com.tencent.imsdk.v2.V2TIMCallbackimport com.tencent.imsdk.v2.V2TIMManagerimport com.tencent.imsdk.v2.V2TIMSDKConfigimport com.tencent.qcloud.tim.push.TIMPushCallbackimport com.tencent.qcloud.tim.push.TIMPushManagerfun loginIMAndRegisterPush(context: Context) {val sdkAppId = 0 // TODO: Replace with your SDKAppID.val userID = "<YOUR_USER_ID>"val userSig = "<YOUR_USER_SIG>"val initSuccess = V2TIMManager.getInstance().initSDK(context, sdkAppId, V2TIMSDKConfig())if (!initSuccess) {Log.e("TIMPush", ">>>>> IM SDK init failed")return}V2TIMManager.getInstance().login(userID, userSig, object : V2TIMCallback {override fun onSuccess() {TIMPushManager.getInstance().registerPush(context, sdkAppId, null, object : TIMPushCallback<Any>() {override fun onSuccess(data: Any?) {Log.d("TIMPush", ">>>>> registerPush success, data = $data")TIMPushManager.getInstance().getRegistrationID(object : TIMPushCallback<Any?>() {override fun onSuccess(data: Any?) {Log.d("TIMPush", ">>>>> getRegistrationID success, registrationID = $data")}override fun onError(errCode: Int, errMsg: String?, data: Any?) {Log.e("TIMPush", ">>>>> getRegistrationID failed, errCode = $errCode, errMsg = $errMsg")}})}override fun onError(errCode: Int, errMsg: String?, data: Any?) {Log.e("TIMPush", ">>>>> registerPush failed, errCode = $errCode, errMsg = $errMsg")}})}override fun onError(code: Int, desc: String?) {Log.e("TIMPush", ">>>>> IM login failed, code = $code, desc = $desc")}})}
registerPush。否则 SDK 可能会按独立推送场景注册 Push 类型账号,并产生对应的 Push DAU。Push DAU 超出套餐额度后,可能会产生额外费用。registerPush 的 onSuccess 回调被触发。registrationID 或 userID,确认 token 已上传。onError,可按 错误码 查询 code 含义。registrationID 必须与 Chat 登录使用的 userID 完全一致,否则会产生账号互踢导致推送丢失。V2TIMOfflinePushInfo pushInfo = new V2TIMOfflinePushInfo();pushInfo.setTitle("推送标题");pushInfo.setDesc("推送内容");pushInfo.setExt("业务自定义 ext".getBytes());V2TIMManager.getMessageManager().sendMessage(v2TIMMessage,userID,null,V2TIMMessage.V2TIM_PRIORITY_DEFAULT,false,pushInfo,new V2TIMSendCallback<V2TIMMessage>() {@Overridepublic void onProgress(int progress) {}@Overridepublic void onError(int code, String desc) {Log.e("TIMPush", ">>>>> sendMessage failed, code = " + code + ", desc = " + desc);}@Overridepublic void onSuccess(V2TIMMessage message) {Log.d("TIMPush", ">>>>> sendMessage success, msgID = " + message.getMsgID());}});
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 android.util.Log;import com.tencent.imsdk.v2.V2TIMManager;import com.tencent.imsdk.v2.V2TIMMessage;import com.tencent.imsdk.v2.V2TIMOfflinePushInfo;import com.tencent.imsdk.v2.V2TIMSendCallback;V2TIMOfflinePushInfo pushInfo = new V2TIMOfflinePushInfo();pushInfo.setTitle("推送标题");pushInfo.setDesc("推送内容");// TODO: ext 由业务自定义,按需替换为您的目标页面、会话 ID 等参数。String ext = "{\\"conversationID\\":\\"user_A\\",\\"conversationType\\":1}";pushInfo.setExt(ext.getBytes());V2TIMMessage message = V2TIMManager.getMessageManager().createTextMessage("Hello TIMPush");V2TIMManager.getMessageManager().sendMessage(message,"<TARGET_USER_ID>", // 单聊填对端 userID,群聊该参数填 nullnull, // 群聊填 groupID,单聊该参数填 nullV2TIMMessage.V2TIM_PRIORITY_DEFAULT,false,pushInfo,new V2TIMSendCallback<V2TIMMessage>() {@Overridepublic void onProgress(int progress) {}@Overridepublic void onSuccess(V2TIMMessage msg) {Log.d("TIMPush", ">>>>> sendMessage success, msgID = " + msg.getMsgID());}@Overridepublic void onError(int code, String desc) {Log.e("TIMPush", ">>>>> sendMessage failed, code = " + code + ", desc = " + desc);}});
import android.util.Logimport com.tencent.imsdk.v2.V2TIMManagerimport com.tencent.imsdk.v2.V2TIMMessageimport com.tencent.imsdk.v2.V2TIMOfflinePushInfoimport com.tencent.imsdk.v2.V2TIMSendCallbackval pushInfo = V2TIMOfflinePushInfo()pushInfo.title = "推送标题"pushInfo.desc = "推送内容"// TODO: ext 由业务自定义,按需替换为您的目标页面、会话 ID 等参数。pushInfo.ext = "{\\"conversationID\\":\\"user_A\\",\\"conversationType\\":1}".toByteArray()val message = V2TIMManager.getMessageManager().createTextMessage("Hello TIMPush")V2TIMManager.getMessageManager().sendMessage(message,"<TARGET_USER_ID>", // 单聊填对端 userID,群聊该参数填 nullnull, // 群聊填 groupID,单聊该参数填 nullV2TIMMessage.V2TIM_PRIORITY_DEFAULT,false,pushInfo,object : V2TIMSendCallback<V2TIMMessage> {override fun onProgress(progress: Int) {}override fun onSuccess(msg: V2TIMMessage) {Log.d("TIMPush", ">>>>> sendMessage success, msgID = ${msg.msgID}")}override fun onError(code: Int, desc: String?) {Log.e("TIMPush", ">>>>> sendMessage failed, code = $code, desc = $desc")}})
Application.onCreate() 中调用 addPushListener 注册 TIMPushListener,并在 onNotificationClicked 中解析 ext 后跳转到业务页面。如果你接入了 TUIKit 并使用 OfflinePushExtInfo 组装的 ext,可改为 new Gson().fromJson(ext, OfflinePushExtInfo.class) 解析后再跳转。import android.app.Application;import android.text.TextUtils;import android.util.Log;import com.tencent.timpush.TIMPushListener;import com.tencent.timpush.TIMPushManager;import org.json.JSONObject;public class App extends Application {private static final String TAG = "TIMPush";@Overridepublic void onCreate() {super.onCreate();TIMPushManager.getInstance().addPushListener(new TIMPushListener() {@Overridepublic void onNotificationClicked(String ext) {Log.d(TAG, ">>>>> TIMPush notification clicked, ext = " + ext);if (TextUtils.isEmpty(ext)) {return;}// 1. 解析 ext。JSON 结构由业务自定义,需与发送端约定一致。String conversationID;int conversationType;try {JSONObject json = new JSONObject(ext);conversationID = json.optString("conversationID");conversationType = json.optInt("conversationType");} catch (Exception e) {Log.e(TAG, ">>>>> parse ext failed: " + e.getMessage());return;}// 2. TODO: 根据业务字段跳转到目标页面。// 若使用了 Chat / TUIKit,建议在用户登录成功后再跳转;// 冷启动场景可先把参数缓存起来,登录回调中再跳转。}});}}
import android.app.Applicationimport android.text.TextUtilsimport android.util.Logimport com.tencent.timpush.TIMPushListenerimport com.tencent.timpush.TIMPushManagerimport org.json.JSONObjectclass App : Application() {override fun onCreate() {super.onCreate()TIMPushManager.getInstance().addPushListener(object : TIMPushListener() {override fun onNotificationClicked(ext: String?) {Log.d("TIMPush", ">>>>> TIMPush notification clicked, ext = $ext")if (TextUtils.isEmpty(ext)) return// 1. 解析 ext。JSON 结构由业务自定义,需与发送端约定一致。val conversationID: Stringval conversationType: Inttry {val json = JSONObject(ext)conversationID = json.optString("conversationID")conversationType = json.optInt("conversationType")} catch (e: Exception) {Log.e("TIMPush", ">>>>> parse ext failed: ${e.message}")return}// 2. TODO: 根据业务字段跳转到目标页面。// 若使用了 Chat / TUIKit,建议在用户登录成功后再跳转;// 冷启动场景可先把参数缓存起来,登录回调中再跳转。}})}}
文档反馈