このページは現在英語版のみで提供されており、日本語版も近日中に提供される予定です。ご利用いただきありがとうございます。

Android

Note:
Self-integrated push only supports regular message push and is no longer maintained. It is strongly recommended to use the Push Plugin (TIMPush), which requires only simple configuration for one-click integration with multiple vendors' push services. It supports not only regular message push but also full-member push and user tag-based push. It offers complete push lifecycle query, data statistics, troubleshooting, and other features, providing you with a stable, timely, and diverse one-stop comprehensive push service.
This article aims to introduce how to self-integrate various vendor push services.

Running the demo for offline push

Step 1. Register your app with vendor push platforms

The offline push feature depends on vendors' original channels. You need to register your app with each vendor's push platform to obtain parameters such as AppID and AppKey. Currently, mobile phone vendors supported inside the Chinese mainland are: Mi, Huawei, HONOR, OPPO, vivo, Meizu, and the mobile phone vendor supported outside the Chinese mainland is Google FCM.

Step 2. Create resources in the IM console

Log in to the Tencent Cloud Chat Console, add the push certificates for each vendor, and configure the AppId, AppKey, AppSecret, and other parameters obtained in step 1 to the push certificates in the IM console. For action after click, refer to step 3.
Open the specified interface within the app: clicking the notification bar will redirect the interface based on the configured self Definition, see Custom Redirect on Click.
Mi
Huawei
OPPO
vivo
Meizu
HONOR
Google FCM
Vendor Push Platform
Configuring in the IM console






Vendor Push Platform
Configuring in the IM console






Notes:
Client ID corresponds to AppID, Client Secret corresponds to AppSecret.
Vendor Push Platform
Configuring in the IM console






Vendor Push Platform
Configuring in the IM console






Vendor Push Platform
Configuring in the IM console






Vendor Push Platform
Configuring in the IM console






Vendor Push Platform
Configuring in the IM console






Note
For Xiaomi, if you have configured the ChannelID on the vendor's developer website, you need to configure the same ChannelID in the Chat Console, otherwise the push may fail.

Step 3. Configure the redirected-to page for offline push

An offline push message received will be displayed in the notification bar as shown in the figure below. You can click the notification bar to open the app and go to the redirected-to page configured. Follow the steps below to configure the activities to be redirected to upon notification message clicking.
Console configuration
The redirected-to page configuration varies by vendor as follows:
Vendor
Action after Click
Specified In-app Page
Mi
Open the specified in-app page
intent://your hostname/your path#Intent;scheme=your protocol, that is, the scheme you defined;launchFlags=0x4000000;component=complete class name of the page to which your app is to be redirected;endTUIKit demo configuration: intent://com.tencent.qcloud/detail#Intent;scheme=pushscheme;launchFlags=0x4000000;component=com.tencent.qcloud.tim.tuikit/com.tencent.qcloud.tim.demo.main.MainActivity;end
Huawei
Open the specified in-app page
intent://your hostname/your path#Intent;scheme=your protocol, that is, the scheme you defined;launchFlags=0x4000000;component=complete class name of the page to which your app is to be redirected;endTUIKit demo configuration: intent://com.tencent.qcloud/detail#Intent;scheme=pushscheme;launchFlags=0x4000000;component=com.tencent.qcloud.tim.tuikit/com.tencent.qcloud.tim.demo.main.MainActivity;end
HONOR
Open the specified in-app page
intent://your hostname/your path#Intent;scheme=your protocol, that is, the scheme you defined;launchFlags=0x4000000;component=complete class name of the page to which your app is to be redirected;endTUIKit demo configuration: intent://com.tencent.qcloud/detail#Intent;scheme=pushscheme;launchFlags=0x4000000;component=com.tencent.qcloud.tim.tuikit/com.tencent.qcloud.tim.demo.main.MainActivity;end
Meizu
Open the specified in-app page
Complete class name of the page to which your app is to be redirectedTUIKit demo configuration: com.tencent.qcloud.tim.demo.main.MainActivity
OPPO
Open the specified in-app page
Complete class name of the page to which your app is to be redirectedTUIKit demo configuration: activity: com.tencent.qcloud.tim.demo.main.MainActivity
vivo
Open the specified in-app page
intent://your hostname/your path#Intent;scheme=your protocol, that is, the scheme you defined;launchFlags=0x4000000;component=complete class name of the page to which your app is to be redirected;endTUIKit demo configuration: intent://com.tencent.qcloud/detail#Intent;scheme=pushscheme;launchFlags=0x4000000;component=com.tencent.qcloud.tim.tuikit/com.tencent.qcloud.tim.demo.main.MainActivity;end
Google FCM
No need to configure
Redirect to the Launcher page of the app by default
Manifest File Configuration
In the app project manifest file AndroidManifest.xml, configure the redirected-to page parameters. Please note that this configuration must be consistent with the Action after Click configured in the IM console.
<!-- The jump interface configured by TUIKitDemo is MainActivity, so fill in com.tencent.qcloud.tim.demo.main.MainActivity here. After integrating into your application, you need to replace it with the complete class name of your application's interface. -->
<activity
android:name="Complete class name of the page to which your app is to be redirected"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize|stateHidden">

<!-- Open in-app page for offline push -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- TUIKitDemo is configured as: pushscheme://com.tencent.qcloud/detail -->
<data
android:host="Your hostname"
android:path="Your path"
android:scheme="Your protocol, i.e., the scheme you defined" />
</intent-filter>

</activity>

Step 4. Set vendor push rules

Application Offline Parameter Configuration
Step 2 After successfully adding the push certificate, the IM console will assign a certificate ID for the corresponding vendor. Please save it locally. When registering the push service after login, provide the obtained vendor token and the certificate ID to the backend through the API setOfflinePushConfig. Take Xiaomi as an example:
The push certificate ID is as follows:

