Mi Push Server Side SDK (Java)更新时间: 2024-10-09 15:06:00

Guide for Mi Push Server Side SDK (Java)

1、Introduction

1.1 Mi Push Server Side SDK

https://admin.xmpush.xiaomi.com/en/mipush/downpage/

1.2 Usage

· Push messages;
· Obtain message statistics;
· Subscribe tags;· Get message status;

· Developer tool.

2、Quick Start

Before you access SDK, you need to Enable Mi Push service, and get the corresponding AppID, AppKey and AppSecret.

You can access MiPush server  by Java Http2 SDK (view section 2.1).

2.1 Access Java Http2 SDK 

2.1.1 Get SDK

Download Java Http2 SDK: https://admin.xmpush.xiaomi.com/en/mipush/downpage/java-http2

Please download the latest version.

2.1.2 JDK Requirement

JDK version should be 1.8 or later.

2.1.3 Import SDK

1. Decompress "MiPush_SDK_Server_Http2.zip"

2. Put the jars under the folder "MiPush_SDK_Server_Http2" into the "libs" directory of your project.

Note:

· If the JDK 1.9 or above is used, conscrypt-openjdk-uber-2.1.0.jar package may not be necessary.
· If you don't want to use the okhttp3 component, you may skip conscrypt-openjdk-uber-2.1.0.jar, okhttp-3.14.2.jar, and okio-1.17.2.jar, and call Constants.disableOkHttp3() method at the same time, which will disable HTTP2.0 protocol.

2.2 Introduction to server side SDK classes

Brief Introduction to Server side SDK Classes

ClassDescription
MessageMessage object
BuilderMessage creator for an Android device
IOSBuilderMessage creator for an iOS device
TargetedMessageMessage content and target
SenderMessage Sender
ResultReturned results from the server side after message is sent
StatsStatistics of sent messages
TracerTrace message status
SubscriptionSubscribe/unsubscribe tags
FeedbackFeedback information, e.g. invalid RegID or Alias list.
This interface will be invalid soon, please use the message receipt callback interface (callback.type: 16) to filter invalid data.
ConstantsConstant definition
ErrorCodeError type

3、Sender

Mi Push message sender class.
com.xiaomi.xmpush.server.Sender
Creating a Sender instance:
Sender(String appSecret) - appSecret is generated when registering on the Mi Dev Platform and can be viewed under the app details.
Return Result
com.xiaomi.xmpush.server.Result
MethodDescription
String getMessageId()If the message has been sent successfully, the server will return the message ID; if it couldn’t be sent, the return will be null.
ErrorCode getErrorCode()Returned error code if the message hasn’t been sent successfully. Otherwise ErrorCode.Success will be returned.
String getReason()Returned reason if the message hasn’t been sent successfully. Otherwise the return will be null.

Demo

private void sendMessage() throws Exception {
Constants.useOfficial();
Sender sender = new Sender(APP_SECRET_KEY);
String messagePayload = “This is a message”;
String title = “notification title”;
String description = “notification description”;
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.notifyType(1) // Use default sound reminder
.build();
Result result = sender.send(message, regId, 3);
Log.v("Server response: ", "MessageId: " + result.getMessageId()
+ " ErrorCode: " + result.getErrorCode().toString()
+ " Reason: " + result.getReason());
}

To send messages to regions outside mainland China, you need to add Region.Europe/Region.Russia/Region.India/Region.Singapore in the sender. For example:

Sender sender = new Sender(APP_SECRET_KEY, Region.Singapore);

3.1 Build messages

· Build Message Object

· Build TargetedMessage Object: TargetedMessage encapsulates the message object with its targeted user.

TargetedMessage class:
com.xiaomi.xmpush.server.TargetedMessage

Difference: Message body only contains message parameters, no message push target (RegID, alias, useraccount, topic)

Note: When the TargetedMessage is used when sending a message, the targetType of all TargetedMessage objects must be the same. Messages can't be sent to both RegID and alias in one request.

MethodDescription
TargetedMessage()Constructor
setMessage(Message message)Setting up a message
setTarget(int targetType, String target)Setting up the message target
targetType represents the target type (currently supports 3 types)
TargetedMessage.TARGET_TYPE_REGID (RegID message type, target corresponds to RegID)
TargetedMessage.TARGET_TYPE_ALIAS (Alias message type, target corresponds to Alias)
TargetedMessage.TARGET_TYPE_USER_ACCOUNT (Useraccount message type, target corresponds to Useraccount)

3.1.1 Android platform

com.xiaomi.xmpush.server.Message.Builder

Message type:

· Notifications (passThrough=0) - Displayed on the device status bar and more details can be viewed when users pull down the notification shade;

· Pass Through message (passThrough=1) - Push messages into the app (don't display on the device status bar), and the app declares the processing logic;

Builder method list:

MethodDescription
Builder()Constructor
payload(String payload)Setting up the message payload. It can’t be left blank. It must be less than 4KB, and each ASCII/Non-ASCII character will be counted as 1 (it’s a required field for pass-through message, optional for non-passthrough message).
title(String title)Setting up the notification title shown on the notification shade. It can't be set blank. It must be less than 50 characters in length, and each ASCII/Non-ASCII character will be counted as 1 (it's required for notification messages).
description(String description)Setting up the notification description shown on the notification shade. It can't be set blank. It must be less than 128 characters in length, and each ASCII/Non-ASCII character will be counted as 1 (it's required for notification messages).
passThrough(int passThrough)Indicating whether this message is a notification or pass-through message, 1 means pass-through message, 0 means notification message (notification message is set by default).
notifyType(Integer type)Setting up notification type, the type value supports:
· 1: Use default sound reminder
· 2: Use default vibration reminder
· 4: Use default LED light reminder
· -1 (system default value): all of the above 3 effects are supported
· 0: none of the above 3 effects are supported, i.e., silent pushes.
Also supports any OR operation of 1, 2, 4 to achieve any effect combination of sound, vibration and flash.
restrictedPackageName(String packageName)Setting up the app package name. The package name must be consistent with the name applied from the developer website.
restrictedPackageNames(String[] packageNames)Setting up multiple package names of the app (to send broadcast messages with multiple package names). The package names must be consistent with the names applied from the developer website. It can be left blank to send pushes to all channels’ package names by default. Note: You can’t call the restrictedPackageName and restrictedPackageNames methods at the same time.
timeToLive(int milliseconds)Optional. Set up how long the message will be saved on the server if a device is offline (unit: ms). The server saves messages up to 2 weeks by default.
timeToSend(long milliseconds)Optional. Schedule time to send messages. The timeToSend uses a time representation with unit of ms. Note: It only supports messages scheduled within 7 days.
notifyId(Integer id)Optional. The notification message only shows 1 push message by default. If you want multiple push messages to be shown on the notification shade, you must set up different notify_id for different messages (notification message with the same notify_id will cover the former).
enableFlowControl(boolean needFlowControl)Optional. Controlling whether or not the push requires a smooth push (/message/advanced/flow.html) (the QPS is less than 3000). This feature is tuned off by default.
extra(String key, String value)Optional. Providing some extended functions (/message/advance/index.html) to the app. Besides these extended functions, developers can customize some key-value pairs to control the client behaviors. Note: The total number of characters can’t exceed 1024, you can set up a maximum of 10 key-value pairs.
build()Generating message object based on preceding attributes.

Demo:

private Message buildMessage() throws Exception {
String PACKAGENAME = "com.xiaomi.mipushdemo";
String messagePayload = “This is a message”;
Message message = new Message.Builder()
.payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.passThrough(1)
.notifyType(1) // Use default sound reminder
.build();
return message;
}

Using emojis

When creating a message, you can insert emojis in the message title and description. Mi Push uses Android's emoji library and provides display support on both MIUI and non-MIUI systems.

The relationship between the emoji supported versions, the Android system versions and Unicode versions is as follows:

Android System VersionEmoji VersionUnicode VersionUnicode Emoji Release DateAndroid Support DateEmoji Amount
7.1492016.07.212016.10.202374
7392016.07.212016.08.221791
6.0.1182015.07.172015.12.071294
6172014.07.16UnknownUnknown
516.12012.022014.11.031090
4.4162010.12014.11.01850
4.3162010.12013.07.24717

Note:

If the Unicode version is a higher version (such as 9.0), the corresponding Android system version needs to be 7.0 and above. If it's below 7.0, some emojis may be displayed abnormally.

3.1.2 iOS platform

com.xiaomi.xmpush.server.Message.IOSBuilder

iOSBuilder method list:

MethodDescription
IOSBuilder()Create iOSBuilder object. The size of APNs message is 256 characters.
description(String description)Setting up the notification description displayed on the notification shade.
title(String title)The notification title shown on the notification shade (supported on iOS 10 or later, if this field exists, it will override the description field).
subtitle(String subtitle)The subtitle shown on the notification shade (supported on iOS 10 or later, if this field exists, it will override the description field).
body(String body)The notification content shown on the notification shade (supported on iOS 10 or later, if this field exists, it will override the description field).
mutableContent(String value)Mutable notification option (supported on iOS 10 or later versions).
timeToLive(int milliseconds)Optional. Set up how long the message will be saved on the server if a device is offline (unit: ms). The server saves messages up to 2 weeks by default.
timeToSend(long milliseconds)Optional. Schedule time to send messages. The timeToSend uses a time representation of 00:00:00.0 UTC from 01/01/1970 (time unit: ms). Note: It only supports messages scheduled within 7 days.
soundURL(String url)Optional. Used to customize message ringtone.
badge(int badge)Optional. Used to customize notification badge.
category(String category)Optional. iOS 8 push message quick-reply category.
extra(String key, String value)Optional. Used to customize key-value pairs. Be able to control the client behavior. Note: You can set up to 10 key-value pairs.
build()Generating message object based on preceding attributes.

Demo:

private Message buildMessage() throws Exception {
String description = “notification description”;
Message message = new Message.IOSBuilder()
.description(description)
.soundURL(“default”) // Message ringtone
.badge(1) // Notification badge
.category("action") // Quick-reply category
.extra("key", "value") // Customized key-value pair
.build();
return message;
}

3.2 RegID messages

Scenarios:

RegID is generated by the Xiaomi Push server based on the device ID, appID, and current timestamp when the app registers with the Mi Push service. Therefore, it can guarantee that the RegID for each app on a same device is different and be used as an unique identifier of the app on the device.
Note: The developer's own server is required to receive and store the RegID returned by Mi Push;

Interface description:

com.xiaomi.xmpush.server.Sender

MethodDescription
send(Message message, String regid, int retries)Sends the message to a specified device with given RegID, a maximum retry number is set when encountering delivery failure.
send(Message message, List<String> regids, int retries)Sends the message to a specified device with a given set of RegIDs a maximum retry number is set when encountering delivery failure. The number of RegIDs can’t exceed 1000.
sendHybridMessageByRegId(message, regids, retries)Send RegID messages to hybrid apps. If it's a hybrid app, you need to call this method.

