Skip to main content
Version: v3

Android Push Guide

Please read Push Notification Overview first to understand the concepts.

There is a special demo for Android message push. See Android-Push-Demo.

Introduction to the Push Process

The Push Notification service on Android relies primarily on the PushService on the client. The PushService is an application-independent process that is created when the application is first launched and then lives (as much as possible) in the background, and is mainly responsible for maintaining a long WebSocket connection with the cloud push server. Thus, as long as PushService is alive, any message that needs to be pushed to the current device will be pushed immediately to the push server; if PushService is killed, the push channel will be interrupted and Android devices will not receive any push messages. After establishing a long WebSocket connection with the push server, PushService will also receive multiple unsuccessful push messages cached by the server at once.

Integrate the Push Notification Service

To integrate the push service, you need the realtime-android library. First, open build.gradle in the app directory and configure it like this:

dependencies {

implementation 'cn.leancloud:realtime-android:8.2.24'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'

}

Then create a new Java class called MyLeanCloudApp and make it inherit from the Application class with the following sample code:

public class MyLeanCloudApp extends Application {

@Override
public void onCreate() {
super.onCreate();

// Pass this, AppId, and AppKey as initialization parameters
LeanCloud.initialize(this, "{{appid}}", "{{appkey}}", "https://please-replace-with-your-customized.domain.com");
}
}

Configure AndroidManifest

Make sure your AndroidManifest.xml contains the following in <application>:

<service android:name="cn.leancloud.push.PushService" />

Please also set the necessary permissions:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

In order for the application to receive pushes even when it is closed, you need to add to <application>:

<receiver android:name="cn.leancloud.push.LCBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>

Push Wakeup

If you want to support inter-app push wakeup mechanism, i.e. two apps using cloud push on the same device, after app A is killed, when app B is woken up it can wake up app A's push at the same time, you can configure it like this:

<service android:name="cn.leancloud.push.PushService" android:exported="true"/>

Complete AndroidManifest.xml

The complete AndroidManifest.xml file configuration is shown below:

<!-- Base module (required) START -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Base module END -->

<application
android:icon="@drawable/notification"
android:theme="@android:style/Theme.Holo.Light"
android:label="@string/app_name"
android:name=".MyLeanCloudApp" >

<!-- Instant Messaging and Push Notification START -->
<!-- Instant Messaging, Push Notification, and LiveQuery require PushService -->
<service android:name="cn.leancloud.push.PushService"/>
<receiver android:name="cn.leancloud.push.LCBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.USER_PRESENT"/>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<!-- Instant Messaging and Push Notification END -->

<!-- User Feedback START -->
<activity
android:name="cn.leancloud.feedback.ThreadActivity" >
</activity>
<!-- User Feedback END -->

Save Installation

When the application is installed on the user's device, the SDK automatically generates an Installation object if the push feature is to be used. This object is essentially the installation information generated by the application on the device and must first be stored on the cloud in order for the device to receive push notifications:

LCInstallation.getCurrentInstallation().saveInBackground();

This code should be called once at application startup to ensure that the device is registered with the cloud. You can listen to the callback to get the installationId to do the data association.

LCInstallation.getCurrentInstallation().saveInBackground().subscribe(new Observer<LCObject>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(LCObject avObject) {
// Operations such as associating the installationId with the user table.
String installationId = LCInstallation.getCurrentInstallation().getInstallationId();
System.out.println("Successfully saved: " + installationId );
}
@Override
public void onError(Throwable e) {
System.out.println("Could not save. Error message: " + e.getMessage());
}
@Override
public void onComplete() {
}
});

Enable the Push Notification Service

Start the push service by calling the following code and also set the default Activity to open.

// Set the default Activity to open
PushService.setDefaultPushCallback(this, PushDemo.class);

Subscribe to Channels

Your application can subscribe to a channel by calling the PushService.subscribe method before saving your Installation:

// Subscribe to the channel and open the corresponding Activity when the channel message arrives
// Parameters in order: current context, channel name, class of the callback object
PushService.subscribe(this, "public", PushDemo.class);
PushService.subscribe(this, "private", Callback1.class);
PushService.subscribe(this, "protected", Callback2.class);

Note:

  • The channel name can only contain upper and lower case English letters, numbers, underscores (_), hyphens (-), equal signs (=), and Chinese characters.
  • The callback object refers to the Activity page that the user enters by clicking the notification in the notification bar.

To unsubscribe from a channel:

PushService.unsubscribe(context, "protected");
//You must save the Installation again after unsubscribing
LCInstallation.getCurrentInstallation().saveInBackground();

Adapting for Android 8.0

After calling LeanCloud.initialize, you need to call PushService.setDefaultChannelId(context, channelid) to set the default channel for notification display, otherwise the message will not be displayed. See Google's official documentation Creating a notification for more information about channel ID.

In addition, our push service also supports multiple push channels. On the client side, developers can create a new notification channel by calling PushService with the following method (or you can call the underlying API to create it yourself):

public static void createNotificationChannel(Context context, String channelId, String channelName,
String description, int importance,
boolean enableLights, int lightColor,
boolean enableVibration, long[] vibrationPattern)

Note the channelId here because we will need it later when we send push notifications. When sending a push request, the custom keyword _notificationChannel allows you to select a different channel for the message presentation.