Save the certificate ID and push parameters locally:
public class PrivateConstants {
/****** Mi offline push parameters start ******/
// Certificate ID generated after uploading a third-party push certificate in the Tencent Cloud console
public static final long XM_PUSH_BUZID = ID of the certificate assigned to your application
// `APPID` and `APPKEY` assigned by the Mi open platform
public static final String XM_PUSH_APPID = "`APPID` of the certificate assigned to your application";
public static final String XM_PUSH_APPKEY = "`APPKEY` of the certificate assigned to your application";
/****** Mi offline push parameters end ******/
}
Manifest File Configuration for Vendor Push Permissions
The manifest file needs to include the push rules and push inheritance classes for each vendor, as follows:
Mi
Huawei
HONOR
OPPO
vivo
Meizu
Google FCM
<!-- Note: The applicationId of TUIKitDemo is com.tencent.qcloud.tim.tuikit. The "xxxx" here needs to be replaced with the applicationId of your application. -->

<!-- ********Mi Push Permission Settings******** -->
<permission
android:name="xxxx.permission.MIPUSH_RECEIVE"
android:protectionLevel="signature" />

<uses-permission android:name="xxxx.permission.MIPUSH_RECEIVE" />

<!-- ********Mi Push service and receiver settings start******** -->
<service
android:name="com.xiaomi.push.service.XMPushService"
android:enabled="true"
android:process=":pushservice" />
<service
android:name="com.xiaomi.push.service.XMJobService"
android:enabled="true"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE"
android:process=":pushservice" />
<!-- Note: This service must be included in version 3.0.1 and later (including version 3.0.1) -->
<service
android:name="com.xiaomi.mipush.sdk.PushMessageHandler"
android:enabled="true"
android:exported="true" />
<service
android:name="com.xiaomi.mipush.sdk.MessageHandleService"
android:enabled="true" />
<!-- Note: This service must be included in version 2.2.5 and later (including version 2.2.5) -->
<receiver
android:name="com.xiaomi.push.service.receivers.NetworkStatusReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver
android:name="com.xiaomi.push.service.receivers.PingReceiver"
android:exported="false"
android:process=":pushservice">
<intent-filter>
<action android:name="com.xiaomi.push.PING_TIMER" />
</intent-filter>
</receiver>
<!-- Self-implement MI push reception broadcast -->
<receiver
android:name="xxxx.XiaomiMsgReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.xiaomi.mipush.RECEIVE_MESSAGE" />
</intent-filter>
<intent-filter>
<action android:name="com.xiaomi.mipush.MESSAGE_ARRIVED" />
</intent-filter>
<intent-filter>
<action android:name="com.xiaomi.mipush.ERROR" />
</intent-filter>
</receiver>
<!-- ********Mi Push service and receiver settings end******** -->
<!-- Note: The applicationId of TUIKitDemo is com.tencent.qcloud.tim.tuikit. The "xxxx" here needs to be replaced with the applicationId of your application. -->

<!-- ********Huawei Push Permission Settings******** -->
<permission
android:name="xxxx.permission.PROCESS_PUSH_MSG"
android:protectionLevel="signatureOrSystem" />
<uses-permission android:name="com.huawei.android.launcher.permission.CHANGE_BADGE" />
<uses-permission android:name="xxxx.permission.PROCESS_PUSH_MSG" />

<!-- ********Huawei Push Settings start******** -->
<service
android:name="xxxx.HUAWEIHmsMessageService"
android:exported="false">
<intent-filter>
<action android:name="com.huawei.push.action.MESSAGING_EVENT"/>
</intent-filter>
</service>
<!-- ********Huawei Push Settings end******** -->
<!-- ********HONOR Push Settings start******** -->
<service
android:name="xxxx.MyHonorMessageService"
android:exported="false">
<intent-filter>
<action android:name="com.hihonor.push.action.MESSAGING_EVENT" />
</intent-filter>
</service>
<!-- ********HONOR Push Settings end******** -->
<!-- ********OPPO Push Permission Settings******** -->
<uses-permission android:name="com.coloros.mcs.permission.RECIEVE_MCS_MESSAGE" />
<uses-permission android:name="com.heytap.mcs.permission.RECIEVE_MCS_MESSAGE" />

<!-- ********OPPO Push start******** -->
<service
android:name="com.heytap.msp.push.service.CompatibleDataMessageCallbackService"
android:permission="com.coloros.mcs.permission.SEND_MCS_MESSAGE">
<intent-filter>
<action android:name="com.coloros.mcs.action.RECEIVE_MCS_MESSAGE" />
</intent-filter>
</service>
<!-- Compatible with versions below Q -->
<service
android:name="com.heytap.msp.push.service.DataMessageCallbackService"
android:permission="com.heytap.mcs.permission.SEND_PUSH_MESSAGE">
<intent-filter>
<action android:name="com.heytap.mcs.action.RECEIVE_MCS_MESSAGE" />
<action android:name="com.heytap.msp.push.RECEIVE_MCS_MESSAGE" />
</intent-filter>
</service>
<!-- Compatible with Q version -->
<!-- ********OPPO Push end******** -->
<!-- ********vivo Push Settings start******** -->
<service
android:name="com.vivo.push.sdk.service.CommandClientService"
android:exported="true" />
<activity
android:name="com.vivo.push.sdk.LinkProxyClientActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
<!-- push application defines message receiver declaration -->
<receiver android:name="xxxx.VIVOPushMessageReceiverImpl">
<intent-filter>
<!-- receive push message -->
<action android:name="com.vivo.pushclient.action.RECEIVE" />
</intent-filter>
</receiver>
<!-- ********vivo Push Settings end******** -->
<!-- Note: The applicationId of TUIKitDemo is com.tencent.qcloud.tim.tuikit. The "xxxx" here needs to be replaced with the applicationId of your application. -->

<!-- Compatible with Flyme 3.0 configuration permissions -->
<permission
android:name="xxxx.permission.C2D_MESSAGE"
android:protectionLevel="signature" />

<uses-permission android:name="com.meizu.c2dm.permission.RECEIVE" />
<uses-permission android:name="xxxx.permission.C2D_MESSAGE" />