Demo:

· Single RegID message:

private void sendMessage() throws Exception {
Constants.useOfficial();
private Sender sender = new Sender(APP_SECRET_KEY, Region.Singapore);
String messagePayload= “This is a message”;
String title = “notification title”;
String description = “notification description”;
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.notifyType(1) // Use default sound reminder
.build();
sender.send(message, regId, 3); // According to RegID, send a message to the specified device
}

· Multiple RegID messages (Recommended)

private void sendMessage() throws Exception {
Constants.useOfficial();
private Sender sender = new Sender(APP_SECRET_KEY, Region.Singapore);
String messagePayload= “This is a message”;
String title = “notification title”;
String description = “notification description”;
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.notifyType(1) // Use default sound reminder
.build();
sender.send(message, Lists.newArrayList(regId1, regId2 ...), 3); // Send messages to a group of devices, the number of RegIDs can't exceed 1000
}

3.3 Alias messages

Scenarios:

Alias is a personalized setting provided by Mi Push, and a one-to-one correspondence between alias and RegID is guaranteed. Developers can set an alias for their app on each device, thus it will be much more convenient for them to manage their devices since alias is a much shorter string than RegID for the consideration of storage. If multiple devices are set with a same alias, the alias will be mapped to the latest set device(if multiple devices need to be managed with a same name, the UserAccount message is recommended).
Note: The client needs to send a Command request to set the alias via Push Client SDK

Interface description:

com.xiaomi.xmpush.server.Sender
MethodDescription
sendToAlias(Message message, String alias, int retries)Sends the message to a specified device with the given alias, a maximum retry number is set when encountering delivery failure. The alias can’t be left blank, contain commas, or exceed 128 characters in length; each ASCII/Non-ASCII character will be counted as 1.
sendToAlias(Message message, List<String> aliasList, int retries)Sends the message to devices with a given set of alias, a maximum retry number is set when encountering delivery failure. The number of alias can’t exceed 1000.

Demo:

· Single alias message:

private void sendMessageToAlias() throws Exception {
Constants.useOfficial();
private Sender sender = new Sender(APP_SECRET_KEY, Region.Singapore);
String messagePayload = “This is a message”;
String title = “notification title”;
String description = “notification description”;
String alias = “testAlias”; //Alias can’t be blank, contain commas, or exceed 128 characters.
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.notifyType(1) // Use default sound reminder
.build();
sender.sendToAlias(message, alias, 3); // Send message to a designated device according to the alias.
}

· Multiple alias messages (Recommended)

private void sendMessageToAliases() throws Exception {
Constants.useOfficial();
private Sender sender = new Sender(APP_SECRET_KEY, Region.Singapore);
String messagePayload = “This is a message”;
String title = “notification title”;
String description = “notification description”;
List<String> aliasList = new ArrayList<String>();
aliasList.add(“testAlias1”); // Alias can’t be blank, contain commas, or exceed 128 characters.
aliasList.add(“testAlias2”); // Alias can’t be blank, contain commas, or exceed 128 characters.
aliasList.add(“testAlias3”); // Alias can’t be blank, contain commas, or exceed 128 characters.
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.notifyType(1) // Use default sound reminder
.build();
sender.sendToAlias(message, aliasList, 3); // Send message to designated devices according to the aliasList.
}

3.4 UserAccount message

Scenarios:

userAccount is mainly applied to users who log in on multiple devices.
An account can be added to multiple (up to 20) devices. It can be deemed as a small topic.
Note:
· The useraccount is set by the client by calling the setUserAccount (final Context context, final String userAccount, String category) interface.

Interface description:

com.xiaomi.xmpush.server.Sender
MethodDescription
sendToUserAccount(Message message, String userAccount, int retries)Sends the message to devices bound to a given user account, a maximum retry number is set when encountering delivery failure. The user account can’t be left blank, contain commas, or exceed 128 characters in length; each ASCII/Non-ASCII character will be counted as 1.
sendToUserAccount(Message message, List<String> accountList, int retries)Sends the message to devices bound to a given set of user accounts, a maximum retry number is set when encountering delivery failure. The number of user account can’t exceed 1000.

Demo:

· Single user account message:

private void sendMessageToUserAccount() throws Exception {
Constants.useOfficial();
private Sender sender = new Sender(APP_SECRET_KEY, Region.Singapore);
String messagePayload = “This is a message”;
String title = “notification title”;
String description = “notification description”;
String useraccount = “testUserAccount”; //useraccount can’t be left blank, contain commas, or exceed 128 characters in length
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.notifyType(1) // Use default sound reminder
.build();
sender.sendToUserAccount(message, useraccount, 3); // Send message to designated devices bound to the useraccount.
}

· Multiple useraccount messages (Recommended):

private void sendMessageToUserAccounts() throws Exception {
Constants.useOfficial();
private Sender sender = new Sender(APP_SECRET_KEY, Region.Singapore);
String messagePayload = “This is a message”;
String title = “notification title”;
String description = “notification description”;
List<String> accoutList = new ArrayList<String>();
accoutList.add(“testUserAccount1”); //useraccount can’t be left blank, contain commas, or exceed 128 characters in length
accoutList.add(“testUserAccount2”); //useraccount can’t be left blank, contain commas, or exceed 128 characters in length
accoutList.add(“testUserAccount3”); //useraccount can’t be left blank, contain commas, or exceed 128 characters in length
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.notifyType(1) // Use default sound reminder
.build();
sender.sendToUserAccount(message, accoutList, 3); // Send message to designated devices bound to the accountList.
}

3.5 Topic messages

Scenarios:

If developers want to send different push messages based on various user groups (generally in large amount), such as groups by different client versions, regions, user genders. In this case, sending topic messages is a good choice. We give different tags (topics) for various user groups. A unified label is also provided for full-volume users, and developers can directly use the label to send messages, which is quick and convenient. Developers can also use topics to perform union, intersection, and subtraction operations to push messages more accurately. Note: View section 7 Subscribe tags.

Attention: Be careful about using API to send full-volume topic messages. If the messages were missent to users due to testing and other reasons, Mi Push reserves the right to prohibit you from sending topic messages.

Interface description:

com.xiaomi.xmpush.server.Sender
MethodDescription
broadcast(Message message, String topic, int retries)Sends the message to a group of devices with given topic, a maximum retry number is set when encountering delivery failure. The topic can’t be left blank, or exceed 128 characters in length; each ASCII/Non-ASCII character will be counted as 1.
broadcastAll(Message message, int retries)Send messages to all devices
multiTopicBroadcast(Message message, List<String> topics, topic_op, int retries)Used to broadcast messages to multiple topics, it supports intersection, union and subtraction operations among topics (if there is only 1 topic, use the single topic version).
broadcastHybridAll(message, retries)Send full-volume messages to hybrid apps. If it's a hybrid app, you need to call this method.

· In multiTopicBroadcast, BROADCAST_TOPIC_OP is an enumeration type, it determines the operational relationship among multiple topics when sending a broadcast message.

public enum BROADCAST_TOPIC_OP {
UNION, // Union
INTERSECTION, // Intersection
EXCEPT, // Subtraction
}

· Example: If the elements of the topic list are [A, B, C, D], then the union result is A∪B∪C∪D, the intersection result is A ∩B∩C∩D, and the subtraction result is A-B-C-D.

Note: You can send up to 5 topics for topic messages.

Demo:

· Single topic:

private void sendBroadcast() throws Exception {
Constants.useOfficial();
private Sender sender = new Sender(APP_SECRET_KEY, Region.Singapore);
String messagePayload = “This is a message”;
String title = “notification title”;
String description = “notification description”;
String topic = “testTopic”;
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.notifyType(1) // Use default sound reminder
.build();
sender.broadcast(message, topic, 3); //Send message to specified group of devices according to the topic
}

· Multiple topics:

private void sendBroadcast() throws Exception {
Constants.useOfficial();
private Sender sender = new Sender(APP_SECRET_KEY, Region.Singapore);
String messagePayload = “This is a message”;
String title = “notification title”;
String description = “notification description”;
List<String> topicList = new ArrayList<>();
String topic1 = “testTopic1”;
String topic2 = “testTopic2”;
topicList.add(topic1);
topicList.add(topic2);
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.notifyType(1) // Use default sound reminder
.build();
// Conduct a union operation according to the topicList, and send message to the specified group of devices
sender.multiTopicBroadcast(message, topicList, BROADCAST_TOPIC_OP.UNION, 3);
}

3.6 Scheduled messages

Scenarios:

Used to push messages for daily push tasks or fixed-time activities, sending real-time push will inevitably be laborious and may not be timely, in this case, you can prepare the push content in advance and schedule to send it at a particular time.

Interface description:

com.xiaomi.xmpush.server.Sender

1. Set timeToSend(long milliseconds) when you build the message object

·The timeToSend is in unit of ms. Note: It only supports messages scheduled within 7 days.

2. Call Sender.send(List messages, int retries, long timeToSend) when you build the TargetedMessage object

· Schedule to send a group of messages. The timeToSend uses a time representation of 00:00:00.0 UTC from 01/01/1970 (time unit: ms). Note: It only supports messages scheduled within 7 days.

MethodDescription
checkScheduleJobExist(String msgId)Detect whether the scheduled task exists
deleteScheduleJob(String msgId)Delete a scheduled message according to the message ID
deleteScheduleJobByJobKey(String jobKey)Delete a scheduled message according to the jobKey

Demo:

Set the timeToSend attribute for a message object:

private void sendMessageToAlias() throws Exception {
Constants.useOfficial();
private Sender sender = new Sender(APP_SECRET_KEY, Region.Singapore);
String messagePayload = “This is a message”;
String title = “notification title”;
String description = “notification description”;
String alias = “testAlias”; //Alias can’t be blank, contain commas, or exceed 128 characters.
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.timeToSend(System.currentTimeMillis() + 60 * 60 * 1000) // Send in 1 hour
.notifyType(1) // Use default sound reminder
.build();
sender.sendToAlias(message, alias, 3); // Send message to a designated device according to the alias.
}

Build TargetedMessage:

private void sendMessageToAlias() throws Exception {
Constants.useOfficial();
private Sender sender = new Sender(APP_SECRET_KEY, Region.Singapore);
String messagePayload = “This is a message”;
String messagePayload1 = “Other This is a message”;
String title = “notification title”;
String title1 = "other notification title"
String description = “notification description”;
String description1 = “other notification description”;
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.notifyType(1) // Use default sound reminder
.build();
String alias = “testAlias”; //Alias can’t be blank, contain commas, or exceed 128 characters.
String alias1 = “testAlias1”; //Alias can’t be blank, contain commas, or exceed 128 characters.
TargetedMessage targetedMessage = new TargetedMessage();
targetedMessage.setTarget(TargetedMessage.TARGET_TYPE_ALIAS, alias);
targetedMessage.setMessage(message);

TargetedMessage targetedMessage1 = new TargetedMessage();
targetedMessage1.setTarget(TargetedMessage.TARGET_TYPE_ALIAS, alias1);
Message message1 = new Message.Builder()
.title(title1)
.description(description1).payload(messagePayload1)
.restrictedPackageName(MY_PACKAGE_NAME)
.notifyType(1) // Use default sound reminder
.build();
targetedMessage1.setMessage(message1);
List<TargetedMessage> messages = new ArrayList<TargetdMessage>();
messages.add(targetMessage);
messages.add(targetMessage1);

// Send a message (set to be sent in 1 hour) to the specified device according to the TargetedMessage list
sender.send(messages, 3, System.currentTimeMillis() + 60 * 60 * 1000);
}

