离线推送流程
实现离线消息推送的过程如下:
- 开发者到厂商的平台注册账号,并通过开发者认证后,申请开通推送服务。
- 创建推送服务,并绑定应用信息,获取推送证书、密码、密钥等信息。
- 登录 即时通信 IM 控制台 填写推送证书及相关信息,即时通信 IM 服务端会为每个证书生成不同的证书 ID。
- 将厂商提供的推送 SDK 集成到开发者的项目工程中,并按各厂商的要求进行配置。
- 集成即时通信 IM SDK 到项目后,将证书 ID、设备信息等上报至即时通信 IM 服务端。
- 当客户端 App 在即时通信 IM 没有退出登录的情况下,被系统或者用户 kill 时,即时通信 IM 服务端将通过消息推送进行提醒。
配置离线推送
华为 EMUI 是一款深度定制的 Android 系统,后台策略严格,默认情况下第三方 App 不具有自启动权限,App 在后台时很容易被系统强制 kill,因此推荐在华为设备上集成华为推送服务,华为推送服务是华为消息服务(HMS)的一部分,在 EMUI 中属于系统级服务,推送到达率相比第三方更高。目前,即时通信 IM 仅支持华为推送的通知栏消息。
注意:
- 此指引文档是直接参考华为推送官方文档所写,若华为推送有变动,请以 华为推送官网 为准。
- 如果不需要对华为设备做专门的离线推送适配,可以忽略此章节。
步骤1:申请华为推送证书
- 打开 华为开发者联盟官网 进行注册并通过开发者认证。
- 登录华为开发者联盟的管理控制台,选择【应用服务】>【开发服务】>【PUSH】,创建华为推送服务应用。
华为推送在申请 PUSH 服务时,需要您提供应用签名证书的 SHA256 指纹,最多允许添加5个。 华为推送服务应用创建完成后,在应用详情中,您可以查看详细的应用信息。 - 记录
包名
、APP ID
、APP Secret
信息。
步骤2:托管证书信息到即时通信 IM
- 登录腾讯云 即时通信 IM 控制台,单击目标应用卡片,进入应用的基础配置页面。
- 单击【Android平台推送设置】区域的【添加证书】。
>?如果您原来已有证书只需变更信息,可以单击【Android平台推送设置】区域的【编辑】进行修改更新。
> - 根据 步骤1 中获取的信息设置以下参数:
- 推送平台:选择华为
- 应用包名称:填写华为推送服务应用的包名
- AppID:填写华为推送服务应用的 APP ID
- AppSecret:填写华为推送服务应用的 APP SECRET
- 角标参数:填写应用入口完整
Activity
类名,用作华为桌面应用角标显示,请参考 华为桌面角标开发指导书 - 点击通知后:选择点击通知栏消息后的响应操作,支持打开应用、打开网页和打开应用内指定界面,更多详情请参见 配置点击通知栏消息事件
当设置为【打开应用】或【打开应用内指定界面】操作时,支持 透传自定义内容。
- 单击【保存】保存信息,证书信息保存后10分钟内生效。
- 待推送证书信息生成后,记录证书的
ID
。
步骤3:集成推送 SDK
说明:
- 即时通信 IM 默认推送的通知标题为
a new message
。- 阅读此小节前,请确保您已经正常集成并使用即时通信 IM SDK。
- 您可以在我们的 demo 里找到华为推送的实现示例,请注意:华为推送版本更新时有可能会有功能调整,若您发现本节内容存在差异,烦请您及时查阅 华为推送官网,并将文档信息差异反馈给我们,我们会及时跟进修改。
步骤3.1:下载华为推送 SDK 并添加引用
- 访问 华为推送官网 下载HMS Agent 套件。
- 解压 HMS Agent 套件。
- 将
hmsagents\src\main\java
文件夹内的文件拷贝到您项目的 src\main\java 目录中。 - 通过 Gradle 进行华为推送 SDK 集成,在您项目的 build.gradle 里添加以下代码:
allprojects { repositories { jcenter() maven {url 'http://developer.huawei.com/repo/'} } }
- 在子项目的 build.gradle 里添加以下信息:
dependencies { // 华为推送 SDK,2.6.3.301可替换成实际所需要的版本 implementation 'com.huawei.android.hms:push:2.6.3.301' // 如果碰到报错:com.huawei.hms.api 不存在,这条也需要加上,注意版本号必须相同 // implementation 'com.huawei.android.hms:base:2.6.3.301' }
步骤3.2:配置 AndroidManifest.xml 文件
- 添加华为推送的必要权限:
<!--HMS-SDK 引导升级 HMS 功能,访问 OTA 服务器需要网络权限-->
<uses-permission android:name="android.permission.INTERNET" />
<!--HMS-SDK 引导升级 HMS 功能,保存下载的升级包需要 SD 卡写权限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--检测网络状态-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!--检测 Wi-Fi 状态-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!--为了获取用户手机的 IMEI,用来唯一的标识用户。-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!--如果是Android 8.0,应用编译配置的 targetSdkVersion>=26,请务必添加以下权限 -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<!--这里的 com.tencent.qcloud.tim.tuikit 改成您的 App 的包名-->
<permission
android:name="com.tencent.qcloud.tim.tuikit.permission.PROCESS_PUSH_MSG"
android:protectionLevel="signatureOrSystem"/>
<uses-permission android:name="com.tencent.qcloud.tim.tuikit.permission.PROCESS_PUSH_MSG" />
<!--这里的 com.tencent.qcloud.tim.tuikit 改成您的 App 的包名-->
- 在 application 下增加以下内容,具体说明请参见 华为推送官网。
<meta-data
android:name="com.huawei.hms.client.appid"
android:value="appid=1234567890"/> <!--这里的 appid 值修改为您的华为推送 App ID-->
<provider
android:name="com.huawei.hms.update.provider.UpdateProvider"
android:authorities="com.tencent.qcloud.tim.tuikit.hms.update.provider"
android:exported="false"
android:grantUriPermissions="true"/>
<provider
android:name="com.huawei.updatesdk.fileprovider.UpdateSdkFileProvider"
android:authorities="com.tencent.qcloud.tim.tuikit.updateSdk.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
</provider>
<activity
android:name="com.huawei.android.hms.agent.common.HMSAgentActivity"
android:configChanges="orientation|locale|screenSize|layoutDirection|fontScale"
android:excludeFromRecents="true"
android:exported="false"
android:hardwareAccelerated="true"
android:theme="@android:style/Theme.Translucent" >
<meta-data
android:name="hwc-theme"
android:value="androidhwext:style/Theme.Emui.Translucent" />
</activity>
<activity
android:name="com.huawei.hms.activity.BridgeActivity"
android:configChanges="orientation|locale|screenSize|layoutDirection|fontScale"
android:excludeFromRecents="true"
android:exported="false"
android:hardwareAccelerated="true"
android:theme="@android:style/Theme.Translucent" >
<meta-data
android:name="hwc-theme"
android:value="androidhwext:style/Theme.Emui.Translucent" />
</activity>
<service
android:name="com.huawei.hms.support.api.push.service.HmsMsgService"
android:enabled="true"
android:exported="true"
android:process=":pushservice">
<intent-filter>
<action android:name="com.huawei.push.msg.NOTIFY_MSG" />
<action android:name="com.huawei.push.msg.PASSBY_MSG" />
</intent-filter>
</service>
步骤3.3:自定义一个 BroadcastReceiver 类
为了接收消息,您需要自定义一个继承自PushReceiver
类的 BroadcastReceiver,我们只需要实现其中的onToken
方法,然后将此 receiver 注册到 AndroidManifest.xml 中。
以下为 Demo 中的示例代码:
public class HUAWEIPushReceiver extends PushReceiver {
private static final String TAG = "HUAWEIPushReceiver";
@Override
public void onToken(Context context, String token, Bundle extras) {
Log.i(TAG, "onToken:" + token);
ThirdPushTokenMgr.getInstance().setThirdPushToken(token); // token 在此处传入,后续推送信息上报时需要使用
ThirdPushTokenMgr.getInstance().setPushTokenToTIM();
}
}
将自定义的 BroadcastReceiver 注册到 AndroidManifest.xml:
<!--这里的 com.tencent.qcloud.tim.demo.thirdpush.HUAWEIPushReceiver 修改成您 App 中的完整类名-->
<receiver android:name="com.tencent.qcloud.tim.demo.thirdpush.HUAWEIPushReceiver"
android:permission="com.tencent.qcloud.tim.tuikit.permission.PROCESS_PUSH_MSG">
<intent-filter>
<!-- 必须,用于接收 token -->
<action android:name="com.huawei.android.push.intent.REGISTRATION" />
<!-- 必须, 用于接收透传消息 -->
<action android:name="com.huawei.android.push.intent.RECEIVE" />
<!-- 必须, 用于接收通知栏消息点击事件 此事件不需要开发者处理,只需注册就可以-->
<action android:name="com.huawei.intent.action.PUSH_DELAY_NOTIFY"/>
</intent-filter>
</receiver>
步骤3.4:在 App 中注册华为推送服务
如果您选择启用华为推送服务,需要在 Application 的onCreate
中调用HMSAgent.init
来对华为推送服务进行初始化。
注册成功后,您将在 步骤3.3 自定义的 BroadcastReceiver 的onToken
中收到注册结果。其中token
为当前设备上当前 App 的唯一标识,请记录token
信息。
以下为 Demo 中的示例代码:
public class DemoApplication extends Application {
private static PojoApplication instance;
@Override
public void onCreate() {
super.onCreate();
// 判断是否是在主线程
if (SessionWrapper.isMainProcess(getApplicationContext())) {
/**
* TUIKit 的初始化函数
*
* @param context 应用的上下文,一般为对应应用的 ApplicationContext
* @param sdkAppID 您在腾讯云注册应用时分配的 SDKAppID
* @param configs TUIKit 的相关配置项,一般使用默认即可,需特殊配置参考 API 文档
*/
long current = System.currentTimeMillis();
TUIKit.init(this, Constants.SDKAPPID, BaseUIKitConfigs.getDefaultConfigs());
System.out.println(">>>>>>>>>>>>>>>>>>"+(System.currentTimeMillis()-current));
// 添加自定初始化配置
customConfig();
System.out.println(">>>>>>>>>>>>>>>>>>"+(System.currentTimeMillis()-current));
if(IMFunc.isBrandXiaoMi()){
// 小米离线推送
MiPushClient.registerPush(this, Constants.XM_PUSH_APPID, Constants.XM_PUSH_APPKEY);
}
if(IMFunc.isBrandHuawei()){
// 华为离线推送
HMSAgent.init(this);
}
if(MzSystemUtils.isBrandMeizu(this)){
// 魅族离线推送
PushManager.register(this, Constants.MZ_PUSH_APPID, Constants.MZ_PUSH_APPKEY);
}
if(IMFunc.isBrandVivo()){
// vivo 离线推送
PushClient.getInstance(getApplicationContext()).initialize();
}
}
instance = this;
}
}
在主界面中获取 token:
if (IMFunc.isBrandHuawei()) {
// 华为离线推送
HMSAgent.connect(this, new ConnectHandler() {
@Override
public void onConnect(int rst) {
QLog.i(TAG, "huawei push HMS connect end:" + rst);
}
});
getHuaWeiPushToken();
}
步骤4:上报推送信息至即时通信 IM 服务端
若您需要通过华为推送进行即时通信 IM 消息的推送通知,必须在用户登录成功后通过TIMManager
中的setOfflinePushToken
方法将您托管到即时通信 IM 控制台生成的证书 ID 及华为推送服务返回的 token 上报到即时通信 IM 服务端。
注意:正确上报 token 与证书 ID 后,即时通信 IM 服务才能将用户与对应的设备信息绑定,从而使用华为推送服务进行推送通知。
以下为 Demo 中的示例代码:
- 定义证书 ID 常量
/**
* 我们先定义一些常量信息在 Constants.java
*/
/****** 华为离线推送参数 start ******/
// 使用您在即时通信 IM 控制台上华为推送证书信息里的证书 ID
public static final long HW_PUSH_BUZID = 6666;
// 华为开发者联盟给应用分配的应用 APPID
public static final String HW_PUSH_APPID = "1234567890"; // 见清单文件
/****** 华为离线推送参数 end ******/
- 上报推送的证书 ID 及 token
/**
* 在 ThirdPushTokenMgr.java 中对推送的证书 ID 及设备信息进行上报操作
*/
public class ThirdPushTokenMgr {
private static final String TAG = "ThirdPushTokenMgr";
private String mThirdPushToken;
public static ThirdPushTokenMgr getInstance () {
return ThirdPushTokenHolder.instance;
}
private static class ThirdPushTokenHolder {
private static final ThirdPushTokenMgr instance = new ThirdPushTokenMgr();
}
public void setThirdPushToken(String mThirdPushToken) {
this.mThirdPushToken = mThirdPushToken; // token 在此处传值,结合上文自定义 BroadcastReciever 类文档说明
}
public void setPushTokenToTIM(){
String token = ThirdPushTokenMgr.getInstance().getThirdPushToken();
if(TextUtils.isEmpty(token)){
QLog.i(TAG, "setPushTokenToTIM third token is empty");
mIsTokenSet = false;
return;
}
TIMOfflinePushToken param = null;
if(IMFunc.isBrandXiaoMi()){ // 判断厂商品牌,根据不同厂商选择不同的推送服务
param = new TIMOfflinePushToken(Constants.XM_PUSH_BUZID, token);
}else if(IMFunc.isBrandHuawei()){
param = new TIMOfflinePushToken(Constants.HW_PUSH_BUZID, token);
}else if(IMFunc.isBrandMeizu()){
param = new TIMOfflinePushToken(Constants.MZ_PUSH_BUZID, token);
}else if(IMFunc.isBrandOppo()){
param = new TIMOfflinePushToken(Constants.OPPO_PUSH_BUZID, token);
}else if(IMFunc.isBrandVivo()){
param = new TIMOfflinePushToken(Constants.VIVO_PUSH_BUZID, token);
}else{
return;
}
TIMManager.getInstance().setOfflinePushToken(param, new TIMCallBack() {
@Override
public void onError(int code, String desc) {
Log.d(TAG, "setOfflinePushToken err code = " + code);
}
@Override
public void onSuccess() {
Log.d(TAG, "setOfflinePushToken success");
mIsTokenSet = true;
}
});
}
}
步骤5:离线推送
成功上报证书 ID 及 token 后,即时通信 IM 服务端会在该设备上的即时通信 IM 用户 logout 之前、App 被 kill 之后,将消息通过华为推送通知到用户端。
说明:
- 华为推送并非100%必达。
- 华为推送可能会有一定延时,通常与 App 被 kill 的时机有关,部分情况下与华为推送服务有关。
- 若即时通信 IM 用户已经 logout 或被即时通信 IM 服务端主动下线(例如在其他端登录被踢等情况),则该设备上不会再收到消息推送。
配置点击通知栏消息事件
您可以选择点击通知栏消息后打开应用、打开网页或打开应用内指定界面。
打开应用
默认为点击通知栏消息打开应用。
打开网页
您需要在 添加证书 时选择【打开网页】并输入以http://
或https://
开头的网址,例如https://cloud.tencent.com/document/product/269
。
打开应用内指定界面
在 manifest 中配置需要打开的 Activity 的
intent-filter
,示例代码如下:<activity android:name="com.tencent.qcloud.tim.demo.chat.ChatActivity" android:launchMode="singleTask" android:screenOrientation="portrait" android:windowSoftInputMode="adjustResize|stateHidden"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <data android:host="com.tencent.qcloud.tim" android:path="/detail" android:scheme="pushscheme" /> </intent-filter> </activity>
获取 intent URL,方式如下:
Intent intent = new Intent(this, ChatActivity.class); intent.setData(Uri.parse("pushscheme://com.tencent.qcloud.tim/detail")); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); String intentUri = intent.toUri(Intent.URI_INTENT_SCHEME); Log.i(TAG, "intentUri = " + intentUri); // 打印结果 intent://com.tencent.qcloud.tim/detail#Intent;scheme=pushscheme;launchFlags=0x4000000;component=com.tencent.qcloud.tim.tuikit/com.tencent.qcloud.tim.demo.chat.ChatActivity;end
在 添加证书 时选择【打开应用内指定界面】并输入上述打印结果。
透传自定义内容
添加证书 时设置【点击通知后】为【打开应用】或【打开应用内指定界面】操作才支持透传自定义内容。
步骤1:发送端设置自定义内容
在发消息前设置每条消息的通知栏自定义内容。
Android 端示例:
String extContent = "ext content"; TIMMessageOfflinePushSettings settings = new TIMMessageOfflinePushSettings(); settings.setExt(extContent.getBytes()); timMessage.setOfflinePushSettings(settings); mConversation.sendMessage(false, timMessage, callback);
服务端示例请参见 OfflinePushInfo 的格式示例。
步骤2:接收端获取自定义内容
点击通知栏的消息时,客户端在相应的 Activity
中获取自定义内容。
Bundle bundle = getIntent().getExtras();
String extContent = bundle.get("ext");
常见问题
如果应用使用了混淆,如何防止华为离线推送功能异常?
如果您的应用使用了混淆,为了防止华为离线推送功能异常,您需要 keep 自定义的 BroadcastReceiver,参考添加以下混淆规则:
说明:以下代码为华为官方示例,请根据实际情况修改后再使用。
-ignorewarning
-keepattributes *Annotation*
-keepattributes Exceptions
-keepattributes InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
-keep class com.hianalytics.android.**{*;}
-keep class com.huawei.updatesdk.**{*;}
-keep class com.huawei.hms.**{*;}
-keep class com.huawei.android.hms.agent.**{*;}
# 请将 com.tencent.qcloud.tim.demo.thirdpush.HUAWEIPushReceiver 改成您 App 中定义的完整类名
-keep com.tencent.qcloud.tim.demo.thirdpush.HUAWEIPushReceiver {*;}
能否自定义配置推送提示音?
目前华为推送不支持自定义的提示音。
收不到推送时,如何排查问题?
- 任何推送都不是100%必达,厂商推送也不例外。因此,若在快速、连续的推送过程中偶现一两条推送未通知提醒,通常是由厂商推送频控的限制引起。
- 按照推送的流程,确认华为推送证书信息是否正确配置在 即时通信 IM 控制台 中。
- 确认您的项目 集成华为推送 SDK 的配置正确,并正常获取到了 token。
- 确认您已将正确的 推送信息上报 至即时通信 IM 服务端。
- 在设备中手动 kill App,发送若干条消息,确认是否能在一分钟内接收到通知。