<!-- ********Meizu Push Settings start******** -->
<receiver android:name="xxxx.MEIZUPushReceiver">
<intent-filter>
<!-- receive push message -->
<action android:name="com.meizu.flyme.push.intent.MESSAGE" />
<!-- receive register message -->
<action android:name="com.meizu.flyme.push.intent.REGISTER.FEEDBACK" />
<!-- receive unregister message -->
<action android:name="com.meizu.flyme.push.intent.UNREGISTER.FEEDBACK" />
<!-- Compatible with lower version Flyme 3 push service configuration -->
<action android:name="com.meizu.c2dm.intent.REGISTRATION" />
<action android:name="com.meizu.c2dm.intent.RECEIVE" />

<category android:name="com.tencent.qcloud.tim.demo.thirdpush" />
</intent-filter>
</receiver>
<!-- ********Meizu Push Settings end******** -->
<!-- Note: The applicationId of TUIKitDemo is com.tencent.qcloud.tim.tuikit. The "xxxx" here needs to be replaced with the applicationId of your application. -->

<!-- ********Overseas Google Cloud Messaging start******** -->
<service
android:name="xxxx.GoogleFCMMsgService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<!-- ********Overseas Google Cloud Messaging end******** -->
vivo and Honor adaptation
According to the access guidelines of vivo and Honor, APPID and APPKEY need to be added to the manifest file, otherwise, compilation issues may occur:
Method 1
Method 2
android {
...
defaultConfig {
...
manifestPlaceholders = [
"VIVO_APPKEY" : "`APPKEY` of the certificate assigned to your application",
"VIVO_APPID" : "`APPID` of the certificate assigned to your application"
"HONOR_APPID" : "`APPID` of the certificate assigned to your application"
]
}
}
// vivo begin
<receiver android:name="com.tencent.qcloud.tim.demo.thirdpush.VIVOPushMessageReceiverImpl">
<intent-filter>
<!-- receive push message -->
<action android:name="com.vivo.pushclient.action.RECEIVE" />
</intent-filter>
</receiver>

<meta-data tools:replace="android:value"
android:name="com.vivo.push.api_key"
android:value="`APPKEY` of the certificate assigned to your application" />
<meta-data tools:replace="android:value"
android:name="com.vivo.push.app_id"
android:value="`APPID` of the certificate assigned to your application" />
// vivo end

// honor begin
<service
android:name="com.tencent.qcloud.tim.tuiofflinepush.oempush.MyHonorMessageService"
android:exported="false">
<intent-filter>
<action android:name="com.hihonor.push.action.MESSAGING_EVENT" />
</intent-filter>
</service>

<meta-data tools:replace="android:value"
android:name="com.hihonor.push.app_id"
android:value="`APPID` of the certificate assigned to your application" />
// honor end
Adaptation to Huawei and Google FCM
Huawei and Google FCM need to integrate the corresponding plugin and JSON configuration files by the vendor's methods.
1.1 Download the configuration file and place it under the root directory of the project.
Huawei
Google FCM






1.2 Add the following configuration under buildscript -> dependencies in your project-level build.gradle file:
classpath 'com.google.gms:google-services:4.2.0'
classpath 'com.huawei.agconnect:agcp:1.4.1.300'
Add the following configuration under allprojects -> repositories in your project-level build.gradle file:
mavenCentral()
// Configure the Maven repository address for HMS Core SDK.
maven {url 'https://developer.huawei.com/repo/'}
The effect after addition is as follows:
repositories {
...
// Configure the Maven repository address for HMS Core SDK.
maven {url 'https://developer.huawei.com/repo/'}
}

dependencies {
...
classpath 'com.google.gms:google-services:4.2.0'
classpath 'com.huawei.agconnect:agcp:1.4.1.300'
}
1.3 Add the following configuration in the app-level build.gradle file.
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.huawei.agconnect'
1.4 Click Sync Now at the top right corner of the project to sync the project.

Step 5. Integrate the vendor push SDK

Integrate SDK
Add the vendor push SDK in the app's build.gradle file.
dependencies {
......
// Huawei
implementation 'com.tencent.timpush:huawei:7.7.5282'
// Google FCM
implementation 'com.tencent.timpush:fcm:7.7.5282'
// Mi
implementation 'com.tencent.timpush:xiaomi:7.7.5282'
// OPPO
implementation 'com.tencent.timpush:oppo:7.7.5282'
// vivo
implementation 'com.tencent.timpush:vivo:7.7.5282'
// honor
implementation 'com.tencent.timpush:honor:7.7.5282'
// Meizu
implementation 'com.tencent.timpush:meizu:7.7.5282'
}
Add Push Class
Include the vendor push classes. The methods are specific to vendors as follows:
Mi
Huawei
HONOR
OPPO
vivo
Meizu
Google FCM
package xxx.xxx.xxx;
import android.content.Context;
import android.text.TextUtils;
import com.tencent.qcloud.tim.tuiofflinepush.utils.TUIOfflinePushErrorBean;
import android.util.Log;
import com.xiaomi.mipush.sdk.ErrorCode;
import com.xiaomi.mipush.sdk.MiPushClient;
import com.xiaomi.mipush.sdk.MiPushCommandMessage;
import com.xiaomi.mipush.sdk.MiPushMessage;
import com.xiaomi.mipush.sdk.PushMessageReceiver;
import java.util.List;
import java.util.Map;

