一、Introduction
1、Push Server SDK文档
2、用途
• 推送消息发送;
• 消息统计数据获取;
• 订阅标签;
• 消息状态;
• 开发者工具;
二、快速接入
接入Java SDK前,您需要已启用小米推送服务,并且获得应用对应的AppId、 AppKey和AppSecret。
您可以选择接入服务端Java Http2 SDK(参见2.1节)。
1、接入Java Http2 SDK
1.1、获取SDK
Java Http2 SDK下载地址:http://admin.xmpush.xiaomi.com/zh_CN/mipush/downpage/java-http2
请下载最新的SDK版本。
1.2、运行环境
要求JDK版本大于或等于1.8。
1.3、导入SDK
- 解压“MiPush_SDK_Server_Http2.zip”压缩包。
- 将“MiPush_SDK_Server_Http2”目录下的jar包放入项目工程libs目录。
说明:如果运行环境为JDK 1.9以上版本可以不引入conscrypt-openjdk-uber-2.1.0.jar包。如果不想使用okhttp3组件,可以不引入conscrypt-openjdk-uber-2.1.0.jar、okhttp-3.14.2.jar和okio-1.17.2.jar这三个jar包,同时调用Constants.disableOkHttp3()方法,此时将不会启动HTTP2.0协议。
2、SDK类定义说明
参见各个类使用说明:
类名 | 使用说明 |
Message | 消息对象 |
Builder | 构建发送给Android设备的Message对象 |
TargetedMessage | 构建要发送的消息内容和发送目标 |
Sender | MiPush消息发送类 |
Result | 服务器返回结果 |
Stats | 获取消息统计数据 |
Tracer | 追踪消息状态 |
Subscription | 订阅/取消订阅标签 |
Feedback{Deprecated} | 获取失效的RegID或Alias列表。 该接口已下线,请使用消息回执callback接口(callback.type: 16)进行失效数据过滤。 |
DevTools | 设备工具集 |
Constants | 常量定义 |
ErrorCode | 错误类型 |
三、发送消息
发送消息依赖Sender类com.xiaomi.xmpush.server.Sender
实例化SenderSender(String appSecret) - appSecret是在开发者网站上注册时生成的, 可在应用详情下查看返回结果Resultcom.xiaomi.xmpush.server.Result
方法 | 说明 |
String getMessageId() | 消息发送成功, 服务器返回消息ID, 否则返回Null |
ErrorCode getErrorCode() | 发送消息返回的错误码, 若返回ErrorCode.Success表示发送成功, 否则发送失败 |
String getReason() | 若消息发送失败, 服务器返回错误原因的文字描述, 否则返回Null |
Result对于所有发送消息接口使用方式完全一样
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) // 使用默认提示音提示
.build();
Result result = sender.send(message, regId, 3);
Log.v("Server response: ", "MessageId: " + result.getMessageId()
+ " ErrorCode: " + result.getErrorCode().toString()
+ " Reason: " + result.getReason());
}
1、构建消息
- 构建Message消息对象
- 构建TargetedMessage对象:TargetedMessage类中封装了Message对象和该Message所要发送的target;
TargetedMessage类:com.xiaomi.xmpush.server.TargetedMessage
区别:Message消息体只是包含消息参数, 不包括消息推送目标(regid, alias, useraccount, topic)
注意: TargetedMessage集合接口发送消息时, 所有的TargetedMessage对象的targetType必须相同, 不支持在一个调用中同时给regid和alias发送消息
方法 | 说明 |
TargetedMessage() | 构造函数 |
setMessage(Message message) | 设置消息 |
setTarget(int targetType, String target) | 设置发送目标 |
targetType表示目标类型(目前仅支持三种类型)TargetedMessage.TARGET_TYPE_REGID(regid消息类型, target对应regid)TargetedMessage.TARGET_TYPE_ALIAS(alias消息类型, target对应alias)TargetedMessage.TARGET_TYPE_USER_ACCOUNT(useraccount消息类型, target对应useraccount)
1.1、Android平台
com.xiaomi.xmpush.server.Message.Builder
消息类型:
- 通知栏消息 - 在系统通知栏进行展示;
Builder方法列表:
方法 | 说明 |
Builder() | 构造方法 |
payload(String payload) | 设置要发送的消息内容payload, 不允许全是空白字符, 长度小于4KB, 一个中英文字符均计算为1 |
title(String title) | 设置在通知栏展示的通知的标题, 不允许全是空白字符, 长度小于50, 一个中英文字符均计算为1(通知栏消息必填) |
description(String description) | 设置在通知栏展示的通知描述, 不允许全是空白字符, 长度小于128, 一个中英文字符均计算为1(通知栏消息必填) |
notifyType(Integer type) | 设置通知类型, type类型支持以下值: • 1:使用默认提示音提示 • 2:使用默认振动提示 • 4:使用默认呼吸灯提示 • -1(系统默认值):以上三种效果都有 • 0:以上三种效果都无,即静默推送。 并且支持1,2,4的任意OR运算来实现声音、振动和呼吸灯的任意组合。 |
restrictedPackageName(String packageName) | 设置app的包名packageName, packageName必须和开发者网站上申请的结果一致 |
restrictedPackageNames(String[] packageNames) | 设置app的多包名packageNames(多包名发送广播消息), packageNames必须和开发者网站上申请的结果一致, 可以为空, 为空则默认给所有渠道包名推送(不能同时调用restrictedPackageName方法和restrictedPackageNames方法) |
timeToLive(int milliseconds) | 可选项,消息有效期,单位:毫秒(ms)。当用户设备未联网时,消息默认缓存时间为:公信消息最长1天,私信消息最长10天,超过缓存时间消息会丢弃 |
timeToSend(long milliseconds) | 可选项, 定时发送消息, timeToSend是以毫秒为单位的时间戳(仅支持七天内的定时消息) |
notifyId(Integer id) | 可选项, 默认情况下, 通知栏只显示一条推送消息, 如果通知栏要显示多条推送消息, 需要针对不同的消息设置不同的notify_id(相同notify_id的通知栏消息会覆盖之前的),且要求notify_id为取值在0~2147483647的整数。 |
enableFlowControl(boolean needFlowControl) | 可选项, 控制消息是否需要进行平滑推送(qps less 3000/second), 默认不支持 |
extra(String key, String value) | 可选项, 对app提供一些扩展功能(除了这些扩展功能, 开发者还可以定义一些key和value来控制客户端的行为, 注:key和value的字符数不能超过1024, 至多可以设置10个key-value键值对) |
build() | 根据设置的属性, 生成Message对象 |
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)
.notifyType(1) // 使用默认提示音提示
.build();
return message;
}
2、RegID消息
使用场景:
regId是app在客户端向小米推送服务注册时, 小米推送服务端根据设备标识和appId以及当前时间戳生成, 因此能够保证每个设备上每个app对应的regId都是不同的, 可以作为每台设备上app的唯一标识;注: 需要开发者自己的服务器接收客户端返回的regid并存储在自身服务器;
接口说明:
com.xiaomi.xmpush.server.Sender
方法 | 说明 |
send(Message message, String regid, int retries) | 根据regid, 发送消息到指定设备上, retries代表发送失败后重试的次数。 |
send(Message message, List<String> regids, int retries) | 根据regids, 发送消息到指定的一组设备上, regids的个数不得超过1000个。 |
sendHybridMessageByRegId(message, regids, retries) | 给快应用发送regid消息。如果应用类型是快应用,须调用此方法。 |
Demo:
- 单个regid消息:
private void sendMessage() throws Exception {
Constants.useOfficial();
private 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) // 使用默认提示音提示
.build();
sender.send(message, regId, 3); //根据regID,发送消息到指定设备上
}
- 多个regid消息(推荐使用)
private void sendMessage() throws Exception {
Constants.useOfficial();
private 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) // 使用默认提示音提示
.build();
sender.send(message, Lists.newArrayList(regId1, regId2 ...), 3); //发送消息到一组设备上, regids个数不得超过1000个
}
3、Alias消息
使用场景:
别名alias是小米推送这边提供的一个个性化设定, 可以为每个设备上的app设置一个别名, 方便开发者管理, 并能做到精细化推送 alias与regid(设备)一一对应, 主要是为了方便开发者管理而推出, 如果多个设备设置同一个alias, 则只能后设置的设备才会收到消息(如果需要多个设备使用同一名称进行管理, 推荐使用UserAccount消息);注: alias由客户端发送Command请求进行设置,且每个app单台设备可订阅的alias上限为15个。
接口说明:
com.xiaomi.xmpush.server.Sender
方法 | 说明 |
sendToAlias(Message message, String alias, int retries) | 根据alias, 发送消息到指定设备上, alias不允许全是空白字符, 不能包含逗号, 长度小于128, 中英文均以一个计算 |
sendToAlias(Message message, List<String> aliasList, int retries) | 根据aliasList, 发送消息到指定的一组设备上, 元素的个数不得超过1000个 |
Demo:
- 单个alias消息:
private void sendMessageToAlias() throws Exception {
Constants.useOfficial();
private Sender sender = new Sender(APP_SECRET_KEY);
String messagePayload = “This is a message”;
String title = “notification title”;
String description = “notification description”;
String alias = “testAlias”; //alias非空白, 不能包含逗号, 长度小于128
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.notifyType(1) // 使用默认提示音提示
.build();
sender.sendToAlias(message, alias, 3); //根据alias, 发送消息到指定设备上
}
- 多个alias消息(推荐使用)
private void sendMessageToAliases() throws Exception {
Constants.useOfficial();
private Sender sender = new Sender(APP_SECRET_KEY);
String messagePayload = “This is a message”;
String title = “notification title”;
String description = “notification description”;
List<String> aliasList = new ArrayList<String>();
aliasList.add(“testAlias1”); //alias非空白,不能包含逗号, 长度小于128
aliasList.add(“testAlias2”); //alias非空白,不能包含逗号, 长度小于128
aliasList.add(“testAlias3”); //alias非空白,不能包含逗号, 长度小于128
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.notifyType(1) // 使用默认提示音提示
.build();
sender.sendToAlias(message, aliasList, 3); //根据aliasList, 发送消息到指定设备上
}
4、UserAccount消息
使用场景:
userAccount主要适用于用户多点登陆的情况;一个账号account可以绑定多个设备(上限20个), 可以认为是小型的topic。注: useraccount由客户端调用setUserAccount(final Context context, final String userAccount, String category)接口进行设置。
接口说明:
com.xiaomi.xmpush.server.Sender
方法 | 说明 |
sendToUserAccount(Message message, String userAccount, int retries) | 根据account, 发送消息到指定account上, account不允许全是空白字符, 不能包含逗号, 长度小于128, 中英文均以一个计算 |
sendToUserAccount(Message message, List<String> accountList, int retries) | 根据accountList, 发送消息到指定的一组设备上, 元素的个数不得超过1000个 |
Demo:
- 单个useraccount消息:
private void sendMessageToUserAccount() throws Exception {
Constants.useOfficial();
private Sender sender = new Sender(APP_SECRET_KEY);
String messagePayload = “This is a message”;
String title = “notification title”;
String description = “notification description”;
String useraccount = “testUserAccount”; //useraccount非空白, 不能包含逗号, 长度小于128
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.notifyType(1) // 使用默认提示音提示
.build();
sender.sendToUserAccount(message, useraccount, 3); //根据useraccount, 发送消息到指定设备上
}
- 多个useraccount消息(推荐使用):
private void sendMessageToUserAccounts() throws Exception {
Constants.useOfficial();
private Sender sender = new Sender(APP_SECRET_KEY);
String messagePayload = “This is a message”;
String title = “notification title”;
String description = “notification description”;
List<String> accoutList = new ArrayList<String>();
accoutList.add(“testUserAccount1”); //useraccount非空白,不能包含逗号, 长度小于128
accoutList.add(“testUserAccount2”); //useraccount非空白,不能包含逗号, 长度小于128
accoutList.add(“testUserAccount3”); //useraccount非空白,不能包含逗号, 长度小于128
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.notifyType(1) // 使用默认提示音提示
.build();
sender.sendToUserAccount(message, accoutList, 3); //根据accountList, 发送消息到指定设备上
}
5、Topic消息
使用场景:
Topic消息, 开发者如果想要给不同的用户群体(量级一般比较大)发送不同的推送消息, 比如不同的客户端版本、 不同地域、男女等的用户群体,那么使用Topic消息就非常适合;通过给不同的用户群体打不同的标签(topic)来实现, 我们内部还为全量用户打了统一标签, 开发者可以直接使用全量标签发送, 方便快捷;开发者还可以使用topic做交并差集运算,以达到更精细推送的目的;注: 参考第七部分订阅标签。
特别提示:请谨慎使用API发送全量Topic消息,如果因测试等原因误发全量消息,对用户造成干扰,小米推送有权禁止topic消息功能使用;
接口说明:
com.xiaomi.xmpush.server.Sender
方法 | 说明 |
broadcast(Message message, String topic, int retries) | 根据topic, 发送消息到指定一组设备上, topic不允许全是空白字符, 长度小于128, 中英文均以一个计算 |
broadcastAll(Message message, int retries) | 向所有设备发送消息 |
multiTopicBroadcast(Message message, List<String> topics, topic_op, int retries) | 向多个topic广播消息, 支持topic间的交集、并集或差集(如果只有一个topic请用单topic版本) |
broadcastHybridAll(message, retries) | 给快应用发送全量消息。如果应用类型是快应用,须调用此方法。 |
- 在multiTopicBroadcast中topic_op - BROADCAST_TOPIC_OP是一个枚举类型, 指定了发送广播消息时多个topic之间的运算关系;
public enum BROADCAST_TOPIC_OP {
UNION, // 并集
INTERSECTION, // 交集
EXCEPT, // 差集
}
- 例如: topics的列表元素是[A, B, C, D], 则并集结果是A ∪ B ∪ C ∪ D, 交集的结果是A ∩ B ∩ C ∩ D,差集的结果是A - B - C - D
注: 发送topic消息时topic的数量不能超过5;
Demo:
- 单个topic:
private void sendBroadcast() throws Exception {
Constants.useOfficial();
private Sender sender = new Sender(APP_SECRET_KEY);
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) // 使用默认提示音提示
.build();
sender.broadcast(message, topic, 3); //根据topic, 发送消息到指定一组设备上
}
- 多个topic:
private void sendBroadcast() throws Exception {
Constants.useOfficial();
private Sender sender = new Sender(APP_SECRET_KEY);
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) // 使用默认提示音提示
.build();
//根据topicList做并集运算, 发送消息到指定一组设备上
sender.multiTopicBroadcast(message, topicList, BROADCAST_TOPIC_OP.UNION, 3);
}
6、定时消息
使用场景:
一些日常的定点推送任务或者一些固定时间点的活动, 实时推送难免会费时费力还可能不及时, 这时候就可以提前准备好推送文案, 提交定时消息到我们后台, 到了推送时间指定时间小米推送会准时将消息下发;
接口说明:
com.xiaomi.xmpush.server.Sender
1.构建Message对象时设置timeToSend(long milliseconds)
- 定时发送消息, timeToSend是以毫秒为单位的时间戳(仅支持七天内的定时消息)
2.构建TargetedMessage对象调用Sender.send(List messages, int retries, long timeToSend)
- 定时发送一组消息, timeToSend是用自1970年1月1日以来00:00:00.0 UTC时间表示(以毫秒为单位的时间)注: 仅支持七天内的定时消息;
方法 | 说明 |
checkScheduleJobExist(String msgId) | 检测定时消息的任务是否存在 |
deleteScheduleJob(String msgId) | 根据消息ID删除指定的定时消息 |
deleteScheduleJobByJobKey(String jobKey) | 根据jobKey删除指定的定时消息 |
Demo:
设置Message对象timeToSend属性:
private void sendMessageToAlias() throws Exception {
Constants.useOfficial();
private Sender sender = new Sender(APP_SECRET_KEY);
String messagePayload = “This is a message”;
String title = “notification title”;
String description = “notification description”;
String alias = “testAlias”; //alias非空白, 不能包含逗号, 长度小于128
Message message = new Message.Builder()
.title(title)
.description(description).payload(messagePayload)
.restrictedPackageName(MY_PACKAGE_NAME)
.timeToSend(System.currentTimeMillis() + 60 * 60 * 1000) // 1个小时后发送
.notifyType(1) // 使用默认提示音提示
.build();
sender.sendToAlias(message, alias, 3); //根据alias, 发送消息到指定设备上
}
构建TargetedMessage:
private void sendMessageToAlias() throws Exception {
Constants.useOfficial();
private Sender sender = new Sender(APP_SECRET_KEY);
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) // 使用默认提示音提示
.build();
String alias = “testAlias”; //alias非空白, 不能包含逗号, 长度小于128
String alias1 = “testAlias1”; //alias非空白, 不能包含逗号, 长度小于128
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) // 使用默认提示音提示
.build();
targetedMessage1.setMessage(message1);
List<TargetedMessage> messages = new ArrayList<TargetdMessage>();
messages.add(targetMessage);
messages.add(targetMessage1);
//根据TargetedMessage列表, 发送消息到指定设备上, 设置一个小时后发送
sender.send(messages, 3, System.currentTimeMillis() + 60 * 60 * 1000);
}
7、提高发送性能
优先使用batch接口, 如优先使用, 在发消息时, 想要发送一条消息给10000个用户, 开发者A只用10次请求每次发送1000个目标量(如alias, regId等), 而开发者B用了10000次请求每次只发送1个目标量. 很明显, 开发者A的效率远高于开发者B, 其次使用TargetMessage消息对象;发送之前如果能够过滤掉一部分无效设备数(通过消息回执callback接口,设置callback.type=16,获取无效设备), 提高发送性能。
8 、提高送达率
使用消息回执callback接口,设置callback.type=16,过滤用户集中的无效设备;设置合适的ttl(timeToLive消息过期时间)也能一定程度上提高送达率;建议使用通知栏消息;
四、高级功能
构造Message对象时, 调用extra(String key, String value)方法设置key和value, 自定义app的扩展功能;
1、自定义铃声
Android 8.0以下版本
Android 8.0以下版本在发送消息时按此方式设置自定义铃声:
调用Message.Builder类的extra(String key, String value)方法设置铃声uri。
key - 'sound_uri', value - 铃声的uri;
注:铃声只能使用当前app内的资源, uri格式满足 android.resource://your packagename/XXX/XXX
铃声文件放在Android app的raw目录下
只适用于通知栏消息
存储的声音文件需要有扩展名, 但是不要把扩展名写在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)
.notifyType(1)
.extra(Constants.EXTRA_PARAM_SOUND_URI, "android.resource://" + PACKAGENAME + "/raw/shaking")
.build();
return message;
}
Android 8.0及以上版本
Android 8.0及以上版本的通知效果以channel中的效果为准,发送消息时设置自定义铃声将不会生效,需要在新建channel时设置自定义铃声。
- 如果您未设置channel,当您发送第一条消息时小米推送会为您创建一个默认channel,该channel的效果会以您发送的这条消息为准。如果您在这条消息中按照上面的方式设置了自定义铃声,该默认channel的铃声效果就会为此自定义铃声效果,以后再更改不会生效。
- 如果您希望更改自定义铃声,只能新建一个channel,在新建时设置自定义铃声,再使用该channel推送消息。该channel推送的消息都会带有此自定义铃声。
channel的使用方法请参见“4.4 通知类别(Channel)”。
2、控制APP前台通知弹出
当app在前台时, 默认情况下服务端向客户端发送通知栏消息, app会弹出通知;如果开发者不想让客户端弹出通知, 调用Message.Builder类的extra(String key, String value)方法设置是否弹出通知;key - 'notify_foreground', value - 开启/关闭(1/0);注:只适用于通知栏消息
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)
.notifyType(1)
.extra(Constants.EXTRA_PARAM_NOTIFY_FOREGROUND, "0")
.build();
return message;
}
3、预定义通知栏通知的点击行为
3.1、打开当前app对应的Launcher Activity:
调用Message.Builder类的extra(String key, String value)方法将key设置为Constants.EXTRA_PARAM_NOTIFY_EFFECT,value设置为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)
.notifyType(1)
.extra(Constants.EXTRA_PARAM_NOTIFY_EFFECT, Constants.NOTIFY_LAUNCHER_ACTIVITY)
.build();
return message;
}
3.2、打开当前app内任意一个Activity
调用Message.Builder类的extra(String key, String value)方法:
key - Constants.EXTRA_PARAM_NOTIFY_EFFECT, value - Constants.NOTIFY_ACTIVITYkey - Constants.EXTRA_PARAM_INTENT_URI, value - 启动Activity的intent uri
获取Intent uri的具体步骤:
在安卓客户端的工程的AndroidManifest.xml里定义一个Activity, 例如下面是一个展示新闻的Activity:
<activity android:name=".NewsActivity"/>
定义一个Intent来启动该Activity, 例如要打开上面定义的NewsActivity可定义Intent为:
intent:#Intent;component=com.yourpackage/.YourActivity;end
例如转换intent为uri:
String uriString = intent.toUri(Intent.URI_INTENT_SCHEME);//该uriString就是Constants.EXTRA_PARAM_INTENT_URI对应的值
返回值:
intent:#Intent;component=com.xiaomi.mipushdemo/.NewsActivity;end
注:
- 如果你希望在Intent uri中携带数据,注意一个限制:Intent.toUri(Intent.URI_INTENT_SCHEME), 返回的结果不会携带除基本类型(boolean, byte, short, int, long, float, double, String)以外的数据类型, 例如数组和HashMap
- 获取了Intent uri之后, 在服务端的工程里(需要引用推送服务器SDK), 把uriString 设置进的Message.Builder.extra(),对应的key是Constants.EXTRA_PARAM_INTENT_URI
- 在生成intent uri时,如果出现点击无法跳转或者Activity的生命周期没有执行时,建议追加flag参数: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)
.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.3、打开网页
调用Message.Builder类的extra(String key, String value)方法:
key -Constants.EXTRA_PARAM_NOTIFY_EFFECT, value - Constants.NOTIFY_WEBkey - Constants.EXTRA_PARAM_WEB_URI, value - 网页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)
.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、通知类别(Channel)
通知类别(Channel)介绍
通知类别(Channel)是 Android O 引入的新功能,旨在解决以下问题:
- 应用的通知越来越多,给用户造成明显打扰。
- 但用户只能全局屏蔽这个应用的全部通知,不能屏蔽部分,然后留下对自己有用的。
为了解决这个问题,Android 支持开发者给自己的通知分成若干类,然后允许用户单独屏蔽这个类别的通知。关于通知类别(Channel)的详细介绍请参见《MIUI 10 通知类别 (Channel) 适配》。
说明:1. 当前版本暂不支持设置Channel Group。2. 对于MIUI系统,可以不设置Channel,通知也能发出。对于非MIUI系统,是否必须设置Channel取决于你的应用的target API:target API ≥ 26(Android 8.0):必须设置Channel,而且必须给每条通知指定一个 Channel,否则无法发出通知。target API ≤ 25(Android 7.1):可以不设置Channel。在8.0及以上的设备,通知也能正常发出。为确保通知在不同类型的设备上都能正常显示,建议您设置Channel。
使用方法
注意:用户最多可创建8组Channel。各Channel的Channel_id不可重复,Channel_name也不允许同名。Channel一旦创建并发送了带有Channel的消息,设备上即会生成这个Channel,不能删除也不能修改,所以请谨慎创建Channel。
- 添加新Channel:
参考《小米推送消息分类新规》2.channel申请与接入方法。
- 发送带有Channel的消息:
构建message时,通过自定义键值对,向extra里传递参数。
key | value |
channel_id | 发送的消息归属于哪类Channel,这里须设置channel id,必须配。 |
代码示例:
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")
.notifyType(1) // 使用默认提示音提示
.extra("channel_id", "my_channel_1") // 设置channel id, 必须配
.build();
return message;
}
5、过滤消息
开发者通过调用Message.Builder类的extra(String key, String value)来指定消息的过滤规则(过滤规则能够支持所有的消息)
key - 'locale', value - 可以接收消息设备的语言范围, 用逗号分隔;key - 'locale_not_in', value - 无法收到消息设备的语言范围, 用逗号分隔;
当前设备locale获取方法为Locale.getDefault().toString()
比如, 中国大陆用"zh_CN"表示(详见附录1:语言代码对照表)
key - 'app_version', value - 可以接收消息app版本号, 用逗号分隔;key - 'app_version_not_in', value - 无法收到消息app版本号, 用逗号分隔;
安卓app版本号来源于manifest文件中的"android:versionName"的值 (目前支持MiPush_SDK_Client_2_2_12_sdk.jar及以后的版本)
key - 'connpt', 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)
.notifyType(1)
.extra("locale","zh_CN")
.build();
return message;
}
6、消息回执
开发者希望消息发送后,推送系统能发送回执给开发者,告知开发者这些消息的送达、点击或发送失败状态。可通过调用Message.Builder类的extra(String key, String value)来指定消息回执规则。
规则列表:
Key | Value含义 |
callback | String(必填字段), 接收回执的Http接口, 最大长度128字节 |
callback.param | String(可选字段), 自定义回执参数, 最大长度256字节 |
callback.type | String(可选字段), 支持以下状态的回执类型: • 1:消息送达。 • 2:消息点击。 • 16:目标设备无效(设备超过30天未联网;alias/user account/regID不正确;App未注册或已卸载;发送目标的区域有误等原因)。 • 32:客户端调用了disablePush接口禁用Push。 • 64:目标设备不符合过滤条件(包括网络条件不符合、地理位置不符合、App版本不符合、机型不符合、地区语言不符合等)。 • 128:当日推送总量超限或单设备接收超限,限制规则请参见“消息限制说明”。 • 1024:消息有效期TTL过期。 如果不设置,默认类型是送达和点击。 说明: • 对于当前设备不在线、非小米手机App未启动等原因导致的本次消息无法下发,不返回回执。 • 如果需要返回多种状态的回执,将type数值相加即可。例如:既需要收到送达回执,也需要收到目标设备无效的回执,请将callback.type设置为17(即1+16);如果需要收到消息送达、消息点击和目标设备无效三种状态的回执,请将callback.type设置为19(1+2+16)。 最佳实践:建议针对上述状态中的16类型做过滤处理,减少对这些用户的无效推送。 |
小米推送服务器每隔1s将已送达、已点击或目标设备无效的消息ID和对应设备的regid或alias通过调用第三方http接口传给开发者(每次调用后, 小米推送服务器会清空这些数据, 下次传给开发者将是新一拨数据)。
注意: 消息的送达回执只支持向regId或alias发送的消息。目标设备无效的回执支持regId、alias和useraccount消息。
服务器callback回调采用post方式,在进行api调用时http请求头会携带以下信息:
Accept:text/html,application/xhtml xml,application/xml
Accept-Charset:UTF-8
Accept-Language:zh-cn
Content-Type:application/x-www-form-urlencoded
请参考,并建议在接入前使用postman或其他工具测试api可用性时也携带以上请求头信息。
request body为data={json格式的字符串},JSON数据格式如下:
{
//type为1表示该消息已送达,targets为送达的设备alias列表
"msgId1":{"param":"param","type": 1, "targets":"alias1,alias2,alias3", "jobkey": "123" ,"barStatus":"Enable","timestamp":1324167800000},
//type为2表示该消息被点击,targets为点击的设备alias列表
"msgId2":{"param":"param","type": 2, "targets":"alias1,alias2,alias3", "jobkey": "456", "barStatus": "Enable", "timestamp": 1524187800000},
//type为16表示目标设备无效,targets为无效的alias列表
"msgId3":{"param":"param","type":16,"targets":"alias1,alias2,alias3","barStatus":"Unknown","timestamp":xxx},
//type为16表示目标设备无效,targets为无效的regId列表,errorCode为1表示无效regId
"msgId4":{"param":"param","type":16,"targets":"regId1,regId2,regId3","barStatus":"Unknown","errorCode":1,"timestamp":xxx,"replaceTarget":{"regId1":"otherRegId"}},
//type为64表示目标设备不符合过滤条件
"msgId5":{"param":"param","type":64,"targets":"regId1,regId2,regId3", "barStatus":"Unknown","timestamp":1572228055643}
//type为128表示当日推送总量超限,或单设备接收超限
"msgId6": {"extra":{"ack":"当日已送达数","quota":"当日可以下发总数"},"type":128,"targets":"alias","timestamp":1585203103625}
"msgId7": {"extra":{"device_acked":"当日单设备已接收数","device_quota":"当日单设备可以下发总数"},"type":128,"targets":"alias","timestamp":1585203104390}
//type为1024表示消息有效期TTL过期
"msgId8": {"param":"param","type":1024,"targets":"regId1,regId2,regId3", "timestamp":1572228055643}
}
格式说明:
外层key代表相应的消息msgId, value是一个JSONObject, 包含了下面的参数值:
param:开发者上传的自定义参数值。
type:消息状态类型(1-送达;2-点击;16-无法找到目标设备;32-客户端调用了disablePush接口禁用Push;64-目标设备不符合过滤条件;128-当日推送总量超限或单设备接收超限;1024-消息有效期TTL过期)。
device_acked:当日单设备已接收数;device_quota:当日单设备可以下发总数;targets:一批alias、regId或useraccount列表,逗号分隔;jobkey:发送消息时设置的jobkey值;barStatus:消息送达时通知栏的状态;Enable:用户允许此app展示通知栏消息; Disable:通知栏消息已关闭; Unknown:通知栏状态未知;timestamp:消息送到设备的时间;replaceTarget:该发送目标无法正常送达,但建议可替换成另外一个新的目标标识以满足该设备的正常推送,其值为键值对;key:该设备原始发送目标标识;value:建议替换成的新的目标标识;errorCode:type为16时返回的无效目标的子类;errorCode:1表示无效regid;errorCode:2表示无效alias;errorCode:3表示无效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)
.notifyType(1)
.extra("callback", "http://www.xiaomi.com/msgcallback")
.build();
return message;
}
7、 消息聚合
开发者在发送消息时可以设置消息的组ID(JobKey), 带有相同的组ID的消息会被聚合为一个消息组;
系统支持按照消息组展示消息详情以及计划推送/送达数量/送达曲线等统计信息。另外, 相同JobKey的消息在客户端会进行去重, 只展示其中的第一条。这样如果发送时同JobKey中不慎有重复的设备也不用担心用户会收到重复的通知。
设置消息的组ID的方法是调用Message.Builder类的extra(String key, String value)方法将key设置为“jobkey”;value设置为消息组的ID, 合法的消息组ID由数字([0-9]), 大小写字母([a-zA-Z]), 下划线(_)和中划线(-)组成, 长度不大于20个字符,且不能以下划线(_)开头。
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)
.notifyType(1)
.extra("jobkey", "0115a001")
.build();
return message;
}
8、平滑推送
考虑有开发者服务器资源的问题, 如果推送消息速度过快会导致开发者服务器产生很大的压力, 所以我们提供平滑推送特性,开发者可以设定消息发送速度。
开发者通过调用Message.Builder类的extra(String key, String value)来设置消息发送速度:
key - "flow_control"value - 发送速度(qps)注: 若设置速度低于1000, 则默认3000qps
说明:如果设置了平滑推送,同一个应用同时发送两条消息时会排队发送,需要等第一条消息发送完毕才会发送第二条。
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)
.notifyType(1)
.extra("flow_control", "20000") // 设置平滑推送, 推送速度20000每秒(qps=20000)
.build();
return message;
}
9、only send once消息
一些开发者希望消息只在设备网络在线时下发,不缓存离线消息进行多次下发,以满足及时性需求。为此我们提供了only send once消息功能,开启该功能后消息只会当设备在线时下发一次。
开发者通过调用Message.Builder类的extra(String key, String value)来设置only send once消息:
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)
.notifyType(1)
.extra("only_send_once", "1") // 设置消息只发送1次
.build();
return message;
}
五、获取统计数据{Deprecated}
获取统计数据的com.xiaomi.xmpush.server.Stats类已下线,请使用com.xiaomi.xmpush.server.Tracer类获取消息统计数据。
六、追踪消息状态
获取统计数据依赖Tracer类:
com.xiaomi.xmpush.server.Tracer
实例化Tracer:
Tracer(String appSecret) - appSecret是在开发者网站上注册时生成的, 可在应用详情下查看;
方法介绍:
- 该方法用于获取某条消息或某个时间段的消息的统计数据,如发送量、送达量、点击量等;
1、获取指定消息ID的统计信息
String getMessageStatus(String msgId, int retries)
- msgId : 发送消息时返回的msgId(参考Sender相关接口)
- retries : 重试次数
返回值 - json字符串
- id表示消息ID。
- resolved表示消息的计划推送数(包含送达数, 以及其他某些原因导致无法下发的目标数)。
- raw_counter表示https原始请求目标数。
- invalid_target表示无效目标数(alias无效, user_account无效等)。
- app_not_register表示app未注册push服务数量。
- device_condition_unmatch表示设备所处的环境不符合消息设置的条件(例如: 网络环境不匹配, 地域不匹配, app版本不匹配, 机型不匹配等)。
- msg_send表示消息的实际下发数。
- delivered表示消息的送达数(实际下发到客户端的消息数量)。
- delivery_rate表示送达率(送达数/有效目标数) 。
- bar_closed表示屏蔽通知栏数。
- msg_display表示消息的展示数(送达数-屏蔽通知栏数)。
- click表示消息点击数。
- click_rate表示消息点击率(点击数/送达数)。
- create_time表示消息发送时间。
- time_to_live表示消息有效期。
- msg_type表示消息发送方式(Common、BatchRegId、Alias、BatchAlias、Topic)。
成功:
{
"result" : "ok",
"description" : "成功",
"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
}
失败:
{
"result" : "error",
"reason" : "XXXXXXXXX",
"description" : "XXXX",
"code" : XXXX
}
2、获取某个时间段内所有消息的统计数据
String getMessageStatus(long beginTime, long endTime, int retries)
- beginTime : 开始时间戳(单位: ms)
- endTime : 结束时间戳(单位: ms)
- retries : 重试次数
返回值 - json字符串;
注:
- 如果该时间区间内的消息数大于100条, 则返回最近100条
- 开始时间和结束时间之间的跨度不能大于7天
成功:
{
"result" : "ok",
"description" : "成功",
"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
}
失败:
{
"result" : "error",
"reason" : "XXXXXXXXX",
"description" : "XXXX",
"code" : XXXX
}
3、获取指定jobkey消息统计数据
String getMessageGroupStatus(String jobKey, int retries)
- jobKey : 发送消息时设置(参考4.高级功能), 相同jobkey的消息在客户端只显示一条, 并可以通过jobkey来批量获取消息的统计信息
- retries : 重试次数
返回值 - json字符串
成功:
{
"result" : "ok",
"description" : "成功",
"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
}
失败:
{
"result" : "error",
"reason" : "XXXXXXXXX",
"description" : "XXXX",
"code" : XXXX
}
Demo:
public void getTrace() throws Exception {
Tracer tracer = new Tracer(APP_SECRET_KEY); // 使用AppSecretKey创建一个Tracer对象
// 获取单条消息的送达状态, 参数:msgId, retry次数
String messageStatus = tracer.getMessageStatus("s1005246409317636237jB", 0);
System.out.println(messageStatus);
// 获取一个时间区间内的消息的送达状态, 参数:开始时间, 结束时间, retry次数
String messageStatus2 = tracer.getMessageStatus(System.currentTimeMillis() - 1000, System.currentTimeMillis(), 3);
System.out.println(messageStatus2);
}
七、订阅标签
使用场景:
标签可以认为是具有某些相同属性的用户集合, 我们可以针对一个标签发送消息。这时,所有订阅了该标签的用户(设备)都会收到该消息(广播消息)。该接口用于将某个设备设置标签(加入集合)或取消标签(从集合中删除)。我们可以通过给不同的用户全体设置不同的标签,已达到精细化推送的目的。
注:每个App单台设备可订阅标签的个数为30个,如果超过了对应上限数,则新订阅的Topic会覆盖最早设置的Topic。
接口说明:
com.xiaomi.xmpush.server.Subscription
实例化Subscription
Subscription(String appSecret) - appSecret是在开发者网站上注册时生成的, 可在应用详情下查看;
API介绍:
subscribeTopic(List regIds, String topic, String category, int retries) | • 给一组regid列表订阅标签(regid为应用注册时,服务器返回给客户端的唯一标识): retries表示重试的次数, catergory可以使用null(限制:最多1000个regId); |
subscribeTopic(List regIds, String topic, String packageName, String category, int retries) | • 给一组regid列表订阅标签(regid为应用注册时,服务器返回给客户端的唯一标识): retries表示重试的次数, catergory可以使用null(限制:最多1000个regId); • 如果APP有多个包名, 则在订阅标签时, 需要提供一个确切的包名(非多包名情况则不需要), 这时需要使用多包名接口; |
subscribeTopic(String regId, String topic, String category, int retries) | • 给某个regId订阅标签; |
subscribeTopic(String regId, String topic, String packageName, String category, int retries) | • 给某个regid订阅标签; • 如果APP有多个包名, 则在订阅标签时, 需要提供一个确切的包名(非多包名情况则不需要), 这时需要使用多包名接口; |
unsubscribeTopic(List regIds, String topic, String category, int retries) | • 取消一组regid列表的标签, 限制: 最多1000个regId; |
unsubscribeTopic(List regIds, String topic, String packageName, String category, int retries) | • 取消一组regid列表的标签, 限制: 最多1000个regId; • 如果APP有多个包名, 则在订阅标签时, 需要提供一个确切的包名(非多包名情况则不需要), 这时需要使用多包名接口; |
unsubscribeTopic(String regId, String topic, String category, int retries) | • 取消某个regId标签; |
unsubscribeTopic(String regId, String topic, String packageName, String category, int retries) | • 取消某个regId标签; • 如果APP有多个包名, 则在订阅标签时, 需要提供一个确切的包名(非多包名情况则不需要), 这时需要使用多包名接口; |
subscribeTopicByAlias(String topic, List aliases, String category, int retries) | • 给一组alias列表订阅标签(限制: 最多1000个alias) |
subscribeTopicByAlias(String topic, List aliases, String packageName, String category, int retries) | • 给一组alias列表订阅标签(限制: 最多1000个alias) • 如果APP有多个包名, 则在订阅标签时, 需要提供一个确切的包名(非多包名情况则不需要), 这时需要使用多包名接口; |
unsubscribeTopicByAlias(String topic, List aliases, String category, int retries) | • 取消一组alias列表的标签(限制: 最多1000个alias); |
unsubscribeTopicByAlias(String topic, List aliases, String packageName, String category, int retries) | • 取消一组alias列表的标签(限制: 最多1000个alias) • 如果APP有多个包名, 则在订阅标签时, 需要提供一个确切的包名(非多包名情况则不需要), 这时需要使用多包名接口。 |
八、拉取失效数据{Deprecated}
建议您使用消息回执callback接口(callback.type: 16)进行失效数据过滤。
Feedback接口用于拉取已经失效的regid或alias等数据,该接口已下线。
九、开发者工具
该接口主要用于调查问题时使用, 可以获取某个设备相关的一些信息。
开发者工具依赖DevTools类
com.xiaomi.xmpush.server.DevTools
实例化DevTools
DevTools(String appSecret) - appSecret是在开发者网站上注册时生成的, 可在应用详情下查看
方法介绍:
1、获取某个设备设置的所有alias
String getAliasesOf(String packageName, String regId, int retries)packageName : 应用包名regId : 设备regIdretries : 重试次数返回值如下:
成功:
{
"result" : "ok",
"description" : "成功",
"data" : {
"list" : ["XXXXXX", "XXXXXX", "XXXXXX"]
},
"code" : 0
}
失败:
{
"result" : "error",
"reason" : "XXXXXXXXX",
"description" : "XXXX",
"code" : XXXX
}
2、获取某个设备订阅的所有topic
String getTopicsOf(String packageName, String regId, int retries)packageName : 应用包名regId : 设备regIdretries : 重试次数返回值如下:
成功:
{
"result" : "ok",
"description" : "成功",
"data" : {
"list" : ["XXXXXX", "XXXXXX", "XXXXXX"]
},
"code" : 0
}
失败:
{
"result" : "error",
"reason" : "XXXXXXXXX",
"description" : "XXXX",
"code" : XXXX
}
十、FAQ
名词解释:
traceID是什么?
在调用我们sdk发送消息返回的结果中, 总会有一个traceId字段, 它代表这个操作请求在我们服务端的唯一标识, 所以通过这个traceId就可以定位请求的访问调查相关问题;
messageID是什么?
messageId用来标识一条消息, 通过messageId我们可以调查消息的活动周期;
异常处理
主要是三类情况:
网络问题证书问题代码漏洞;
网络问题
确认网络到api.xmpush.xiaomi.com是否畅通;
证书问题
服务端接口使用https方式, 请确认本地是否导入证书;
代码漏洞
参考Server SDK文档, 确认是否由于代码缺失参数或者调用方法错误;
十一、附录:
附录1:国家地区语言代码(基于 ISO-3166 标准)
语言代码 | 语言_区域描述(中文) | 语言_区域描述(英文) |
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_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 |
附录2:品牌表
品牌 | 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 |