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
Class | Description |
Message | Message object |
Builder | Message creator for an Android device |
IOSBuilder | Message creator for an iOS device |
TargetedMessage | Message content and target |
Sender | Message Sender |
Result | Returned results from the server side after message is sent |
Stats | Statistics of sent messages |
Tracer | Trace message status |
Subscription | Subscribe/unsubscribe tags |
Feedback | Feedback 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. |
Constants | Constant definition |
ErrorCode | Error 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
Method | Description |
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.
Method | Description |
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:
Method | Description |
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 Version | Emoji Version | Unicode Version | Unicode Emoji Release Date | Android Support Date | Emoji Amount |
7.1 | 4 | 9 | 2016.07.21 | 2016.10.20 | 2374 |
7 | 3 | 9 | 2016.07.21 | 2016.08.22 | 1791 |
6.0.1 | 1 | 8 | 2015.07.17 | 2015.12.07 | 1294 |
6 | 1 | 7 | 2014.07.16 | Unknown | Unknown |
5 | 1 | 6.1 | 2012.02 | 2014.11.03 | 1090 |
4.4 | 1 | 6 | 2010.1 | 2014.11.01 | 850 |
4.3 | 1 | 6 | 2010.1 | 2013.07.24 | 717 |
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:
Method | Description |
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
Method | Description |
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
Method | Description |
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
Method | Description |
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
Method | Description |
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.
Method | Description |
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 Version | MIUI Global Version | |
Message content | Supports 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 icon | Only 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 shade | 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. | 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. |
Button | Supports 0~3 buttons | Supports 0~3 buttons |
【Large image styles】
MIUI mainland China Version | MIUI Global Version | |
Message content | Up 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. |
Image | Fixed 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 icon | Only 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 shade | 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. | 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. |
Button | Supports 0~3 buttons | Supports 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.
key | value |
channel_id | Indicates 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:
Key | Meaning of the Value |
callback | String (required field), the Http address of your server to receive the receipt, the maximum length is 128 bytes. |
callback.param | String (optional field), customized receipt parameters to decide which types of information are returned in the callback, the maximum length is 64 bytes. |
callback.type | String (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 Code | Language_Region Description (Chinese) | Language_Region Description (English) |
af_ZA | 南非荷兰语_南非 | Afrikaans_South Africa |
am_ET | 阿姆哈拉语_埃塞俄比亚 | Amharic_Ethiopia |
ar | 阿拉伯语_all | Arabic_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_latn | Arabic_Egypt#u_nu_latn |
ar_GB | Arabic_Egypt#u_nu_latn | Arabic_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 | 阿塞拜疆语_阿塞拜疆#Latn | Azerbaijani_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 | 孟加拉语_all | Bengali_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 | 德语_all | German_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 | 英语_all | English_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 | 英语_OC | English_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 | 英语_ZG | English_ZG |
en_ZW | 英语_津巴布韦 | English_Zimbabwe |
es | 西班牙语_all | Spanish_all |
es_419 | 西班牙语_419 | Spanish_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_latn | Persian_Iran#u_nu_latn |
fa_IR_LNum | 波斯语_伊朗_拉丁文 | Persian_Iranian_Latin |
fi_FI | 芬兰语_芬兰 | Finnish_Finland |
fil_PH | 菲律宾语_菲律宾 | Filipino_Philippines |
fr | 法语_all | French_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 | 卡纳达语_all | Kannada_all |
gu_IN | 古吉拉特语_印度 | Gujarati_India |
ha_NG | 豪萨语_尼日利亚 | Hausa_Nigeria |
he_IL | 希伯来_以色列 | Hebrew_Israel(he_IL) |
hi | 印地文_all | Hindi_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 | 印度尼西亚语_all | Indonesian_all |
in_ID | 印尼语_印度尼西亚 | Indonesian_Indonesia(in_ID) |
it_CH | 意大利语_瑞士 | Italian_Switzerland |
it_IT | 意大利语_意大利 | Italian_Italy |
iw_IL | 希伯来语_以色列 | Hebrew_Israel |
ja | 日语_all | Japanese_all |
ja_CN | 日语_中国 | Japanese_China |
ja_JP | 日语_日本 | Japanese_Japan |
ka_GE | 格鲁吉亚语_格鲁吉亚 | Georgian_Georgian |
kk_KZ | 哈萨克语_哈萨克斯坦 | Kazakh_Kazakhstan |
km_KH | 高棉 (柬埔寨语)_柬埔寨 | Khmer (Cambodian)_Cambodia |
kn | 古吉拉特语_all | Gujarati_all |
kn_IN | 卡纳达语_印度 | Kannada_India |
ko | 朝鲜语_all | Korean_all |
ko_CN | 韩语_中国 | Korean_China |
ko_KR | 韩语_韩国 | Korean_Korea |
ko_US | 韩语_美国 | Korean_United States |
lo_LA | 老挝语_老挝 | Lao_Lao |
lt | 立陶宛语_all | Lithuanian_all |
lt_LT | 立陶宛_立陶宛 | Lithuania_Lithuania |
lv | 拉脱维亚语_all | Latvian_all |
lv_LV | 拉脱维亚语_拉脱维亚 | Latvian_Latvia |
mk | 马其顿_all | Macedonia_all |
mk_MK | 马其顿_马其顿 | Macedonia_Macedonia |
ml | 马拉雅拉姆语_all | Malayalam_all |
ml_IN | 马拉雅拉姆语_印度 | Malayalam_India |
mn_MN | 蒙古语 _蒙古 | Mongolian _ Mongolia |
mr | 马拉地语_all | Marathi_all |
mr_IN | 马拉地语_印度 | Marathi_India |
ms_BN | 马来语_文莱 | Malay_Brunei |
ms_MY | 马来语_马来西亚 | Malay_Malaysia |
mt | 马耳他语_all | Maltese_all |
mt_MT | 马耳他语_马耳他 | Maltese_Malta |
mx_MX | 缅甸语_墨西哥 | Burmese_Mexico |
my_MM | 缅甸语_缅甸 | Burmese_Myanmar |
my_ZG | 缅甸语_ZG | Burmese_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 | 奥里雅语_all | Oriya_all |
or_IN | 奥利亚语_印度 | Oriya_India |
pa | 旁遮普_all | Punjab_all |
pa_IN | 旁遮普_印度 | Punjab_India |
pa_IN_#Guru | 旁遮普_印度#Guru | Punjab_India#Guru |
pl | 波兰语_all | Polish_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 | 罗曼什语_all | Romansh_all |
ro | 罗马尼亚语_罗马尼亚 | Romanian_Romania |
ro_MD | 罗马尼亚_摩尔多瓦 | Romania_Moldova |
ro_mo | 罗马尼亚语_摩尔多瓦共和国 | Romanian_Republic of Moldova |
ro_RO | 罗马尼亚 | Romania |
ru | 俄语_all | Russian_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 | 梵文_all | Sanskrit_all |
sb | 索布语_all | Sorbian_all |
sk | 斯洛伐克语_all | Slovak_all |
sk_SK | 斯洛伐克语 | Slovak |
sl | 斯洛文尼亚语_all | Slovenian_all |
sl_SI | 斯洛文尼亚语_斯洛文尼亚 | Slovenian_Slovenian |
sq_AL | 阿尔巴尼亚语_阿尔巴尼亚 | Albanian_Albanian |
sr_ME_#Cyrl | 塞尔维亚语_黑山_西里尔文 | Serbian_Montenegro_Cyrillic |
sr_RS | 塞尔维亚语_塞尔维亚 | Serbian_Serbia |
sr_RS_#Cyrl | 塞尔维亚语_塞尔维亚#Cyrl | Serbian_Serbian#Cyrl |
sr_RS_#Latn | 塞尔维亚语_塞尔维亚#Latn | Serbian_Serbian#Latn |
sr_sp_Cyrl | 塞尔维亚语_西里尔字母 | Serbian _ Cyrillic |
sr_sp_Latn | 塞尔维亚语_拉丁文 | Serbian_Latin |
st | 南部索托语_all | Southern Soto_all |
sv_FI | 瑞典语_芬兰 | Swedish_Finland |
sv_SE | 瑞典语_瑞典 | Swedish_Sweden |
sw | 斯瓦希里语_all | Swahili_all |
ta | 泰米尔语_all | Tamil_all |
ta_IN | 泰米尔语_印度 | Tamil_India |
te | 泰卢固语_all | Telugu_all |
te_IN | 泰卢固语_印度 | Telugu_India |
th | 泰语_all | Thai_all |
th_GB | 泰语_英国 | Thai_UK |
th_TH | 泰语_泰国 | Thai_Thailand |
th_US | 泰语_美国 | Thai_United States |
tn | 茨瓦纳语_all | Tswana_all |
tr | 土耳其语_all | Turkish_all |
tr_CY | 土耳其_塞浦路斯 | Turkey_Cyprus |
tr_TR | 土耳其 | Turkey |
ts | 特松加语_all | Tsonga_all |
tt | 鞑靼语_all | Tatar_all |
uk | 乌克兰语_all | Ukrainian_all |
uk_UA | 乌克兰 | Ukraine |
und | und | und |
ur | 乌都语_all | Udo_all |
ur_IN | 乌尔都语_印度 | Urdu_India |
ur_PK | 乌尔都语(巴基斯坦)_巴基斯坦 | Urdu (Pakistan)_Pakistan |
uz_UZ | 乌兹别克语_乌兹别克斯坦 | Uzbek_Uzbekistan |
uz_UZ_#Latn | 乌兹别克语_乌兹别克斯坦#Latn | Uzbek_Uzbekistan#Latn |
uz_UZ_Cyrl | 乌兹别克语_西里尔文 | Uzbek_Cyrillic |
uz_UZ_Latn | 乌兹别克语_拉丁文 | Uzbek_Latin |
vi | 越南语_all | Vietnamese_all |
vi_US | 越南语_美国 | Vietnamese_United States |
vi_VN | 越南语_越南 | Vietnamese_Vietnamese |
xh | 班图语_all | Bantu_all |
yi | 意第绪语_all | Yiddish_all |
zh | 中文_all | Chinese_all |
zh_AE_#Hans | 中文_阿拉伯联合酋长国_#Hans | Chinese_United Arab Emirates_#Hans |
zh_AU_#Hans | 中文_澳大利亚_#Hans | Chinese_Australia_#Hans |
zh_CA_#Hans | 中文_加拿大_#Hans | Chinese_Canada_#Hans |
zh_CN | 中文_中国大陆_拼音排序 | Chinese_Mainland China_Pinyin Ranking |
zh_CN_#Hans | 中文_中国#Hans | Chinese_China #Hans |
zh_CN_#Hant | 中文_中国_#Hant | Chinese_中国_#Hant |
zh_DE_#Hans | 中文_德国_#Hans | Chinese_Germany_#Hans |
zh_ES_#Hans | 中文_西班牙_#Hans | Chinese_Spain_#Hans |
zh_FR_#Hans | 中文_法国_#Hans | Chinese_France_#Hans |
zh_GB_#Hans | 中文_英国_#Hans | Chinese_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 | 中文_中国香港_#Hans | Chinese_Hong Kong, China_#Hans |
zh_HK_#Hant | 中文_中国香港_#Hant | Chinese_Hong Kong, China_#Hant |
zh_IT_#Hans | 中文_意大利_#Hans | Chinese_Italian_#Hans |
zh_JP_#Hans | 中文_日本_#Hans | Chinese_日本_#Hans |
zh_MM_#Hans | 中文_缅甸_#Hans | Chinese_Myanmar_#Hans |
zh_MO | 中文_澳门特别行政区 | Chinese_Macao Special Administrative Region |
zh_MO_#Hans | 中文_中国澳门_#Hans | Chinese_Macau_China_#Hans |
zh_MO_#Hant | 中文_中国澳门_#Hant | Chinese_Macau_China_#Hant |
zh_MY_#Hans | 中文_马来西亚_#Hans | Chinese_Malaysia_#Hans |
zh_MY_#Hant | 中文_马来西亚_#Hant | Chinese_Malaysia_#Hant |
zh_NZ_#Hans | 中文_新西兰_#Hans | Chinese_New Zealand_#Hans |
zh_PA_#Hans | 中文_巴拿马_#简体(zh_PA_#Hans) | Chinese_Panama_#Simplified |
zh_PH_#Hans | 中文_菲律宾_#Hans | Chinese_Philippines_#Hans |
zh_RU_#Hans | 中文_俄罗斯_#Hans | Chinese_Russian_#Hans |
zh_SG | 中文_新加坡 | Chinese_Singapore |
zh_SG_#Hans | 中文_新加坡_#Hans | Chinese_Singapore_#Hans |
zh_TH_#Hans | 中文_泰国_#Hans | Chinese_Thailand_#Hans |
zh_TW | 中文_台湾地区 | Chinese_Taiwan |
zh_TW_#Hans | 中文_台湾_#Hans | Chinese_Taiwan_#Hans |
zh_TW_#Hant | 中文_台湾#Hant | Chinese_Taiwan#Hant |
zh_US_#Hans | 中文_美国_#Hans | Chinese_US_#Hans |
zh_VN_#Hans | 中文_越南_#Hans | Chinese_Vietnam_#Hans |
zh_ZG_#Hans | 中文_ZG_#Hans | Chinese_ZG_#Hans |
zu | 祖鲁语_all | Zulu_all |
Appendix 2: Brand List
Brand | model |
小米 | xiaomi |
三星 | samsung |
华为 | huawei |
中兴 | zte |
中兴努比亚 | nubia |
酷派 | coolpad |
联想 | lenovo |
魅族 | meizu |
HTC | htc |
OPPO | oppo |
VIVO | vivo |
摩托罗拉 | motorola |
索尼 | sony |
LG | lg |
金立 | jinli |
天语 | tianyu |
诺基亚 | nokia |
美图秀秀 | meitu |
谷歌 | |
TCL | tcl |
锤子手机 | 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 range | model |
0-999 | 0-999 |
1000-1999 | 1000-1999 |
2000-3999 | 2000-3999 |
Above 4000 | 4000+ |