public class XiaomiMsgReceiver extends PushMessageReceiver {
private static final String TAG = XiaomiMsgReceiver.class.getSimpleName();
private String mRegId;

@Override
public void onReceivePassThroughMessage(Context context, MiPushMessage miPushMessage) {
Log.d(TAG, "onReceivePassThroughMessage is called. ");
}

@Override
public void onNotificationMessageClicked(Context context, MiPushMessage miPushMessage) {
Log.d(TAG, "onNotificationMessageClicked miPushMessage " + miPushMessage.toString());

if (OEMPushSetting.mPushCallback == null) {
return;
}

Map<String, String> extra = miPushMessage.getExtra();
String ext = extra.get("ext");
if (TextUtils.isEmpty(ext)) {
Log.w(TAG, "onNotificationMessageClicked: no extra data found");
return;
}
// When "Open Application" is selected in the IM console, clicking the notification bar will trigger this callback
}

@Override
public void onNotificationMessageArrived(Context context, MiPushMessage miPushMessage) {
Log.d(TAG, "onNotificationMessageArrived is called. ");
}

@Override
public void onReceiveRegisterResult(Context context, MiPushCommandMessage miPushCommandMessage) {
Log.d(TAG, "onReceiveRegisterResult is called. " + miPushCommandMessage.toString());
String command = miPushCommandMessage.getCommand();
List<String> arguments = miPushCommandMessage.getCommandArguments();
String cmdArg1 = ((arguments != null && arguments.size() > 0) ? arguments.get(0) : null);

Log.d(TAG,
"cmd: " + command + " | arg: " + cmdArg1 + " | result: " + miPushCommandMessage.getResultCode() + " | reason: " + miPushCommandMessage.getReason());

if (MiPushClient.COMMAND_REGISTER.equals(command)) {
if (miPushCommandMessage.getResultCode() == ErrorCode.SUCCESS) {
mRegId = cmdArg1;
}
}

Log.d(TAG, "regId: " + mRegId);
// Call the API to report to the IM backend after obtaining the token
}

@Override
public void onCommandResult(Context context, MiPushCommandMessage miPushCommandMessage) {
super.onCommandResult(context, miPushCommandMessage);
}
}
package xxx.xxx.xxx;

import com.huawei.hms.push.HmsMessageService;
import com.huawei.hms.push.RemoteMessage;
import com.tencent.qcloud.tim.tuiofflinepush.TUIOfflinePushConfig;
import com.tencent.qcloud.tim.tuiofflinepush.utils.TUIOfflinePushErrorBean;
import android.util.Log;

public class HUAWEIHmsMessageService extends HmsMessageService {
private static final String TAG = HUAWEIHmsMessageService.class.getSimpleName();

@Override
public void onMessageReceived(RemoteMessage message) {
Log.i(TAG, "onMessageReceived message=" + message);
}

@Override
public void onMessageSent(String msgId) {
Log.i(TAG, "onMessageSent msgId=" + msgId);
}

@Override
public void onSendError(String msgId, Exception exception) {
Log.i(TAG, "onSendError msgId=" + msgId);
}

@Override
public void onNewToken(String token) {
Log.i(TAG, "onNewToken token=" + token);
// Call the API to report to the IM backend after obtaining the token

}

@Override
public void onTokenError(Exception exception) {
Log.i(TAG, "onTokenError exception=" + exception);
}

@Override
public void onMessageDelivered(String msgId, Exception exception) {
Log.i(TAG, "onMessageDelivered msgId=" + msgId);
}
}

package xxx.xxx.xxx;
import android.text.TextUtils;
import com.hihonor.push.sdk.HonorMessageService;
import com.hihonor.push.sdk.bean.DataMessage;
import android.util.Log;

public class MyHonorMessageService extends HonorMessageService {
private static final String TAG = MyHonorMessageService.class.getSimpleName();

@Override
public void onNewToken(String token) {
Log.i(TAG, "onNewToken token=" + token);

if (TextUtils.isEmpty(token)) {
return;
}

// Call the API to report to the IM backend after obtaining the token

}

@Override
public void onMessageReceived(DataMessage dataMessage) {
Log.i(TAG, "onMessageReceived message=" + dataMessage);
}
}
package xxx.xxx.xxx;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
import com.heytap.msp.push.callback.ICallBackResultService;
import com.tencent.qcloud.tim.tuiofflinepush.utils.TUIOfflinePushErrorBean;
import android.util.Log;

public class OPPOPushImpl implements ICallBackResultService {
private static final String TAG = OPPOPushImpl.class.getSimpleName();

@Override
public void onRegister(int responseCode, String registerID) {
Log.i(TAG, "onRegister responseCode: " + responseCode + " registerID: " + registerID);

if (responseCode != 0) {
// Print error
} else {
// Call the API to report to the IM backend after obtaining the token
}
}

@Override
public void onUnRegister(int responseCode) {
Log.i(TAG, "onUnRegister responseCode: " + responseCode);
}

@Override
public void onSetPushTime(int responseCode, String s) {
Log.i(TAG, "onSetPushTime responseCode: " + responseCode + " s: " + s);
}

@Override
public void onGetPushStatus(int responseCode, int status) {
Log.i(TAG, "onGetPushStatus responseCode: " + responseCode + " status: " + status);
}

@Override
public void onGetNotificationStatus(int responseCode, int status) {
Log.i(TAG, "onGetNotificationStatus responseCode: " + responseCode + " status: " + status);
}

@Override
public void onError(int i, String s) {
Log.i(TAG, "onError code: " + i + " string: " + s);
}
}

package xxx.xxx.xxx;
import android.content.Context;
import android.util.Log;
import com.vivo.push.model.UPSNotificationMessage;
import com.vivo.push.sdk.OpenClientPushMessageReceiver;
import java.util.Map;

public class VIVOPushMessageReceiverImpl extends OpenClientPushMessageReceiver {
private static final String TAG = VIVOPushMessageReceiverImpl.class.getSimpleName();

private static String sExt = "";

@Override
public void onNotificationMessageClicked(Context context, UPSNotificationMessage upsNotificationMessage) {
Log.i(TAG, "onNotificationMessageClicked upsNotificationMessage " + upsNotificationMessage.toString());
Map<String, String> extra = upsNotificationMessage.getParams();
sExt = extra.get("ext");
}

public static String getParams() {
String tmp = sExt;
sExt = "";
return tmp;
}

@Override
public void onReceiveRegId(Context context, String regId) {
Log.i(TAG, "onReceiveRegId = " + regId);
}
}
package xxx.xxx.xxx;
import android.content.Context;
import android.content.Intent;
import com.meizu.cloud.pushsdk.MzPushMessageReceiver;
import com.meizu.cloud.pushsdk.handler.MzPushMessage;
import com.meizu.cloud.pushsdk.notification.PushNotificationBuilder;
import com.meizu.cloud.pushsdk.platform.message.PushSwitchStatus;
import com.meizu.cloud.pushsdk.platform.message.RegisterStatus;
import com.meizu.cloud.pushsdk.platform.message.SubAliasStatus;
import com.meizu.cloud.pushsdk.platform.message.SubTagsStatus;
import com.meizu.cloud.pushsdk.platform.message.UnRegisterStatus;
import android.util.Log;