3.7 Improve the message sending performance

·Tip 1: Use the batch interface instead of single message request. To send a message to 10,000 users, Developer A chose to use the batch interface, requested 10 times and sent to 1000 targets (such as alias, RegID, etc.) each time, while Developer B requested 10,000 times and sent to 1 target each time. Obviously, the efficiency of Developer A is much higher than that of Developer B. Tip 2: Use the TargetMessage message object;
· Filter out invalid devices before sending messages (set callback.type=16 through message receipt callback interface to get the list of invalid devices), in order to improve the message sending performance;
·Setting up a reasonable ttl (timeToLive: message expiration time) for a message can also increase the delivery rate to a certain extent. If the message is not required on time efficiency, you can set a longer ttl, or use our server's default time (1 weeks) without setting this value. In this way, as long as the devices become online within the valid period of ttl, they can receive previously pushed messages.

3.8 Increase the delivery rate

· Set callback.type=16 through message receipt callback interface, in order to filter out some invalid devices in the following requests;
· Setting up a reasonable ttl (timeToLive: message expiration time) for a message can also increase the delivery rate to a certain extent.
· It's recommended to send notification messages;

4、Advanced functions

When constructing the message object, call the extra(String key, String value) method to set the key and value, so as to customize the extended functions of the app;

4.1 Customize ringtones

Android versions below 8.0

When sending messages on Android versions lower than 8.0, you can customize ringtones in this way:

Call the extra(String key, String value) method of the Message.Builder class to set the ringtone URI.
· key - 'sound_uri', value - Ringtone's URI;
Note:
· The ringtone can only be selected from current app's resources, and the URI format should be: android.resource://your packagename/XXX/XXX.
· The ringtone files are put in the raw folder of the Android app.
· It's only used for notification messages.
· The stored sound file must have an extension name, but don't write the extension name in the URI.
private Message buildMessage() throws Exception {
String PACKAGENAME = "com.xiaomi.mipushdemo";
String messagePayload = “This is a message”;
String title = “notification title”;
String description = “notification description”;
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.passThrough(0) // Display messages in the notification shade
.notifyType(1)
.extra(Constants.EXTRA_PARAM_SOUND_URI, "android.resource://" + PACKAGENAME + "/raw/shaking")
.build();
return message;
}

Android 8.0 and above versions

The notification effect of Android 8.0 and above is subject to the effect configured in channels. Setting a customized ringtone when sending a message will not take effect. You need to set a customized ringtone when creating a new channel.

· If you haven't set a channel, Mi Push will create a default channel for you when you send the first message, and the effect will be subject to this message you send. If you set a customized ringtone in this message as described above, the default channel's ringtone effect will be the customized ringtone effect, and you won't be able to change the ringtone in the future.

· If you want to change the customized ringtone, you can only set it when creating a new channel, and then use this channel to push messages. Messages pushed by this channel will carry this customized ringtone.

   To use the channel, view "4.5 Notification category (Channel)".

4.2 Control the pop-up of the app's foreground notifications

When the app runs in the foreground, if the server sends a notification message to the client, the app will pop up the notification by default;
If you don't want the device to pop up notifications, change the settings by calling the extra(String key, String value) method of the Message.Builder class;
· key - 'notify_foreground', value - Turn on/off(1/0);
Note: It's only used for notification messages.

Demo:

private Message buildMessage() throws Exception {
String PACKAGENAME = "com.xiaomi.mipushdemo";
String messagePayload = “This is a message”;
String title = “notification title”;
String description = “notification description”;
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.passThrough(0) // Display messages on the notification shade
.notifyType(1)
.extra(Constants.EXTRA_PARAM_NOTIFY_FOREGROUND, "0")
.build();
return message;
}

4.3 Pre-declare the click behavior of notification messages

1. Open the Launcher Activity server corresponding to the current app:

You need call the extra(String key, String value) method of the Message.Builder class to set the key as Constants.EXTRA_PARAM_NOTIFY_EFFECT, and the value as Constants.NOTIFY_LAUNCHER_ACTIVITY;

Demo:

private Message buildMessage() throws Exception {
String PACKAGENAME = "com.xiaomi.mipushdemo";
String messagePayload = “This is a message”;
String title = “notification title”;
String description = “notification description”;
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.passThrough(0) // Display messages in the notification shade
.notifyType(1)
.extra(Constants.EXTRA_PARAM_NOTIFY_EFFECT, Constants.NOTIFY_LAUNCHER_ACTIVITY)
.build();
return message;
}

2. Open any Activity within current app

Call the extra(String key, String value) method of the Message.Builder class:

key - Constants.EXTRA_PARAM_NOTIFY_EFFECT, value - Constants.NOTIFY_ACTIVITY
key - Constants.EXTRA_PARAM_INTENT_URI, value - The intent URI to start an activity

How to get an intent URI:

Declare an activity in the AndroidManifest.xml of the Android client project. The following example is an activity that displays news.
<activity android:name=".NewsActivity"/>
Declare an intent to start the activity, for example, to start the NewsActivity above, declare the intent as:
intent:#Intent;component=com.yourpackage/.YourActivity;end
For example, convert the intent to URI:
String uriString = intent.toUri(Intent.URI_INTENT_SCHEME);// The uriString is the value corresponding to Constants.EXTRA_PARAM_INTENT_URI
Return value:
intent:#Intent;component=com.xiaomi.mipushdemo/.NewsActivity;end

Note:

· If you want to carry data in the intent URI, pay attention to a restriction: Intent.toUri(Intent.URI_INTENT_SCHEME). Except basic types (boolean, byte, short, int, long, float, double, String), the returned result won't carry any other data types, such as arrays and HashMap.

· After you get the Intent URI, set uriString into Message.Builder.extra() in the server project (need to import the push server SDK). The corresponding key is Constants.EXTRA_PARAM_INTENT_URI.

· When the intent URI is generated, if it can't redirect after click, or the life cycle of the activity is not executed, it's recommended to add the flag parameter: intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP).

Demo:

private Message buildMessage() throws Exception {
String PACKAGENAME = "com.xiaomi.mipushdemo";
String messagePayload = “This is a message”;
String title = “notification title”;
String description = “notification description”;
return new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.passThrough(0) // Display messages in the notification shade
.notifyType(1)
.extra(Constants.EXTRA_PARAM_NOTIFY_EFFECT, Constants.NOTIFY_ACTIVITY)
.extra(Constants.EXTRA_PARAM_INTENT_URI, "intent:#Intent;component=com.xiaomi.mipushdemo/.NewsActivity;end")
.build();
}

3. Open web page

Call the extra(String key, String value) method of the Message.Builder class:

key -Constants.EXTRA_PARAM_NOTIFY_EFFECT, value - Constants.NOTIFY_WEB
key - Constants.EXTRA_PARAM_WEB_URI, value - Web page URI

Demo:

private Message buildMessage() throws Exception {
String PACKAGENAME = "com.xiaomi.mipushdemo";
String messagePayload = “This is a message”;
String title = “notification title”;
String description = “notification description”;
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.passThrough(0) // Display messages in the notification shade
.notifyType(1)
.extra(Constants.EXTRA_PARAM_NOTIFY_EFFECT, Constants.NOTIFY_WEB)
.extra(Constants.EXTRA_PARAM_WEB_URI, "http://www.xiaomi.com")
.build();
return message;
}

4.4 Rich Text

MIUI versions above MIUI 10 support rich text style messages such as large image, large text, large icon, and small icon, and also support the push of rich text messages through the server SDK .

 4.4.1 Large image / large text / large icon

Style Introduction

Examples of the large text and image messages in mainland China version:(the left one is for Large Text and the right one is for Large image)

Description:
On MIUI 12, the image of a large image message will be displayed between the title and the content.