For example, the following request will be displayed on the client in the channel with notification ID "1":

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{
"where": {"key" : "value"}
"data": {
"alert": "Message content",
"title": "Title to display in the notification bar",
"_notificationChannel": "1"
}
}' \
https://{{host}}/1.1/push

Send Push Notifications

By default, Developer Center > Your game > Game Services > Cloud Services > Push Notification > Settings has Prevent clients from sending push notifications checked to prevent clients from pushing messages to any target device in the app without restriction. We recommend that developers check this box to send push messages via the REST API or the dashboard. If there is a need to send pushes from the client, you will need to uncheck this first.

Send to All Devices

LCPush push = new LCPush();
Map<String, Object> pushData = new HashMap<String, Object>();
pushData.put("alert","push message to android device directly");
push.setPushToAndroid(true);
push.setData(pushData);
push.sendInBackground().subscribe(new Observer<JSONObject>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(JSONObject jsonObject) {
System.out.println("Push successful" + jsonObject);
}
@Override
public void onError(Throwable e) {
System.out.println("Push failed. Error message: " + e.getMessage());
}
@Override
public void onComplete() {
}
});

Send to Specific Users

Send to users on the "public" channel:

LCQuery pushQuery = LCInstallation.getQuery();
pushQuery.whereEqualTo("channels", "public");
LCPush push = new LCPush();
push.setQuery(pushQuery);
push.setMessage("Push to channel.");
push.setPushToAndroid(true);
push.sendInBackground().subscribe(new Observer<JSONObject>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(JSONObject jsonObject) {
System.out.println("Push successful" + jsonObject);
}
@Override
public void onError(Throwable e) {
System.out.println("Push failed. Error message: " + e.getMessage());
}
@Override
public void onComplete() {
}
});

To send to a user with a specific Installation id, you would typically associate LCInstallation with the device's logged-in user LCUser as a property, and then you can send a message to a specific user by querying the InstallationId with the following code to achieve a private message-like function:

LCQuery pushQuery = LCInstallation.getQuery();
// Assuming that THE_INSTALLATION_ID is the installationId stored in the user table,
// you can retrieve it and store it in the user table when the application is opened by the user
pushQuery.whereEqualTo("installationId", THE_INSTALLATION_ID);
LCPush.sendMessageInBackground("Tarara invited you to play Arc Symphony with her!",pushQuery).subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Object object) {
System.out.println("Push successful" + object);
}
@Override
public void onError(Throwable e) {
System.out.println("Push failed. Error message: " + e.getMessage());
}
@Override
public void onComplete() {
}
});

Read More: How to Reply to Push Messages

Message Format

For the specific message format, see the Push Notification REST API. For Android devices, the default message content parameters support the following attributes:

{
"alert": "Message content",
"title": "Title to display in the notification bar",
"custom-key": "A custom property added by the user; custom-key is just an example, feel free to replace it",
"silent": false, // Used to control whether to turn off the notification bar alert; default is false, i.e. do not turn off the notification bar alert
"action": "com.your_company.push" // Must be provided if using a custom receiver
}

The silent property above is a flag for the push-through message and the notification bar message. If silent is true, the message is not displayed in the notification bar; if silent is false, the message is displayed in the notification bar.

As mentioned earlier, after PushService receives a push message, it determines whether the message is expired and whether a duplicate message has been received before forwarding the message, and only non-expired and non-duplicate messages are notified to the application by sending a local notification or broadcast.

How Notification Bar Messages Respond to User Click Events

When the PushService sends a notification bar message, it sets the response class for the notification bar, depending on whether the developer calls PushService.setDefaultPushCallback(context, clazz) or PushService.subscribe(context, "channel", clazz) to set the callback class that sets the response class for the notification bar.

In the onCreate function of the callback class, the developer can then use the following code to get the specific data of the push message:

public class CallbackActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.callback2);

// Get the push message data
String message = this.getIntent().getStringExtra("com.avoscloud.Data");
String channel = this.getIntent().getStringExtra("com.avoscloud.Channel");
System.out.println("message=" + message + ", channel=" + channel);
}
}

Customized Receiver

If you want to push messages that don't appear in the Android notification bar, but instead execute the application's predefined logic, you need to declare your own Receiver in the AndroidManifest.xml of your Android project:

<receiver android:name="com.avos.avoscloud.PushDemo.MyCustomReceiver" android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="com.avos.UPDATE_STATUS" />
</intent-filter>
</receiver>

Here com.avos.avoscloud.PushDemo.MyCustomReceiver is your Android's Receiver class, and <action android:name="com.avos.UPDATE_STATUS" /> must correspond to the action specified in the push's data.

Your Receiver can be implemented like this:

public class MyCustomReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// Retrieve the push message data
String message = intent.getStringExtra("com.avoscloud.Data");
String channel = intent.getStringExtra("com.avoscloud.Channel");
System.out.println("message=" + message + ", channel=" + channel);
}
}

Also, the request to send the push is changed accordingly, e.g:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{
"channels":[ "public"],
"data": {
"action": "com.avos.UPDATE_STATUS",
"name": "LeanCloud."
}
}' \
https://{{host}}/1.1/push

Note that if you are using a custom Receiver, the message sent must have an action and its value exists in the <intent-filter> list of the custom receiver configuration, for example 'com.avos.UPDATE_STATUS'. Please use your own action and try not to confuse it with other applications. It is recommended to use the domain name to define it.