public class MEIZUPushReceiver extends MzPushMessageReceiver {
private static final String TAG = MEIZUPushReceiver.class.getSimpleName();

@Override
public void onMessage(Context context, String s) {
Log.i(TAG, "onMessage method1 msg = " + s);
}

@Override
public void onMessage(Context context, String message, String platformExtra) {
Log.i(TAG, "onMessage method2 msg = " + message + ", platformExtra = " + platformExtra);
}

@Override
public void onMessage(Context context, Intent intent) {
String content = intent.getExtras().toString();
Log.i(TAG, "flyme3 onMessage = " + content);
}

@Override
public void onUpdateNotificationBuilder(PushNotificationBuilder pushNotificationBuilder) {
super.onUpdateNotificationBuilder(pushNotificationBuilder);
}

@Override
public void onNotificationClicked(Context context, MzPushMessage mzPushMessage) {
Log.i(TAG, "onNotificationClicked mzPushMessage " + mzPushMessage.toString());
}

@Override
public void onNotificationArrived(Context context, MzPushMessage mzPushMessage) {
super.onNotificationArrived(context, mzPushMessage);
}

@Override
public void onNotificationDeleted(Context context, MzPushMessage mzPushMessage) {
super.onNotificationDeleted(context, mzPushMessage);
}

@Override
public void onNotifyMessageArrived(Context context, String s) {
super.onNotifyMessageArrived(context, s);
}

@Override
public void onPushStatus(Context context, PushSwitchStatus pushSwitchStatus) {}

@Override
public void onRegisterStatus(Context context, RegisterStatus registerStatus) {
Log.i(TAG, "onRegisterStatus token = " + registerStatus.getPushId());
// Call the API to report to the IM backend after obtaining the token

}

@Override
public void onUnRegisterStatus(Context context, UnRegisterStatus unRegisterStatus) {}

@Override
public void onSubTagsStatus(Context context, SubTagsStatus subTagsStatus) {}

@Override
public void onSubAliasStatus(Context context, SubAliasStatus subAliasStatus) {}

@Override
public void onRegister(Context context, String s) {}

@Override
public void onUnRegister(Context context, boolean b) {}
}
package xxx.xxx.xxx;
import com.google.firebase.messaging.FirebaseMessagingService;
import android.util.Log;

public class GoogleFCMMsgService extends FirebaseMessagingService {
private static final String TAG = GoogleFCMMsgService.class.getSimpleName();

@Override
public void onNewToken(String token) {
super.onNewToken(token);
Log.i(TAG, "onNewToken google fcm onNewToken : " + token);
// Call the API to report to the IM backend after obtaining the token

}
}
Push Service Registration
To meet compliance requirements, after the user agrees to the privacy policy and logs in successfully, initialize and register each vendor's push service, store the token (obtained after successful registration) in the registration result callback, and call the setOfflinePushConfig API to report the push token to the backend. For some vendors, the token can also be returned via API calls after registration. See the following code for details.
public void init() {
...

if (BrandUtil.isBrandXiaoMi()) {
// Mi offline push
MiPushClient.registerPush(this, PrivateConstants.XM_PUSH_APPID, PrivateConstants.XM_PUSH_APPKEY);
} else if (BrandUtil.isBrandHonor()) {
HonorMessaging.getInstance(context).turnOnPush().addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(com.hihonor.push.sdk.tasks.Task<Void> task) {
if (task.isSuccessful()) {
TUIOfflinePushLog.i(TAG, "Honor turnOn push successfully.");
} else {
TUIOfflinePushLog.i(TAG, "Honor turnOn push failed." + task.getException());
}
}
});