On MIUI global versions, sending the messages with large icons is supported (for mainland China versions, it's only supported on MIUI 12 or later). Example:

Styles of large text and image messages:

【Large text styles】

MIUI mainland China VersionMIUI Global Version
Message contentSupports multiple lines of text;
Up to 128 characters, and you can use "\n" to wrap the text.
Supports multiple lines of text;
Up to 128 characters, you can NOT use "\n" to wrap the text.
Customized large iconOnly supported on MIUI 12 or later versions, the large icon won't be shown on the versions below MIUI 12;
The large icon is displayed on the right side;
image format: PNG/JPG/JPEG; image size: 120×120px; file size: smaller than 200 KB.
Supported. Displays on the right side;
image format: PNG/JPG/JPEG; image size: 120×120px; file size: smaller than 200 KB.
Shown on notification shadeThe first message in the notification shade will be fully expanded; while for other messages, only the title and the first line of text will be displayed like normal messages, you need to press and hold the notification to expand the entire content.The first message in the notification shade will be fully expanded; while for other messages, only the title and the first line of text will be displayed like normal messages, you need to press and hold the notification to expand the entire content.
ButtonSupports 0~3 buttonsSupports 0~3 buttons

【Large image styles】

MIUI mainland China VersionMIUI Global Version
Message contentUp to 128 characters (the length of a single letter and space is counted as 1);
doesn't support long text or line breaks.
Up to 128 characters (the length of a single letter and space is counted as 1);
doesn't support long text or line breaks.
ImageFixed image size: 876*324px;
image format: PNG/JPG/JPEG;
file size: smaller than 1MB.
Fixed image size: 984*450px;
image format: PNG/JPG/JPEG;
file size: smaller than 1MB.
Customized large iconOnly supported on MIUI 12 or later versions, large icon won't be shown on versions below MIUI 12;
displays on the right side, and only shows when the large image is folded;
image format: PNG/JPG/JPEG; image size: 120×120px; file size: smaller than 200 KB.
Supported. Displays on the right side;
image format: PNG/JPG/JPEG; image size: 120×120px; file size: smaller than 200 KB.
Shown on notification shadeThe first message in the notification shade will be fully expanded; while for other messages, only the title and the first line of text will be displayed like normal messages, you need to press and hold the notification to expand the entire content.The first message in the notification shade will be fully expanded; while for other messages, only the title and the first line of text will be displayed like normal messages, you need to press and hold the notification to expand the entire content.
ButtonSupports 0~3 buttonsSupports 0~3 buttons

Description:

· Rich text messages are only supported on MIUI 10 and above. On lower versions and non-MIUI systems, these messages will be displayed in the style of normal messages.

· Among MIUI mainland China versions, the large icon is only supported on MIUI 12 and above, and will not be displayed on versions below MIUI 12.

· When you send a large image message, if the image download fails due to network reasons, the image won't be displayed, and the message will be displayed in normal style.

Setting method

Step 1. Upload an image

Note:
Large image size: 984*450px (for MIUI Global versions), 876*324px (for MIUI mainland China versions); file size: smaller than 1 MB; image format: PNG/JPG/JPEG.
Icon image size: 120*120px; file size: smaller than 200 KB; icon image format: PNG/JPG/JPEG.

    Codes:

...
File file = new File("<upload file path name>");
Media media = new Media("<your app secret>");
Result result = media .upload(file, <isIcon>, <isGlobal>);
// The second parameter indicates whether it is an icon, and the third parameter indicates whether it is used on global versions. // Note that the returned URL must be URL decoded.
String picUrl = URLDecoder.decode(result.getData(Constants.JSON_MEDIA_PICTURE_URL), "UTF8");
// When you upload a large image, the icon URL of the large image after being cropped and zoomed will be returned. If you don't know what to upload for the large icon in the large image, you can use this returned icon URL. // When you upload a large icon, only the icon URL will be returned.
String iconUrl = URLDecoder.decode(result.getData(Constants.JSON_MEDIA_ICON_URL), "UTF8");
...

Note:

If the format of the uploaded small icon doesn't meet our requirement, an error code "66108" will be returned, with reasons such as "File extension name error", "Small icon format must be PNG" or "Small icon image size is too small".

Step 2. Build a message with rich text format.

   Codes:

    a. Large text

  ...
Message message = new Message.Builder()
.description("no more than 128 words.")
.extra(new Message.NotificationStyleBuilder()
.bigTextStyle() // Here declares that it's large text
.largeIconUri("<icon url>") // Here uses the icon URL returned
.build())
.build();
...

    b. Large image

...
Message message = new Message.Builder()
.extra(new Message.NotificationStyleBuilder()
.bigPictureStyle() // Here declares that it's large image
.bigPicUri("<pic url>")
.largeIconUri("<icon url>")
.build())
.build();
...

    c. Add buttons      

    The events after each button is clicked are the same as the predefined click events of the normal notification messages, namely: open the app homepage, open a designated page (intent) and open a web page (URL).

...
Message message = new Message.Builder()
.extra(new Message.NotificationStyleBuilder()
.bigPictureStyle() // Here is an example of the large image style, the large text style also supports adding buttons in the same way
.bigPicUri("<pic url>")
.largeIconUri("<icon url>")
.leftBtn().name("<left btn name>").launcher().end() // Open the app homepage
.midBtn().name("<mid btn name>").activity().intentUri("<intent uri>").end() // Open a designated page (intent)
.rightBtn().name("<right btn name>").web("<url>").end() // Open a web page (URL)
.build())
.build();
...

    Note:

    After clicking, the button will not disappear automatically.

    If the subsequent behavior after clicking the button is to open a certain page of the app, in the declaration configuration of this page you need to add:

<intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>

4.4.2 Small icon

Style introduction

The small icon is an important part of the notification, and can be used to indicate the notification type, source, etc.The styles of MIUI 10 small icon would be:

· MIUI 10 Global version: Display the small icon on the notification header

· MIUI 10 mainland China version: Doesn't display the small icon in notifications by default.MIUI 10.2 and above versions support switching to native styles. After switching, the mainland China version will display a small icon on the notification header just like the global version.

In the example below, the left image shows the effect of global versions, while the other two images indicate how to switch to native styles in mainland China versions as well as the effect after switching.

For the adaptation of small icons:

Tips for adapting small icons:
· Small icon must be a PNG image with Alpha transparency channel.
· The background must be transparent.
· The graphics must be white.Don't upload graphics in other colors, you can change the color by using setColor.And don't set to white, otherwise the Android system will change the color to gray automatically.
· Don't leave too much padding around.

Setting method

Step 1: Upload small icon image.

Note:

    For devices of different sizes, there is no need to upload small icons of different sizes. It is recommended to use 60 x 60px uniformly.Don’t upload pictures whose quality is lower than the recommended value, otherwise they will be blurred.However, if you upload a picture with a higher picture quality value than the recommended one, the system will automatically reduce the value without affecting the visual effect.

    Codes:    

    After you upload a small icon image, it will return a URL.

...

File file = new File("<upload file path name>");
Media media = new Media("<your app secret>");
Result result = media .smallIconUpload(file); // You can view the data structure of the Result and retrieve the fields based on your requirements
String picUrl = URLDecoder.decode(result.getData(Constants.JSON_SMALL_ICON_URL), "UTF8");

    Note: Constants.JSON_SMALL_ICON_URL is already declared in server_api.

    Result format:

{
"messageId": "Xxo001345312251113178f",
"traceId": "Xxo001345312251113178f",
"errorCode": {
"value": 0,
"description": "Success"
},
"data": {
"sha1": "35bb8d1b4c5e69ba8c93d1abfe1bc47911376395",
"small_icon_url": "http://f7.market.xiaomi.com/download/MiPass/062b9c585310d434c0363fdaa2256d91ea02f5a3a/35bb8d1b4c5e69ba8c93d1abfe1bc47911376395.png"
}
}

Step 2: When generating the message, put the URL and the color to be rendered into the Extra of the message.

    Codes:

· If you are using Sender to send messages

Message.IOSBuilder builder = new Message.IOSBuilder();
//Message.Builder builder = new Message.Builder();
//Attention! Code need to be added is listed below
builder.extra(STYLE_SMALL_ICON_URI, "small_icon_url") ;//
builder.extra(STYLE_SMALL_ICON_COLOR, "#FFFFFF"); //Pay attention to the color format, you can refer to https://www.114la.com/other/rgb.htm

Note:

    String STYLE_SMALL_ICON_COLOR = "notification_small_icon_color";           

    String STYLE_SMALL_ICON_URI = "notification_small_icon_uri";

    Already declared in server_api.

· If you use thrift to send messages

InternalMessage message = new InternalMessage();

message.putToExtra(STYLE_SMALL_ICON_URI, "small_icon_url") ;

message.putToExtra(STYLE_SMALL_ICON_COLOR, oxffff00);

Get historical small icon and color value

Through the above operations, you will be able to upload small icons.The URL and color value of the small icon image used last time can be queried by AppID.

Method name: Media.querySmallIconInfoByAppId

Parameters: AppID: Long type

Return value: Result:

{
"messageId": "Xxo001345312251113178f",
"traceId": "Xxo001345312251113178f",
"errorCode": {
"value": 0,
"description": "Success"
},
"data": {
"smallIconColor": "#ABCDEF",
"smallIconUrl": "http://f7.market.xiaomi.com/download/MiPass/062b9c585310d434c0363fdaa2256d91ea02f5a3a/35bb8d1b4c5e69ba8c93d1abfe1bc47911376395.png"
}
}

4.5 Notification category (Channel)

Notification category (Channel) introduction

Notification category (Channel), a new feature introduced by Android O to solve the following problems:

· There are more and more notifications in the app, causing obvious interruptions to users.

· But users can only block all notifications of this app, not some of them to remain useful ones.

To solve this problem, Android supports developers to divide their notifications into several categories, and then allows users to block notifications in a certain category individually.For a detailed introduction to the notification category (Channel), refer to"MIUI 10 Notification Category (Channel) Adaptation".

Description:
1. This version doesn't support setting up Channel Group currently.
2. For MIUI system, notifications can be sent without setting the Channel.For non-MIUI systems, whether to set up Channel depends on the target API of your app:
· Target API ≥ 26 (Android 8.0): Channel must be set, and a Channel must be specified for each notification, otherwise the notification can't be sent.
· Target API ≤ 25 (Android 7.1): Channel may not be set.In devices running Android 8.0 and above, notifications can also be sent normally.
To ensure that notifications can be displayed normally on different types of devices, it's recommended that you set up Channel.

Method

Note:
Users can create up to 8 channels.
The Channel_id of each Channel can't be repeated, and the Channel_name is also not allowed to be repeated.
Once a Channel is created and sent with a message, the Channel will be generated on the device, and it can't be deleted or modified, so be careful when creating a Channel.

· Add a new Channel:

ChannelHelper channelHelper = new ChannelHelper(APP_SECRET);
ChannelInfo channelInfo = new ChannelInfo.Builder()
.channelId("id") //Required. The ID of the notification category. Enter up to 200 characters.
.channelName("name")//Required. The name of the notification category. Enter up to 40 characters.
.channelDesc("desc") //Optional. The description of the notification category. Enter up to 300 characters.
.notifyType(7) // Required. The notification effect styles. (1: Use default sound reminder; 2: Use default vibration reminder; 4: Use default LED light reminder; -1: All of the above 3 effects are supported; 0: None of the above 3 effects are supported.)
.soundUrl("sound_url") //Optional. Customized ringtone URI for notification, refer to "4.1 Customize Ringtone" for more details.
.build();
Result result = channelHelper.addNewChannel(channelInfo, 1)

Note:

Channel set through the API will be synced to the operating platform, which might take a few minutes. Channels can also be created directly on operating platform.

· Obtain all valid Channels:

ChannelHelper channelHelper = new ChannelHelper(APP_SECRET);
Result result = channelHelper.getChannelList(1);

Example of returned data:

[{"channel_description":"desc","channel_id":"id","channel_name":"name","notify_type":1,"sound_url":"url"},{...}]

· Abandon a Channel:

ChannelHelper channelHelper = new ChannelHelper(APP_SECRET);
Result result = channelHelper.discardChannel("channel_id", 1);

· Send messages with Channel:

When building a message, pass parameters to extra through custom key-value pairs.

keyvalue
channel_idIndicates which channel the message belongs to. The channel must be created and configured, otherwise an error will be returned.

Code example:

 private Message buildMessage() throws Exception {
String PACKAGENAME = "com.xiaomi.mipushdemo";
String messagePayload = "This is a message";
String title = "notification title";
String description = "notification description";
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName("com.xiaomi.mipushdemo")
.passThrough(0) // Display messages in the notification shade
.notifyType(1) // Use default sound reminder
.extra("channel_id", "my_channel_1") // Set channel ID (must be created)
.build();
return message;
}

· When setting up Channel in environment outside mainland China, add Region.Europe/Region.Russia/Region.India/Region.Singapore when calling, the example is as follows:

ChannelHelper channelHelper = new ChannelHelper(APP_SECRET, Region.Singapore)

4.6. Filter messages

Developers can specify message filtering rules by calling extra(String key, String value) of the Message.Builder class (filtering rules can support all types of messages).

key-'locale', value - The language range of the devices that can receive messages, separated by commas;
key - 'locale_not_in', value - The language range of the devices that can't receive messages, separated by commas;

The current device locale acquisition method is Locale.getDefault().toString()

For example, Mainland China is represented by "zh_CN" (view details in the Appendix 1: Country/Region Language Codes)

key - 'model', value - The model range of the devices that can receive messages, separated by commas;
key - 'model_not_in', value - The model range of the devices that can't receive messages, separated by commas;

There are two uses of model:

1. The MODEL range of the devices that can receive messages, separated by commas.Build.MODEL - The current device Model acquisition method (for example, the mobile version of Mi 4 is represented by "MI 4LTE").
2. The BRAND range of the devices that can receive messages, separated by commas.For example, Samsung mobile phones are represented by "samsung" (Currently covering 42 mainstream brands, view details in the Appendix 2 "Brand List")
key - 'app_version', value - The app versions of the devices that can receive messages, separated by commas;
key - 'app_version_not_in', value - The app versions of the devices that can't receive messages, separated by commas;

The Android app version number is derived from the value of "android:versionName" in the manifest file (currently supports MiPush_SDK_Client_2_2_12_sdk.jar and later versions)

key - 'connpt', value - Designate to receive messages under a specific network environment, currently only supports the value "wifi";

Demo:

private Message buildMessage() throws Exception {
String PACKAGENAME = "com.xiaomi.mipushdemo";
String messagePayload = “This is a message”;
String title = “notification title”;
String description = “notification description”;
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.passThrough(0) // Display messages in the notification shade
.notifyType(1)
.extra("locale","zh_CN")
.build();
return message;
}

4.7. Message receipt

After messages are sent, Mi Push can send a receipt to developers about the data such as delivery success number, click number, etc. The message receipt rules can be specified by calling extra(String key, String value) of the Message.Builder class.

List of rules:

KeyMeaning of the Value
callbackString (required field), the Http address of your server to receive the receipt, the maximum length is 128 bytes.
callback.paramString (optional field), customized receipt parameters to decide which types of information are returned in the callback, the maximum length is 64 bytes.
callback.typeString (optional field), supports the following types of receipts: ·
1: Message delivery.·
2: Message clicks.·
3: The message delivery and clicks.· Note that the delivery receipt and click receipt might be sent via two separate callback requests.
16: Invalid target devices (An invalid device might be one of the following cases: a). the alias/user account/regID is incorrect; b). the app is not registered or uninstalled; c). the destination area is incorrect, etc.).·
32: The client SDK calls the disablePush interface to disable Push.·
64: The target device doesn't meet the filtering conditions (including network conditions, geographic location, app version, model, regional language, etc.).·
If not set, the default type is 3.