new Thread(new Runnable() {
@Override
public void run() {
try {
String pushToken = HonorInstanceId.getInstance(context).getPushToken();
TUIOfflinePushLog.i(TAG, "Honor get pushToken " + pushToken);

// Check if pushToken is null
if(!TextUtils.isEmpty(token)) {
// Call the `setOfflinePushConfig` API of the IM SDK to report this token
String pushToken = token;
}
} catch (com.hihonor.push.sdk.common.data.ApiException e) {
TUIOfflinePushLog.i(TAG, "Honor get pushToken failed, " + e);
}
}
}).start();
}
else if (BrandUtil.isBrandHuawei()) {
// For Huawei offline push, set whether to receive the call example of the push notification bar message
HmsMessaging.getInstance(this).turnOnPush().addOnCompleteListener(new com.huawei.hmf.tasks.OnCompleteListener<Void>() {
@Override
public void onComplete(com.huawei.hmf.tasks.Task<Void> task) {
if (task.isSuccessful()) {
DemoLog.i(TAG, "huawei turnOnPush Complete");
} else {
DemoLog.e(TAG, "huawei turnOnPush failed: ret=" + task.getException().getMessage());
}
}
});

new Thread() {
@Override
public void run() {
try {
// read from agconnect-services.json
String appId = AGConnectServicesConfig.fromContext(MainActivity.this).getString("client/app_id");
String token = HmsInstanceId.getInstance(MainActivity.this).getToken(appId, "HCM");
DemoLog.i(TAG, "huawei get token:" + token);
if(!TextUtils.isEmpty(token)) {
// Call the `setOfflinePushConfig` API of the IM SDK to report this token
String pushToken = token;
}
} catch (ApiException e) {
DemoLog.e(TAG, "huawei get token failed, " + e);
}
}
}.start();
} else if (MzSystemUtils.isBrandMeizu(this)) {
// Meizu offline push
PushManager.register(this, PrivateConstants.MZ_PUSH_APPID, PrivateConstants.MZ_PUSH_APPKEY);
} else if (BrandUtil.isBrandVivo()) {
// vivo offline push
PushClient.getInstance(getApplicationContext()).initialize();

DemoLog.i(TAG, "vivo support push: " + PushClient.getInstance(getApplicationContext()).isSupport());
PushClient.getInstance(getApplicationContext()).turnOnPush(new IPushActionListener() {
@Override
public void onStateChanged(int state) {
if (state == 0) {
String regId = PushClient.getInstance(getApplicationContext()).getRegId();
DemoLog.i(TAG, "vivopush open vivo push success regId = " + regId);

// Call the `setOfflinePushConfig` API of the IM SDK to report this token
String pushToken = token;
} else {
// According to the vivo push documentation, state = 101 indicates that the vivo model or version does not support vivo push. Link: https://dev.vivo.com.cn/documentCenter/doc/156
DemoLog.i(TAG, "vivopush open vivo push fail state = " + state);
}
}
});
} else if (HeytapPushManager.isSupportPush()) {
// OPPO offline push
OPPOPushImpl oppo = new OPPOPushImpl();
oppo.createNotificationChannel(this);
// According to the OPPO documentation, the app must call the init(...) API before proceeding to subsequent operations.
HeytapPushManager.init(this, false);
HeytapPushManager.register(this, PrivateConstants.OPPO_PUSH_APPKEY, PrivateConstants.OPPO_PUSH_APPSECRET, oppo);
} else if (BrandUtil.isGoogleServiceSupport()) {
FirebaseInstanceId.getInstance().getInstanceId()
.addOnCompleteListener(new com.google.android.gms.tasks.OnCompleteListener<InstanceIdResult>() {
@Override
public void onComplete(Task<InstanceIdResult> task) {
if (!task.isSuccessful()) {
DemoLog.w(TAG, "getInstanceId failed exception = " + task.getException());
return;
}

// Get new Instance ID token
String token = task.getResult().getToken();
DemoLog.i(TAG, "google fcm getToken = " + token);

// Call the `setOfflinePushConfig` API of the IM SDK to report this token
String pushToken = token;
}
});
}
}
Take Huawei as an example. Store the token (obtained after successful registration) in the registration result callback, and call the setOfflinePushConfig API to report the token to the backend.
public class HUAWEIHmsMessageService extends HmsMessageService {

...

@Override
public void onNewToken(String token) {
DemoLog.i(TAG, "onNewToken token=" + token);

// Call the `setOfflinePushConfig` API of the IM SDK to report this token
String pushToken = token;
}

...
}
Report the push certificate and token to the backend
Call the setOfflinePushConfig API to report the push token. Construct the `V2TIMOfflinePushConfig` class, set `businessID` as the certificate ID of the vendor, and report the token obtained after registration of the vendor push service.
V2TIMOfflinePushConfig v2TIMOfflinePushConfig = null;
// Set `businessID` as the certificate ID of the vendor and report the token obtained after registration of the vendor push service.
v2TIMOfflinePushConfig = new V2TIMOfflinePushConfig(businessID, token);
V2TIMManager.getOfflinePushManager().setOfflinePushConfig(v2TIMOfflinePushConfig, new V2TIMCallback() {
@Override
public void onError(int code, String desc) {
DemoLog.d(TAG, "setOfflinePushToken err code = " + code);
}

@Override
public void onSuccess() {
DemoLog.d(TAG, "setOfflinePushToken success");
}
});

Step 6. Sync foreground and background status

If a message newly received needs to be displayed in the phone's notification bar when your app is switched to the background, call the doBackground() API of the IM SDK to sync the app status to the IM backend. When your app is switched back to the foreground, call the doForeground() API of the IM SDK to sync the app status to the IM backend.
// When the app is switched to the background
V2TIMManager.getOfflinePushManager().doBackground(totalCount, new V2TIMCallback() {
@Override
public void onError(int code, String desc) {
DemoLog.e(TAG, "doBackground err = " + code + ", desc = " + desc);
}

@Override
public void onSuccess() {
DemoLog.i(TAG, "doBackground success");
}
});
// When the app is switched to the foreground
V2TIMManager.getOfflinePushManager().doForeground(new V2TIMCallback() {
@Override
public void onError(int code, String desc) {
DemoLog.e(TAG, "doForeground err = " + code + ", desc = " + desc);
}

@Override
public void onSuccess() {
DemoLog.i(TAG, "doForeground success");
}
});

Step 7. Set offline push parameters when sending messages

When you call sendMessage to send messages, you can use V2TIMOfflinePushInfo to set offline push parameters. For more information, see the sendMessage() method in ChatProvider:
OfflineMessageContainerBean containerBean = new OfflineMessageContainerBean();
OfflineMessageBean entity = new OfflineMessageBean();
entity.content = message.getExtra().toString();
entity.sender = message.getFromUser();
entity.nickname = chatInfo.getChatName();
entity.faceUrl = TUIChatConfigs.getConfigs().getGeneralConfig().getUserFaceUrl();
containerBean.entity = entity;

V2TIMOfflinePushInfo v2TIMOfflinePushInfo = new V2TIMOfflinePushInfo();
v2TIMOfflinePushInfo.setExt(new Gson().toJson(containerBean).getBytes());
// For OPPO, you must set the `ChannelID` to receive push messages. The `ChannelID` must be identical with that in the console.
v2TIMOfflinePushInfo.setAndroidOPPOChannelID("tuikit");

final V2TIMMessage v2TIMMessage = message.getTimMessage();
String msgID = V2TIMManager.getMessageManager().sendMessage(v2TIMMessage, isGroup ? null : userID, isGroup ? groupID : null,
V2TIMMessage.V2TIM_PRIORITY_DEFAULT, false, v2TIMOfflinePushInfo, new V2TIMSendCallback<V2TIMMessage>() {
@Override
public void onProgress(int progress) {

}

@Override
public void onError(int code, String desc) {
TUIChatUtils.callbackOnError(callBack, TAG, code, desc);
}

@Override
public void onSuccess(V2TIMMessage v2TIMMessage) {
TUIChatLog.v(TAG, "sendMessage onSuccess:" + v2TIMMessage.getMsgID());
message.setMsgTime(v2TIMMessage.getTimestamp());
TUIChatUtils.callbackOnSuccess(callBack, message);
}
});