Note:
1.    No receipt will be returned in the following cases:
a).The message can't be delivered because the current device is offline
b). The app is not launched while conducting pass-through messages,
c). The app is not launched on non-Mi Phones,
d). The message is expired [TTL parameter], etc.·
2. If you need multiple status receipts, just add the type value.For example, if you need to receive both the delivery receipt and the receipt of invalid target device, set callback.type as 17 (ie 1+16); if you need to receive receipts of message delivery, message click, and invalid target device, set callback.type as 19 (1+2+16).



Best practice: It's recommended to filter the invalid devices returned by callback-16 to reduce unnecessary pushes to these users.    

Each message receipt will contain the messageId and the regID/alias list of devices receiving messages, devices clicking the message, or invalid devices. These message receipts are sent by Mi Push Server every 1s by calling the requested http API (After each call, Mi Push Server will clear these data, and new data will be sent next time).

Note: 
· The delivery receipt only supports messages sent to regID or alias.
· The receipt of invalid target device supports regID, alias and useraccount messages.

The server callback uses the post method, and will pack the folloging information when requesting the http API.

Accept:text/html,application/xhtml xml,application/xml

Accept-Charset:UTF-8

Accept-Language:zh-cn

Content-Type=application/x-www-form-urlencoded.

It is highly suggested to add the above headers when testing our API with tools like Postman.

The request body is “data={json format string}”, and the JSON data format is as follows:


{
//Type 1 means that the message has been delivered, and targets are device aliases that have been delivered.
"msgId1":{"param":"param","type": 1, "targets":"alias1,alias2,alias3", "jobkey": "123" ,"barStatus":"Enable","timeStamp":1324167800000},


//Type 2 means that the message was clicked, and targets are the aliases of the clicked device.
"msgId2":{"param":"param","type": 2, "targets":"alias1,alias2,alias3", "jobkey": "456", "barStatus": "Enable", "timeStamp": 1524187800000},


//Type 16 means that the target device is invalid, and targets are invalid aliases.
"msgId3":{"param":"param","type":16,"targets":"alias1,alias2,alias3","barStatus":"Unknown","timestamp":xxx},


//Type 16 means that the target device is invalid, targets are invalid regIDs, and an errorCode of 1 indicates invalid regID.
"msgId4":{"param":"param","type":16,"targets":"regId1,regId2,regId3","barStatus":"Unknown","errorCode":1,"timestamp":xxx,"replaceTarget":{"regId1":"otherRegId"}},


//Type 64 means that the target device doesn't meet the filtering conditions.
"msgId5":{"param":"param","type":64,"targets":"regId1,regId2,regId3", "barStatus":"Unknown","timestamp":1572228055643}

Format description:

The outer key represents the corresponding message msgID, and the value is a JSONObject, which contains the following parameter values:
· param: The customized parameter value uploaded by the developer.
· type: The message status type.1-Delivery; 2-Click; 16-Invalid target, 32-The client has called the disablePush interface to disable Push, 64-The target device doesn't meet the filtering conditions, 512-The total number of pushes on the day exceeds the limit (Restriction Rules).
· targets: a list of Aalias, RegID or useraccount, separated by commas.
· jobkey: The jobkey value set by the developer when sending a message.
· barStatus: The status of the notification bar when the message is delivered."Enable" means that the user allows the app to display the notification message, and "Disable" means that the notification message has been disabled. "Unknown" means that the status of the notification bar is unknown.
· timestamp: The time when the message was delivered to the device.
· replaceTarget: It means that the current target can‘t be delivered, you may replace it with a new target identifier to push messages normally.The value is a key-value pair, the key represents the original target identifier of the device, and the value means that it's recommended to replace the original target identifier with a new one.
· errorCode: The subclass of invalid target returned when the type is 16.errorCode: 1 means invalid RegID; errorCode: 2 means invalid alias; errorCode: 3 means invalid useraccount.

Demo:

private Message buildMessage() throws Exception {
String PACKAGENAME = "com.xiaomi.mipushdemo";
String messagePayload = "This is a message";
String title = "notification title";
String description = "notification description";
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.passThrough(0) // Display messages on the notification shade
.notifyType(1)
.extra("callback", "http://www.xiaomi.com/msgcallback")
.build();
return message;
}

4.8 Message aggregation

Developers can set the group ID (JobKey) of the message when sending a message, and messages with the same group ID will be aggregated into a message group;

The system supports the display of message details and statistical information such as planned pushes/delivery amount/delivery curve according to the message group.In addition, messages with the same JobKey will be deduplicated on the client side, and only the one will be displayed and fowllowing messages with the same jobkey will be omitted even they are delivered successfully to devices.In this way, if there are duplicate devices in the same JobKey accidentally when sending messages, there is no need to worry that the user will receive duplicate notifications.

The method to set the group ID of the message is to call the extra(String key, String value) method of the Message.Builder class to set the key to "jobkey";
Set the value as the message group ID, the legal message group ID consists of numbers ([0-9]), uppercase and lowercase letters ([a-zA-Z]), underscore (_) as well as dash (-). The length is up to 12 characters, and it can't start with an underscore (_).

Demo:

private Message buildMessage() throws Exception {
String PACKAGENAME = "com.xiaomi.mipushdemo";
String messagePayload = “This is a message with job key.”;
String title = “notification title”;
String description = “notification description”;
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.passThrough(0) // Display messages on the notification shade
.notifyType(1)
.extra("jobkey", "0115a001")
.build();
return message;
}

4.9 Smooth push

If the message sending speed is too fast,it will cause a lot of pressure on the developer's server, so we provide the smooth push feature, by this way the developer can set the message sending speed.

The developer can set the message sending speed by calling extra(String key, String value) of the Message.Builder class:

key - "flow_control"
value - Sending speed (qps)
Note: If the set speed is lower than 1000 qps, it will use the default speed of 3000 qps(query per second).

Description:

When smooth push is set, if the same app sends 2 messages at the same time, the second message will be sent only after the first message is sent.

Demo:

private Message buildMessage() throws Exception {
String PACKAGENAME = "com.xiaomi.mipushdemo";
String messagePayload = “This is a message with job key.”;
String title = “notification title”;
String description = “notification description”;
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.passThrough(0) // Display messages on the notification shade
.notifyType(1)
.extra("flow_control", "20000") // Use smooth push, and set the speed as 20000 qps (qps=20000)
.build();
return message;
}

4.10 only send once message

Some developers hope that messages will be delivered only when the device network is connected, and offline messages won't be cached for multiple deliveries.We provided "only send once" feature for sending messages. After turning on it, the message will only be delivered once when the device is online.

The developer can set the "only send once" messages by calling extra(String key, String value) of the Message.Builder class:

key - "only_send_once"
value - "1"

Demo:

private Message buildMessage() throws Exception {
String PACKAGENAME = "com.xiaomi.mipushdemo";
String messagePayload = “This is a message that will only be send once.”;
String title = “notification title”;
String description = “notification description”;
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.passThrough(0) // Display messages on the notification shade
.notifyType(1)
.extra("only_send_once", "1") // Set the message sending times as only once
.build();
return message;
}

5、Get stats data{Deprecated}

com.xiaomi.xmpush.server.Stats class has been removed, to get the stats data of messages, please use com.xiaomi.xmpush.server.Tracer class.

6、Trace message status

Used to track message status

com.xiaomi.xmpush.server.Tracer
Tracer(String appSecret) - appSecret is generated when registering on the Mi Dev Platform and can be viewed under the app details.

This class is used to obtain statistical data of a certain message or messages sent in a certain period of time, such as the number of sent messages, delivered messages, and clicks, etc.;

1. Get the statistics of the specified message ID

String getMessageStatus(String msgId, int retries)
· msgId: The msgId returned after you sent a message (refers to Sender related interfaces).
· retries: The number of retries.
Return value - json string
· id: Message ID.
· raw_counter: The number of targets originally requested by HTTPS.
· resolved: Requested number of target devices minus the number of invlid devices (including the number of deliveries, and the number of targets that can't be delivered due to some other reasons).
· invalid_target: The number of invalid targets (it may be invaid alias, or invalid userAccount etc).
· app_not_register: The number of devices that that haven’t been registered push services on the app.
· device_condition_unmatch: The number of devices whose environment don’t meet the filtering conditions of the message settings, e.g. the network environment, region, app version, or device model etc. 
· msg_send: The actual number of sent messages.
· delivered: The number of message deliveries (the number of messages actually arrive target device).
· delivery_rate: The delivery rate (Rate = Deliveries/Number of effective targets).
· bar_closed: The number of blocked messages in the notification shade.
· msg_display: The number of displayed messages (Number = The number of deliveries - The number of blocked messages in the notification shade).
· click: The number of message taps.
· click_rate: The tap rate of messages (clicks/deliveries).
· create_time: The sending time of the messages.
· time_to_live: The valid time period of the message.
· msg_type: The way of the message sending (such as Common, BatchRegId, Alias, BatchAlias and Topic).

Success:

{
"result" : "ok",
"description" : "Success",
"data" : {
"data" : "{"id" : XXXX, "delivery_rate" : XXXX, "delivered" : XXXX, "resolved" : XXXX, "raw_counter": XXXX, "invalid_target": XXXX, "app_not_register": XXXX, "device_condition_unmatch": XXXX, "msg_type" : XXXX, "create_time" : XXXX, "time_to_live" : XXXX, "click" : XXXX, "click_rate":XXXX}"
},
”code”:0
}

Failure:

{
"result" : "error",
"reason" : "XXXXXXXXX",
"description" : "XXXX",
"code" : XXXX
}

2. Get all message status within a certain time period

String getMessageStatus(long beginTime, long endTime, int retries)
· beginTime: The start time stamp (unit: ms).
· endTime: The end time stamp (unit: ms).
· retries: The number of retries.
Return value - json string;
Note:
· If there are more than 100 messages in that time period, the stats of the 100 messages closest to the end time will be returned.
· The time span between the start and end time can’t exceed 7 days.

Success:

{
"result" : "ok",
"description" : "Success",
"data" : {
"data" : "{"id" : XXXX, "delivery_rate" : XXXX, "delivered" : XXXX, "resolved" : XXXX, "msg_type" : XXXX, "raw_counter": XXXX, "invalid_target": XXXX, "app_not_register": XXXX, "device_condition_unmatch": XXXX, "create_time" : XXXX, "time_to_live" : XXXX, "click" : XXXX, "click_rate":XXXX}"
},
”code”:0
}

Failure:

{
"result" : "error",
"reason" : "XXXXXXXXX",
"description" : "XXXX",
"code" : XXXX
}

3. Get the statistics of the specified jobKey message

String getMessageGroupStatus(String jobKey, int retries)
· jobKey: Set when sending a message (refer to 4. Advanced Features). For messages with the same jobKey, only one message will be displayed on the client, and the statistics of the messages can be obtained in batches through the jobKey.
· retries: The number of retries.
Return value - json string

Success:

{
"result" : "ok",
"description" : "Success",
"data" : {
"data" : "{"id" : XXXX, "delivery_rate" : XXXX, "delivered" : XXXX, "resolved" : XXXX, "msg_type" : XXXX, "create_time" : XXXX, "time_to_live" : XXXX, "click" : XXXX, "click_rate":XXXX}"
},
”code”:0
}

Failure:

{
"result" : "error",
"reason" : "XXXXXXXXX",
"description" : "XXXX",
"code" : XXXX
}

Demo:

public void getTrace() throws Exception {
Tracer tracer = new Tracer(APP_SECRET_KEY); // Use AppSecretKey to create a Tracer object
// Get the delivery status of a single message, parameters: msgId, number of retries
String messageStatus = tracer.getMessageStatus("s1005246409317636237jB", 0);
System.out.println(messageStatus);

// Get the delivery status of messages within a certain time period, parameters: start time, end time, number of retries
String messageStatus2 = tracer.getMessageStatus(System.currentTimeMillis() - 1000, System.currentTimeMillis(), 3);
System.out.println(messageStatus2);
}

7、Subscription

Scenarios:

Tags can be considered as a collection of users with some of shared attributes. We can send a message based on a tag. At this time, all users (devices) who have subscribed to the tag will receive the message (broadcast message). This interface is used to set a tag (add to the collection) or cancel a tag (remove from the collection) of a certain device. We can push messages accurately by setting tags for different user groups.

Interface description:

com.xiaomi.xmpush.server.Subscription
Subscription(String appSecret) - appSecret is generated when registering on the Mi Dev Platform and can be viewed under the app details.

Method list:

subscribeTopic(List regIds, String topic, String category, int retries)Subscribe topic for a group of RegID (the unique identifier that the server returns to the client when registering the app) lists. In which, retries means the number of retries when encountering failure; for category you can set to null. Limit: Maximum of 1000 RegIDs.
subscribeTopic(List regIds, String topic, String packageName, String category, int retries)Subscribe topic for a group of RegID (the unique identifier that the server returns to the client when registering the app) lists. In which, retries means the number of retries when encountering failure; for category you can use null. Limit: Maximum of 1000 RegIDs.

· If there are multiple package names for the app, you must offer 1 specific package name when subscribing topics; otherwise it’s not required.
subscribeTopic(String regId, String topic, String category, int retries)Subscribe topic for a RegID.
subscribeTopic(String regId, String topic, String packageName, String category, int retries)
· Subscribe topic for a RegID.

· If there are multiple package names for the app, you must offer 1 specific package name when subscribing topics; otherwise it’s not required.
unsubscribeTopic(List regIds, String topic, String category, int retries)
· Cancel the subscription of topics for a group of RegID. Limit: Maximum of 1000 RegIDs.
unsubscribeTopic(List regIds, String topic, String packageName, String category, int retries)· Cancel the subscription of topics for a group of RegID. Limit: Maximum of 1000 RegIDs.

· If there are multiple package names for the app, you must offer 1 specific package name when unsubscribing topics; otherwise it’s not required.
unsubscribeTopic(String regId, String topic, String category, int retries)
· Cancel the subscription of topic for a RegID.
unsubscribeTopic(String regId, String topic, String packageName, String category, int retries)
· Cancel the subscription of topic for a RegID.

· If there are multiple package names for the app, you must offer 1 specific package name when unsubscribing topics; otherwise it’s not required.
subscribeTopicByAlias(String topic, List aliases, String category, int retries)· Subscribe topic for a group of alias. Limit: Maximum of 1000 aliases.
subscribeTopicByAlias(String topic, List aliases, String packageName, String category, int retries)· Subscribe topic for a group of alias. Limit: Maximum of 1000 aliases.

· If there are multiple package names for the app, you must offer 1 specific package name when unsubscribing topics; otherwise it’s not required.
unsubscribeTopicByAlias(String topic, List aliases, String category, int retries)
Cancel the subscription of topic for a group of alias. Limit: Maximum of 1000 aliases.
unsubscribeTopicByAlias(String topic, List aliases, String packageName, String category, int retries)Cancel the subscription of topic for a group of alias. Limit: Maximum of 1000 aliases.

· If there are multiple package names for the app, you must offer 1 specific package name when unsubscribing topics; otherwise it’s not required.

8、Pull invalid data{Deprecated}

The Feedback interface is used to pull data such as the invalid RegID or alias.

This interface has been removed. It is recommended that you use the message receipt callback interface (callback.type: 16) to filter invalid data.

9、Batch query RegID’s registration region

If the target users include users inside and outside mainland China, you can use this interface to query the the target user's home region, and then use the interfaces inside and outside mainland China to push messages respectively.

Interface introduction:

String getRegionByRegIds(List regIds, int retries)
· regIds: RegID list

· retries: The number of retries.

Return value:

· Success

{
"result": "ok",
"trace_id": "Xcm54810571643337078jz",
"code": 0,
"data": {
"regid1": "CN",
"regid2": "CN"
},
"description": "Success"
}

· Failure

{
"result" : "error",
"reason" : "XXXXXXXXX",
"description" : "XXXX",
"code" : XXXX
}

Description:

After calling this interface to get the registration region of the RegID, you need to call the mainland China and global push interfaces for target devices respectively when sending messages.

· mainland China

Sender sender = new Sender(APP_SECRET_KEY);

· Russia

Sender sender = new Sender(APP_SECRET_KEY, Region.Russia);

· India

Sender sender = new Sender(APP_SECRET_KEY, Region.India);

· EEA+UK

Sender sender = new Sender(APP_SECRET_KEY, Region.Europe);

· other countries/regions

Sender sender = new Sender(APP_SECRET_KEY, Region.Singapore);

10、 FAQ

Terms:

What is traceID?

After calling our SDK to send a message, there will always be a traceID field in the result, which represents the unique identification of this operation request on our server, so through this traceID, we can locate the related issues of requested access and investigation;

What is messageID?

The messageID is used to identify a message, through the messageID we can investigate the activity cycle of the message;

Abnormal problems

There are mainly 3 types of situations:

Network problem, certification problem, and code vulnerability;

Network problem

Confirm whether the network is connected to the api.global.xmpush.xiaomi.com

Certification problem

The server interface uses HTTPS method, confirm whether the certification is imported locally;

Code vulnerability

Refer to the Guide for Mi Push Server Side SDK to confirm whether it is due to missing parameters or wrong calling method;

11、Appendix:

Appendix 1: Country/Region Language Codes (Based on ISO-3166 Standard)

Language CodeLanguage_Region Description (Chinese)Language_Region Description (English)
af_ZA南非荷兰语_南非Afrikaans_South Africa
am_ET阿姆哈拉语_埃塞俄比亚Amharic_Ethiopia
ar阿拉伯语_allArabic_all
ar_AE阿拉伯语_阿拉伯联合酋长国Arabic_United Arab Emirates
ar_BH阿拉伯语_巴林Arabic_Bahrain
ar_DZ阿拉伯语_阿尔及利亚Arabic_Algeria
ar_EG阿拉伯语_埃及Arabic_Egypt
ar_EG_#u_nu_latn阿拉伯文_埃及#u_nu_latnArabic_Egypt#u_nu_latn
ar_GBArabic_Egypt#u_nu_latnArabic_United Kingdom
ar_IL阿拉伯语_以色列Arabic_Israel
ar_IQ阿拉伯语_伊拉克Arabic_Iraq
ar_JO阿拉伯语_约旦Arabic_Jordan
ar_KW阿拉伯语_科威特Arabic_Kuwait
ar_LB阿拉伯语_黎巴嫩Arabic_Lebanon
ar_LY阿拉伯语_利比亚Arabic_Libya
ar_MA阿拉伯语_摩洛哥Arabic_Morocco
ar_OM阿拉伯语_阿曼Arabic_Oman
ar_PS阿拉伯语_巴勒斯坦Arabic_Palestine
ar_QA阿拉伯语_卡塔尔Arabic_Qatar
ar_SA阿拉伯语_沙特阿拉伯Arabic_Saudi Arabia
ar_SD阿拉伯语_苏丹Arabic_Sudan
ar_SY阿拉伯语_叙利亚Arabic_Syrian
ar_TN阿拉伯语_突尼斯Arabic_Tunisia
ar_US阿拉伯语_美国Arabic_United States
ar_YE阿拉伯语_也门Arabic_Yemen
arn_CL马普切语_智利Mapuche_Chile
as_IN阿萨姆语_印度Assamese_India
az_AZ阿塞拜疆语_阿塞拜疆Azerbaijani_Azerbaijani
az_AZ_#Latn阿塞拜疆语_阿塞拜疆#LatnAzerbaijani_Azerbaijan#Latn
az_Cyrl阿塞拜疆语_西里尔文Azerbaijani_Cyrillic
az_Latn阿塞拜疆语_拉丁文Azerbaijani_Latin
ba_RU巴什基尔语_俄罗斯Bashkir_Russia
be_BY白俄罗斯语_白俄罗斯Belarusian_Belarus
bg_BD孟加拉语_孟加拉Bengali_Bangladesh
bg_BG保加利亚语_保加利亚Bulgarian_Bulgarian
bg_IN孟加拉语_印度Bengali_India
bn孟加拉语_allBengali_all
bn_BD孟加拉语 (孟加拉)_孟加拉国Bengali (Bangladesh)_Bangladesh
bn_IN孟加拉语 (印度)_印度Bengali (India)_India
bo_CN藏语_中国Tibetan_China
br_FR布列塔尼语_法国Breton_France
bs_BA波斯尼亚语_波黑Bosnian_Bosnian
bs_Cyrl波斯尼亚语_西里尔文Bosnian_Cyrillic
bs_Latn波斯尼亚语_拉丁文Bosnian_Latin
ca_ES加泰罗尼亚语_西班牙Catalan_Spain
co_FR科西嘉语_法国Corsican_France
cs_CZ捷克语_捷克共和国Czech_Czech Republic
cy_GB威尔士语_英国Welsh_United Kingdom
da_DK丹麦语_丹麦Danish_Denmark
de德语_allGerman_all
de_AT德语_奥地利German_Austria
de_CH德语_瑞士German_Switzerland
de_DE德语_德国_Dictionary排序German_Germany_Dictionary sort
de_LI德语_列支敦士登German_Liechtenstein
de_LU德语_卢森堡German_Luxembourg
dsb_DE下索布语_德语Lower Sorbian_German
dv_MF迪维西语_马尔代夫Divisian_Maldives
el_GR希腊语_希腊Greek_Greek
en英语_allEnglish_all
en_029英语_加勒比(en_029)English_Caribbean (en_029)
en_AE英语_阿拉伯联合酋长国English_United Arab Emirates
en_AI英语_安圭拉English_Anguilla
en_AS英语_美属萨摩亚English_American Samoa
en_AT英语_奥地利English_Austria
en_AU英语_澳大利亚English_Australia
en_BD英语_孟加拉国English_Bangladesh
en_BE英语_比利时English_Belgium
en_BG英语_保加利亚English_Bulgarian
en_BR英语_巴西English_Brazil
en_BZ英语_伯利兹English_Belize
en_CA英语_加拿大English_Canada
en_CB英语_加勒比(en_CB)English_Caribbean (en_CB)
en_CH英语_瑞士English_Switzerland
en_CN英语_中国English_China
en_EE英语_爱沙尼亚English_Estonia
en_EG英语_埃及English_Egypt
en_ES英语_西班牙English_Spain
en_FI英语_芬兰English_Finland
en_FR英语_法国English_France
en_GB英语_英国English_UK
en_GR英语_希腊English_Greek
en_HK英语_中国香港English_Hong Kong, China
en_HU英语_匈牙利English_California
en_ID英语_印尼English_Indonesia
en_IE英语_爱尔兰English_Ireland
en_IL英语_以色列English_Israel
en_IN英语_印度English_India
en_IO英语_英属印度洋领地English_British Indian Ocean Territory
en_IQ英语_伊拉克English_Iraq
en_IR英语_伊朗English_Iran
en_JM英语_牙买加English_Jamaica
en_JP英语_日本English_Japan
en_KE英语_肯尼亚English_Kenya
en_KH英语_柬埔寨English_Cambodia
en_KR英语_韩国English_Korea
en_KW英语_科威特English_Kuwait
en_LT英语_立陶宛English_Lithuania
en_LV英语_拉脱维亚English_Latvia
en_MM英语_缅甸English_Myanmar
en_MO英语_中国澳门English_Macau, China
en_MX英语_墨西哥English_Mexico
en_MY英语_马来西亚English_Malaysia
en_NG英语_尼日利亚English_Nigeria
en_NL英语_荷兰English_Netherlands
en_NO英语_挪威English_Norway
en_NZ英语_新西兰English_New Zealand
en_OC英语_OCEnglish_OC
en_PH英语_菲律宾English_Philippines
en_PK英语_巴基斯坦English_Pakistan
en_PL英语_波兰English_Poland
en_QA英语_卡塔尔English_Qatar
en_RO英语_罗马尼亚English_Montreal
en_RU英语_俄罗斯English_Russian
en_SA英语_沙特阿拉伯English_Saudi Arabia
en_SE英语_瑞典English_Sweden
en_SG英语_新加坡English_Singapore
en_SI英语_斯洛文尼亚English_Slovenia
en_TH英语_泰国English_Thailand
en_TR英语_土耳其English_Turkish
en_TT英语_特立尼达岛English_Trinidad
en_UA英语_乌克兰English_Ukraine
en_US英语_美国English_United States
en_VN英语_越南English_Vietnam
en_ZA英语_南非English_South Africa
en_ZG英语_ZGEnglish_ZG
en_ZW英语_津巴布韦English_Zimbabwe
es西班牙语_allSpanish_all
es_419西班牙语_419Spanish_419
es_AR西班牙语_阿根廷Spanish_Argentina
es_BO西班牙语_玻利维亚Spanish_Bolivia
es_CL西班牙语_智利Spanish_Chile
es_CO西班牙语_哥伦比亚Spanish_Colombia
es_CR西班牙语_哥斯达黎加Spanish_Costa Rica
es_CU西班牙语_古巴Spanish_Cuba
es_DO西班牙语_多米尼加共和国Spanish_Dominican Republic
es_EA西班牙语_休达及美利拉Spanish _ Ceuta and Melilla
es_EC西班牙语_厄瓜多尔Spanish_Ecuador
es_ES西班牙语_西班牙 (现代)Spanish_Spain (modern)
es_GT西班牙语_危地马拉Spanish_Guatemala
es_HN西班牙语_洪都拉斯Spanish_Honduras
es_IC西班牙语_ 加那利群岛Spanish_Canary Islands
es_MX西班牙语_墨西哥Spanish_Mexico
es_NI西班牙语_尼加拉瓜Spanish_Nicaragua
es_PA西班牙语_巴拿马Spanish_Panama
es_PE西班牙语_秘鲁Spanish_Peru
es_PR西班牙语_波多黎各Spanish_Puerto Rico
es_PY西班牙语_巴拉圭Spanish_Paraguay
es_SV西班牙语_萨尔瓦多Spanish_El Salvador
es_US西班牙语_美国Spanish_United States
es_UY西班牙语_乌拉圭Spanish_Uruguay
es_VE西班牙语_委内瑞拉Spanish_Venezuela
et_EE爱沙尼亚语_爱沙尼亚Estonian_Estonian
eu_ES巴斯克语_西班牙Basque_Spain
fa_AF波斯语_阿富汗Persian_Afghanistan
fa_FA波斯语_波斯Persian_Persian
fa_IR波斯语_伊朗Persian_Iran
fa_IR_#u_nu_latn波斯语_伊朗#u_nu_latnPersian_Iran#u_nu_latn
fa_IR_LNum波斯语_伊朗_拉丁文Persian_Iranian_Latin
fi_FI芬兰语_芬兰Finnish_Finland
fil_PH菲律宾语_菲律宾Filipino_Philippines
fr法语_allFrench_all
fr_BE法语_比利时French_Belgium
fr_BF法语_布基纳法索French_Burkina Faso
fr_CA法语_加拿大French_Canada
fr_CD法语_刚果民主共和国French_Democratic Republic of the Congo
fr_CH法语_瑞士French_Switzerland
fr_CI法语_科特迪瓦French_Côte d'Ivoire
fr_CM法语_喀麦隆French_Cameroon
fr_DZ法语_阿尔及利亚French_Algeria
fr_FR法语_法国French_France
fr_LU法语_卢森堡French_Luxembourg
fr_MA法语_摩洛哥French_Morocco
fr_SN法语_塞内加尔French_Senegal
fr_TN法语_突尼斯French_Tunisia
gd_IE盖尔语_爱尔兰Gaelic_Ireland
gl_ES加利西亚_西班牙Galicia_Spain
gu卡纳达语_allKannada_all
gu_IN古吉拉特语_印度Gujarati_India
ha_NG豪萨语_尼日利亚Hausa_Nigeria
he_IL希伯来_以色列Hebrew_Israel(he_IL)
hi印地文_allHindi_all
hi_IN印地文_印度Hindi_India
hr_BA克罗地亚语_波黑Croatian_Bosnia and Herzegovina
hr_HR克罗地亚语_克罗地亚Croatian_Croatia
hu_HU匈牙利Hungary
hy_AM亚美尼亚语_亚美尼亚Armenian_Armenian
id_ID印尼语_印尼Indonesian_Indonesia(id_ID)
in印度尼西亚语_allIndonesian_all
in_ID印尼语_印度尼西亚Indonesian_Indonesia(in_ID)
it_CH意大利语_瑞士Italian_Switzerland
it_IT意大利语_意大利Italian_Italy
iw_IL希伯来语_以色列Hebrew_Israel
ja日语_allJapanese_all
ja_CN日语_中国Japanese_China
ja_JP日语_日本Japanese_Japan
ka_GE格鲁吉亚语_格鲁吉亚Georgian_Georgian
kk_KZ哈萨克语_哈萨克斯坦Kazakh_Kazakhstan
km_KH高棉 (柬埔寨语)_柬埔寨Khmer (Cambodian)_Cambodia
kn古吉拉特语_allGujarati_all
kn_IN卡纳达语_印度Kannada_India
ko朝鲜语_allKorean_all
ko_CN韩语_中国Korean_China
ko_KR韩语_韩国Korean_Korea
ko_US韩语_美国Korean_United States
lo_LA老挝语_老挝Lao_Lao
lt立陶宛语_allLithuanian_all
lt_LT立陶宛_立陶宛Lithuania_Lithuania
lv拉脱维亚语_allLatvian_all
lv_LV拉脱维亚语_拉脱维亚Latvian_Latvia
mk马其顿_allMacedonia_all
mk_MK马其顿_马其顿Macedonia_Macedonia
ml马拉雅拉姆语_allMalayalam_all
ml_IN马拉雅拉姆语_印度Malayalam_India
mn_MN蒙古语 _蒙古Mongolian _ Mongolia
mr马拉地语_allMarathi_all
mr_IN马拉地语_印度Marathi_India
ms_BN马来语_文莱Malay_Brunei
ms_MY马来语_马来西亚Malay_Malaysia
mt马耳他语_allMaltese_all
mt_MT马耳他语_马耳他Maltese_Malta
mx_MX缅甸语_墨西哥Burmese_Mexico
my_MM缅甸语_缅甸Burmese_Myanmar
my_ZG缅甸语_ZGBurmese_ZG
nb_NO伯克梅尔语_挪威Birkmel _ Norway
ne_IN尼泊尔语(印度)_印度Nepali (India)_India
ne_NP尼泊尔语(尼泊尔)_尼泊尔Nepali (Nepal)_Nepal
nl_BE荷兰语_比利时Dutch_Belgium
nl_NL荷兰语_荷兰Dutch_Netherlands
nn_NO尼诺斯克语_挪威Nynorsk_Norway
or奥里雅语_allOriya_all
or_IN奥利亚语_印度Oriya_India
pa旁遮普_allPunjab_all
pa_IN旁遮普_印度Punjab_India
pa_IN_#Guru旁遮普_印度#GuruPunjab_India#Guru
pl波兰语_allPolish_all
pl_PL菲律宾Philippines
pt_AO葡萄牙语_安哥拉Portuguese_Angola
pt_br葡萄牙语_巴西Portuguese_Brazil
pt_CV葡萄牙语_佛得角Portuguese_Cape Verde
pt_GW葡萄牙语_几内亚比绍Portuguese_Guinea Bissau
pt_MZ葡萄牙语_莫桑比克Portuguese_Mozambique
pt_PT葡萄牙语_葡萄牙Portuguese_Portugal
rm罗曼什语_allRomansh_all
ro罗马尼亚语_罗马尼亚Romanian_Romania
ro_MD罗马尼亚_摩尔多瓦Romania_Moldova
ro_mo罗马尼亚语_摩尔多瓦共和国Romanian_Republic of Moldova
ro_RO罗马尼亚Romania
ru俄语_allRussian_all
ru_IL俄语_以色列Russian_Israel
ru_KG俄语_吉尔吉斯坦Russian_Kyrgyzstan
ru_KZ俄语_哈萨克斯坦Russian_Kazakhstan
ru_MD俄语_摩尔多瓦Russian_Moldova
ru_mo俄语_摩尔多瓦共和国Russian_Republic of Moldova
ru_RU俄罗斯Russia
sa梵文_allSanskrit_all
sb索布语_allSorbian_all
sk斯洛伐克语_allSlovak_all
sk_SK斯洛伐克语Slovak
sl斯洛文尼亚语_allSlovenian_all
sl_SI斯洛文尼亚语_斯洛文尼亚Slovenian_Slovenian
sq_AL阿尔巴尼亚语_阿尔巴尼亚Albanian_Albanian
sr_ME_#Cyrl塞尔维亚语_黑山_西里尔文Serbian_Montenegro_Cyrillic
sr_RS塞尔维亚语_塞尔维亚Serbian_Serbia
sr_RS_#Cyrl塞尔维亚语_塞尔维亚#CyrlSerbian_Serbian#Cyrl
sr_RS_#Latn塞尔维亚语_塞尔维亚#LatnSerbian_Serbian#Latn
sr_sp_Cyrl塞尔维亚语_西里尔字母Serbian _ Cyrillic
sr_sp_Latn塞尔维亚语_拉丁文Serbian_Latin
st南部索托语_allSouthern Soto_all
sv_FI瑞典语_芬兰Swedish_Finland
sv_SE瑞典语_瑞典Swedish_Sweden
sw斯瓦希里语_allSwahili_all
ta泰米尔语_allTamil_all
ta_IN泰米尔语_印度Tamil_India
te泰卢固语_allTelugu_all
te_IN泰卢固语_印度Telugu_India
th泰语_allThai_all
th_GB泰语_英国Thai_UK
th_TH泰语_泰国Thai_Thailand
th_US泰语_美国Thai_United States
tn茨瓦纳语_allTswana_all
tr土耳其语_allTurkish_all
tr_CY土耳其_塞浦路斯Turkey_Cyprus
tr_TR土耳其Turkey
ts特松加语_allTsonga_all
tt鞑靼语_allTatar_all
uk乌克兰语_allUkrainian_all
uk_UA乌克兰Ukraine
undundund
ur乌都语_allUdo_all
ur_IN乌尔都语_印度Urdu_India
ur_PK乌尔都语(巴基斯坦)_巴基斯坦Urdu (Pakistan)_Pakistan
uz_UZ乌兹别克语_乌兹别克斯坦Uzbek_Uzbekistan
uz_UZ_#Latn乌兹别克语_乌兹别克斯坦#LatnUzbek_Uzbekistan#Latn
uz_UZ_Cyrl乌兹别克语_西里尔文Uzbek_Cyrillic
uz_UZ_Latn乌兹别克语_拉丁文Uzbek_Latin
vi越南语_allVietnamese_all
vi_US越南语_美国Vietnamese_United States
vi_VN越南语_越南Vietnamese_Vietnamese
xh班图语_allBantu_all
yi意第绪语_allYiddish_all
zh中文_allChinese_all
zh_AE_#Hans中文_阿拉伯联合酋长国_#HansChinese_United Arab Emirates_#Hans
zh_AU_#Hans中文_澳大利亚_#HansChinese_Australia_#Hans
zh_CA_#Hans中文_加拿大_#HansChinese_Canada_#Hans
zh_CN中文_中国大陆_拼音排序Chinese_Mainland China_Pinyin Ranking
zh_CN_#Hans中文_中国#HansChinese_China #Hans
zh_CN_#Hant中文_中国_#HantChinese_中国_#Hant
zh_DE_#Hans中文_德国_#HansChinese_Germany_#Hans
zh_ES_#Hans中文_西班牙_#HansChinese_Spain_#Hans
zh_FR_#Hans中文_法国_#HansChinese_France_#Hans
zh_GB_#Hans中文_英国_#HansChinese_UK_#Hans
zh_Han_AU中文_Han_澳大利亚Chinese_Han_Australia
zh_Hans中文_简体Chinese_Simplified
zh_Hans_AU中文_简体_澳大利亚Chinese_Simplified_Australia
zh_Hans_CA中文_简体_加拿大Chinese_Simplified_Canada
zh_Hans_CN中文_简体_中国Chinese_Simplified_China
zh_Hans_DE中文_简体_德国Chinese_Simplified_Germany
zh_Hans_ES中文_简体_西班牙Chinese_Simplified_Spain
zh_Hans_FR中文_简体_法国Chinese_Simplified_France
zh_Hans_GB中文_简体_英国Chinese_Simplified_UK
zh_Hans_HK中文_简体_中国香港Chinese_Simplified_Hong Kong, China
zh_Hans_IT中文_简体_意大利Chinese_Simplified_Italy
zh_Hans_JP中文_简体_日本Chinese_Simplified_Japan
zh_Hans_KR中文_简体_韩国Chinese_Simplified_South Korea
zh_Hans_MO中文_简体_中国澳门Chinese_Simplified_Macao, China
zh_Hans_MY中文_简体_马来西亚Chinese_Simplified_Malaysia
zh_Hans_NZ中文_简体_新西兰Chinese_Simplified_New Zealand
zh_Hans_PH中文_简体_菲律宾Chinese_Simplified_Filipino
zh_Hans_SG中文_简体_新加坡Chinese_Simplified_Singapore
zh_Hans_TH中文_简体_泰国Chinese_Simplified_Thailand
zh_Hans_TW中文_简体_台湾Chinese_Simplified_Taiwan
zh_Hans_US中文_简体_美国Chinese_Simplified_United States
zh_Hant中文_繁体Chinese_Traditional
zh_Hant_AU中文_繁体_澳大利亚Chinese_Traditional_Australia
zh_Hant_CN中文_繁体_中国Chinese_Traditional_China
zh_Hant_HK中文_繁体_中国香港Chinese_Traditional_Hong Kong, China
zh_Hant_JP中文_繁体_日本Chinese_Traditional_Japan
zh_Hant_MO中文_繁体_中国澳门Chinese_Traditional_Macao, China
zh_Hant_TW中文_繁体_台湾Chinese_Traditional_Taiwan
zh_Hant_US中文_繁体_美国Chinese_Traditional_United States
zh_HK中文_香港特别行政区Chinese_Hong Kong Special Administrative Region
zh_HK_#Hans中文_中国香港_#HansChinese_Hong Kong, China_#Hans
zh_HK_#Hant中文_中国香港_#HantChinese_Hong Kong, China_#Hant
zh_IT_#Hans中文_意大利_#HansChinese_Italian_#Hans
zh_JP_#Hans中文_日本_#HansChinese_日本_#Hans
zh_MM_#Hans中文_缅甸_#HansChinese_Myanmar_#Hans
zh_MO中文_澳门特别行政区Chinese_Macao Special Administrative Region
zh_MO_#Hans中文_中国澳门_#HansChinese_Macau_China_#Hans
zh_MO_#Hant中文_中国澳门_#HantChinese_Macau_China_#Hant
zh_MY_#Hans中文_马来西亚_#HansChinese_Malaysia_#Hans
zh_MY_#Hant中文_马来西亚_#HantChinese_Malaysia_#Hant
zh_NZ_#Hans中文_新西兰_#HansChinese_New Zealand_#Hans
zh_PA_#Hans中文_巴拿马_#简体(zh_PA_#Hans)Chinese_Panama_#Simplified
zh_PH_#Hans中文_菲律宾_#HansChinese_Philippines_#Hans
zh_RU_#Hans中文_俄罗斯_#HansChinese_Russian_#Hans
zh_SG中文_新加坡Chinese_Singapore
zh_SG_#Hans中文_新加坡_#HansChinese_Singapore_#Hans
zh_TH_#Hans中文_泰国_#HansChinese_Thailand_#Hans
zh_TW中文_台湾地区Chinese_Taiwan
zh_TW_#Hans中文_台湾_#HansChinese_Taiwan_#Hans
zh_TW_#Hant中文_台湾#HantChinese_Taiwan#Hant
zh_US_#Hans中文_美国_#HansChinese_US_#Hans
zh_VN_#Hans中文_越南_#HansChinese_Vietnam_#Hans
zh_ZG_#Hans中文_ZG_#HansChinese_ZG_#Hans
zu祖鲁语_allZulu_all

Appendix 2: Brand List

Brandmodel
小米xiaomi
三星samsung
华为huawei
中兴zte
中兴努比亚nubia
酷派coolpad
联想lenovo
魅族meizu
HTChtc
OPPOoppo
VIVOvivo
摩托罗拉motorola
索尼sony
LGlg
金立jinli
天语tianyu
诺基亚nokia
美图秀秀meitu
谷歌google
TCLtcl
锤子手机chuizi
一加手机1+
中国移动china mobile
昂达angda
邦华banghua
波导bird
长虹changhong
大可乐dakele
朵唯doov
海尔haier
海信hisense
康佳konka
酷比魔方kubimofang
米歌mige
欧博信ouboxin
欧新ouxin
飞利浦philip
维图voto
小辣椒xiaolajiao
夏新xiaxin
亿通yitong
语信yuxin

Appendix 3: Price Range

Price rangemodel
0-9990-999
1000-19991000-1999
2000-39992000-3999
Above 40004000+

Mi Push FAQ