Step 8. Parse offline push messages

When an offline push message in the notification column is received and clicked, it will automatically redirect to the interface you configured in Step 3. You can retrieve the passed offline push parameters in the onResume() method of the interface startup by calling getIntent().getExtras(), and then custom the redirection. For details, see the handleOfflinePush() method in TUIKitDemo.
private void handleOfflinePush() {
// Determine whether to log in to IM again based on the log-in status
// 1. If the log-in status is V2TIMManager.V2TIM_STATUS_LOGOUT, you will redirect to the log-in interface, and log in to IM again
if (V2TIMManager.getInstance().getLoginStatus() == V2TIMManager.V2TIM_STATUS_LOGOUT) {
Intent intent = new Intent(MainActivity.this, SplashActivity.class);
if (getIntent() != null) {
intent.putExtras(getIntent());
}
startActivity(intent);
finish();
return;
}

// 2. Otherwise, it means the app is just in the background, directly parse the offline push parameters
final OfflineMessageBean bean = OfflineMessageDispatcher.parseOfflineMessage(getIntent());
if (bean != null) {
setIntent(null);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (manager != null) {
manager.cancelAll();
}

if (bean.action == OfflineMessageBean.REDIRECT_ACTION_CHAT) {
if (TextUtils.isEmpty(bean.sender)) {
return;
}
TUIUtils.startChat(bean.sender, bean.nickname, bean.chatType);
}
}
}

Note
By clicking the message in the Notification colunm in FCM, you will by default redirect to the application's default Launcher interface. You can retrieve the passed offline push parameters by calling getIntent().getExtras() in the onResume() method of the interface startup, and then custom the redirection.
Upon completion of the above configurations, when your app is switched to the background or the process is killed, the messages will be pushed offline and displayed in the notification bar. You can click the message in the notification bar to redirect to the specified app page.

Custom Push Ringtone for Offline Push

System settings before Android 8.0, API calls setAndroidSound() and setIOSSound().

1. Custom ringtone resource files for Android should be added to the project's raw directory; for iOS, link them into the Xcode project.
2. The message specifies using a custom ringtone.
V2TIMOfflinePushInfo v2TIMOfflinePushInfo = new V2TIMOfflinePushInfo();
v2TIMOfflinePushInfo.setAndroidSound("Ringtone Name");
v2TIMOfflinePushInfo.setIOSSound("Ringtone Name.mp3");

String msgID = V2TIMManager.getMessageManager().sendMessage(v2TIMMessage, isGroup ? null : userID, isGroup ? groupID : null,
V2TIMMessage.V2TIM_PRIORITY_DEFAULT, false, v2TIMOfflinePushInfo, new V2TIMSendCallback<V2TIMMessage>() {
@Override
public void onProgress(int progress) {
TUIChatUtils.callbackOnProgress(callBack, progress);
}

@Override
public void onError(int code, String desc) {
TUIChatUtils.callbackOnError(callBack, TAG, code, desc);
}

@Override
public void onSuccess(V2TIMMessage v2TIMMessage) {

}
});
Note
Supported in IMSDK v6.1.2155 or above.
The interface supports Huawei, Xiaomi, FCM, and APNS.

System settings for Android 8.0 and later need to be implemented through a channel.

Huawei and ANPS
Huawei and APNS still call setAndroidSound() and setIOSSound() to set offline push notification ringtones.
Mi
1.1 Log in to the vendor console to create a channel and configure it. The ringtone file needs to be added to the raw directory of your local Android Studio project.



1.2 Send the message specifying the custom ringtone's channel ID. For details, see setAndroidXiaoMiChannelID.
V2TIMOfflinePushInfo v2TIMOfflinePushInfo = new V2TIMOfflinePushInfo();
v2TIMOfflinePushInfo.setAndroidXiaoMiChannelID("Channel ID Applied by Manufacturer");

String msgID = V2TIMManager.getMessageManager().sendMessage(v2TIMMessage, isGroup ? null : userID, isGroup ? groupID : null,
V2TIMMessage.V2TIM_PRIORITY_DEFAULT, false, v2TIMOfflinePushInfo, new V2TIMSendCallback<V2TIMMessage>() {
@Override
public void onProgress(int progress) {
TUIChatUtils.callbackOnProgress(callBack, progress);
}

@Override
public void onError(int code, String desc) {
TUIChatUtils.callbackOnError(callBack, TAG, code, desc);
}

@Override
public void onSuccess(V2TIMMessage v2TIMMessage) {

}
});
FCM
1.1 Create a channel that requires a custom ringtone.
You need to first create a channel with a custom ringtone in the code. The ringtone file needs to be added to the raw directory of your local Android Studio project, and record the name of the channel ID.
1.2 Send the message specifying the custom ringtone's channel ID. For details, see setAndroidFCMChannelID.
V2TIMOfflinePushInfo v2TIMOfflinePushInfo = new V2TIMOfflinePushInfo();
v2TIMOfflinePushInfo.setAndroidFCMChannelID(PrivateConstants.fcmPushChannelId);

String msgID = V2TIMManager.getMessageManager().sendMessage(v2TIMMessage, isGroup ? null : userID, isGroup ? groupID : null,
V2TIMMessage.V2TIM_PRIORITY_DEFAULT, false, v2TIMOfflinePushInfo, new V2TIMSendCallback<V2TIMMessage>() {
@Override
public void onProgress(int progress) {
TUIChatUtils.callbackOnProgress(callBack, progress);
}

@Override
public void onError(int code, String desc) {
TUIChatUtils.callbackOnError(callBack, TAG, code, desc);
}

@Override
public void onSuccess(V2TIMMessage v2TIMMessage) {

}
});
Note
Supported in IMSDK v7.0.3754 or above.
FCM custom ringtones or setting channel ID is supported only in Certificate Mode.


FAQs

How do I troubleshoot if I cannot receive offline push messages?

OPPO devices

General reasons for not receiving push notifications on OPPO phones include:
According to the requirements of the official OPPO Push website, ChannelID must be configured on OPPO devices running Android 8.0 or above, otherwise, push notifications cannot be displayed. For the method of configuration, refer to setAndroidOPPOChannelID.
The notification column display feature is disabled by default for OPPO installation application. You need to check the switch status.

Google FCM

If push messages cannot be received, check whether the certificates are successfully uploaded to the IM console by referring to "Configuring in the IM console - Google FCM" and verify with the illustration to see if they are added correctly.

Sending messages as Custom Definition Messages

The offline push for custom messages is different from that for normal messages. As we cannot parse the content of custom messages, we cannot determine the push's content. Therefore, by default, there is no offline push. If you need an offline push, you need to set the desc field in offlinePushInfo when using sendMessage, and the desc information will by default be displayed during the push.

Effects of Device Notification Bar Settings

The direct manifestation of offline push is notification column alerts. Thus, like other notifications, it is subject to device notification settings. Take Huawei as an example:
"Settings - Notifications - Lock Screen Notifications - Hide or Do Not Show Notifications" will affect the display of offline push notifications when the screen is locked.
"Settings - Notifications - More Notification Settings - Show Notification Icons (Status Column)" will affect the display of offline push notification icon in the status column.
"Settings - Notifications - Application Notifications Management - Allow Notifications" will directly affect the display of offline push notifications.
"Settings - Notifications - Application Notifications Management - Notification Sound" and "Settings - Notifications - Application Notifications Management - Notification Mute" will affect the offline push notification ringtone.

Completed the integration process but still cannot receive offline push messages

First, verify whether normal push is possible using the Offline Testing Tool in the IM Console.
If offline push does not work properly and the device status is exceptional, check the parameters in the IM console and then check the code initialization and registration logic, including the vendor push service registration and IM offline push configuration.
If offline push does not work properly but the device status is normal, check whether the ChannelID is correct or whether the backend service is working properly.
The offline push feature relies on the vendor's capabilities. Some simple characters may be filtered by the vendor and cannot be passed through and pushed.
If offline push messages are not pushed timely or cannot be received, you need to check the vendor's push restrictions.

How to troubleshoot if the jump interface is unsuccessful?

Click the notification column of an offline push message to redirect to the specified interface. The backend delivers the redirection modes and page parameters that you configure for various vendors in the console to vendor servers based on vendor API rules. When you click the notification column for offline push messages, the system opens and redirects to the corresponding page. The opening of the corresponding page also depends on the manifest file. Only when the configuration in the manifest file is consistent with that in the console, the corresponding page can be opened and redirected properly.
1. First, you need to check whether the configuration in the console and that in the manifest file are correct and consistent with each other. For more information, see the TUIKitDemo configuration. Note that the API modes may vary by vendors.
2. If the system redirects to the configuration page, you need to check whether the parsing of offline messages on the configuration page and the page redirection are proper.

Vendor's push restrictions

1. All vendors in China have adopted message classification mechanisms, and different push policies are assigned for different types of messages. To make the push timely and reliable, you need to set the push message type of your app as the system message or important message with a high priority based on the vendor's rules. Otherwise, offline push messages are affected by the vendor's push message classification and may vary from your expectations.
2. In addition, some vendors set limits on the daily volumes of app push messages. You can check such limits in the vendor's console.
3. If offline push messages are not pushed timely or cannot be received, consider the following:
Huawei: Starting from EMUI 10.0, Huawei Push intelligently categorizes notification messages into two levels: Service and Communication and Information Marketing. Versions earlier than EMUI 10.0 don't categorize notifications but have only one level, so all notifications are displayed through the "default notification" channel, which is equivalent to the Service and Communication level on EMUI 10.0. The daily push volume of Information Marketing messages has been capped based on the app type since January 5, 2023, while the daily push volume of Service and Communication messages is not limited. Additionally, message classification is also related to self-help message classification permission.
If there is no self-help message classification permission, the vendor will perform secondary intelligent message classification on push messages.
If you have applied for the self-help message classification permission and the push message carries the category field, the message will be pushed based on the custom classification. For details, see setAndroidHuaWeiCategory.
Honor: Honor phone push notifications are related to the system version.
Currently, the HONOR channel only supports domestic HONOR devices on Magic UI 4.0 or later and overseas HONOR devices on Magic UI 4.2 or later.
Honor devices below the versions mentioned can use the Huawei Manufacturer for push access.
For details, see Vendor Description.
vivo: The push service will optimize message classification rules and adjust the quantity limits for different message categories starting April 3, 2023.
Regarding message classification optimization, add a secondary classification category field and configure different push speeds based on different secondary classifications. For the API, see setAndroidVIVOCategory. The default value of category can be configured in the IM console.
Regarding the adjustment of message quantity limits, system messages can apply for unlimited permissions, with no limit on the number of messages a single user can receive per day per application. The daily push limit for operational messages = the number of active users with notifications enabled * multiplier, with a default multiplier of 2, and 3 for news applications. The daily limit for a single user per application is 2 messages, and 5 for news applications.
OPPO: Push messages are classified into private messages and public messages with different push effects and policies. Private messages are those that a user pays attention to and wants to receive in time. The private message channel permission needs to be applied for via email. The public message channel is subject to a number limit.
Mi: Push messages are classified into "private messages" and "public messages," with the default channel being public messages. The daily push quantity of public messages is capped. Public messages are suitable for pushing hot news, new product promotions, platform announcements, community topics, prize-winning activities, and other content of general interest to users. Private messages are suitable for pushing chat messages, personal order changes, delivery notifications, transaction reminders, IoT system notifications, and other private notifications. The number of private message notifications is not limited. Message classification management requires channel application and integration in the vendor's console.
Meizu: Push messages are subject to a number limit.
For details, see Vendor Description.
FCM: Upstream message push is subject to a frequency limit.
For details, see Vendor Description.