Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱
MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

目录

小米推送介绍

Demo地址

推送文档

控制台

SDK下载

【17329910039】【bqt中信账号】

小米相比极光等推送SDK的优势:

  • MIUI上系统级通道:在MIUI上系统级长连接,最大程度提高消息送达率
  • iOS/Android全平台支持:支持两大系统的推送服务,iOS开发者还可以将存量用户无缝迁移到小米推送中
  • 稳定 安全 高效:每秒百万级推送速度,亿级同时在线,99.8%的消息300毫秒内到达
  • 使用简单灵活:客户端0.5天集成,也可通过服务端API与业务逻辑相结合
  • 细致全面的统计工具:提供细致全面的统计工具,帮助开发者精准把握推送的使用情况
  • 自助调查工具:开发者可以自助查询设备与消息的送达/在线情况

FAQ

FAQ1

FAQ2

小米推送服务有哪些限制?

目前针对首批合作开发者,小米推送服务没有设置任何推送频率的使用限制,之后出于防止恶意应用攻击等考虑,可能会增加对推送消息的频率、对单一用户可以接收的数量等做一些限制,但不会影响开发者的正常使用。而且所提供的推送服务完全免费。 对于单条消息,可携带的数据量最大不能超过4KB。

Android版推送中,多个app都使用推送时,他们会共享连接吗?

在最新MIUI上,会直接使用系统长连接通道,所有app会和系统共享一个长连接;在其他rom上,目前没有共享连接。多通道的设计从通道安全性和流量计算上会更加合理,并且小米推送的多通道实现可以保证多条长连接对系统电量的影响和一条长连接基本相同。

什么是透传?

透传类推送是指开发者可选择不通过任何预定义的方式展现,由应用直接接收推送消息。利用透传消息,开发者可自定义更多使用推送的方式和展现形式,从而能更为灵活地使用消息推送通道。 在一些拥有应用启动管理功能的Android系统上(如MIUI),透传的实现需要应用在后台处于启动状态。

透传和通知栏,在送达率上有什么分别?

  • 首先解释一下透传和通知栏方式的原理,透传是指当小米推送服务客户端SDK接收到消息之后,直接把消息通过回调方法发送给应用,不做任何处理;而通知栏方式,则在设备接收到消息之后,首先由小米推送服务SDK弹出标准安卓通知栏通知,在用户点击通知栏之后,激活应用。
  • 在非MIUI系统中,由于维护小米推送服务长连接的service是寄生在App的运行空间当中的,因此透传和通知栏方式在送达率上并没有任何区别,都需要应用驻留在后台。即,如果一台设备通知栏消息能够接收到并弹出,那么其透传消息也同样能接收到。
  • 在MIUI系统中,由于长连接是由MIUI系统服务建立并维护的,因此在接收消息的时候并不需要应用驻留后台。如果采用通知栏方式接收消息,由于通知栏也是MIUI系统服务弹出的,就可以做到不需要用户后台驻留或者可以自启动消息就能送达。而如果采用透传消息,由于需要直接执行应用的代码,因此即使消息已经到了系统服务,如果应用没有驻留后台或者能自启动,消息依然不能送达,需等下次用户手动点击激活应用后,才能接收到消息。
  • 综上,在MIUI系统中,通知栏消息的送达率会远高于透传方式;在非MIUI系统中,通知栏和透传方式的送达率是一样的。

使用推送服务demo没有成功是什么原因?

一般注册推送服务没成功,常见的原因如下:

  • 1.没有开启推送服务。使用推送服务前需要登录开发者账号、创建应用、开通推送服务3个步骤,缺一不可。
  • 2.没有正确配置AndroidManifest.xml文件。需要特别注意包名、权限部分,包名需要跟开发者站点上开通推送服务的一致,权限的前缀需要改成包名。
  • 3.系统时间错误。由于小米推送服务需要使用https请求向服务器注册一个匿名账号,在次过程中如果系统时间错误,会引起https过期,导致注册不成功。
  • 4.联网被阻止。小米推送服务客户端需要使用5222和443两个端口,如果在公司内网,需要联系IT部门把这两个端口开放。同时需要检查应用的联网是否会被一些手机安全助手阻止。需要特别注意的是,在MIUI系统上,长连接是由“小米服务框架”这个系统应用维护的,因此需要确保这个应用的联网并没有被阻止。

如果我使用通知栏类型消息,能否在通知栏消息到达之前,先执行一段app的代码?或者在通知栏到达时,通知app?

在MIUI系统上,通知栏类型的消息,是不需要应用启动就能弹出的(这一特性决定了通知栏消息的弹出可以不受应用自启动管理的影响),因此在整个弹出通知栏消息的过程中,app是完全不可感知的,当用户点击通知栏消息之后,才会执行到app的代码。

为什么onNotificationMessageArrived方法没被调用到?

  • 首先,确定你的接入是否正确,这个方法需要在manifest中添加 <action android:name=”com.xiaomi.mipush.MESSAGE_ARRIVED” /> 这个action。 在接入正确的前提下,这个方法也不是保证一定能被调用的。
  • 在MIUI系统上,这个方法的调用需要同时满足如下两个条件:
    • 1.新版的MIUI。这个特性是在2015年才加进小米推送服务的,因此需要MIUI升级到较新的版本才能调用这个方法。
    • 2.需要应用驻留后台。小米推送服务的通知栏消息,是可以在应用不启动的前提下,就弹出通知栏消息的,在这种情况下, 由于MIUI的自启动管理,限制了应用不能在被杀后被后台唤醒,所以推送消息不能直接唤醒应用执行这个方法。

为什么我在onNotificationMessageClicked方法中的startActivity不能调起目标界面?

由于onNotificationMessageClicked中传入的context是application context,本身没有activity栈,因此需要在创建activity时候加入NEW_TASK的flag:

Intent i = new Intent(context, MyActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);

当我的应用被杀掉之后,还能否接收到小米推送服务的消息?

有如下几种情况:如果是在MIUI系统中,使用通知栏类型的消息,是不需要应用出于启动状态就能接收并弹出通知栏的。使用透传消息,则需要应用驻留后台才能接收,由于MIUI的自启动管理限制,所以如果应用被杀,是收不到透传消息的。而如果是在非MIUI系统中,是需要应用驻留后台才能接收消息的,因此如果应用被杀死并且不能后台自启动的话,是没有办法接收消息的。为了让app尽可能的驻留后台,小米推送服务SDK监听了网络变化等系统事件,并且有应用之间的互相唤醒,但这些措施并不能保证应用可以一直在后台驻留。

简洁版自定义消息推送Demo

在适当的时候初始化

private void initMiPush() {
String APP_ID = "1000270";
String APP_KEY = "670100056270"; // 注册push服务,注册成功后会向Receiver发送广播,可以从onCommandResult方法中的参数中获取注册信息
if (PushUtil.shouldInitMiPush(this)) {
MiPushClient.registerPush(this, APP_ID, APP_KEY);
}
}
public static boolean shouldInitMiPush(Context context) {
ActivityManager am = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE));
if (am != null) {
List<ActivityManager.RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();
String mainProcessName = context.getPackageName();
int myPid = Process.myPid();
for (ActivityManager.RunningAppProcessInfo info : processInfos) {
if (info.pid == myPid && mainProcessName.equals(info.processName)) {
return true;
}
}
}
return false;
}

Activity

/**
* 1、设置 topic 和 alias。 服务器端使用 appsecret 即可以向demo发送广播和单点的消息。<br/>
* 2、为了修改本 demo 为使用你自己的 appid,你需要修改几个地方:Application中的 APP_ID 和 APP_KEY
* AndroidManifest.xml 中的 packagename,和权限 permission.MIPUSH_RECEIVE 的前缀为你的 packagename。
*/
public class MiPushTestActivity extends ListActivity { public static boolean isForeground = false; protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] array = {"设置别名",
"撤销别名",
"设置帐号",
"撤销帐号",
"设置标签", "撤销标签",
"设置接收消息时间",
"暂停推送",
"重新开始推送",};
setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, new ArrayList<>(Arrays.asList(array))));
} @Override
protected void onResume() {
isForeground = true;
super.onResume();
} @Override
protected void onPause() {
isForeground = false;
super.onPause();
} @Override
protected void onListItemClick(ListView l, View v, int position, long id) {
switch (position) {
case 0:
set_alias();
break;
case 1:
unset_alias();
break;
case 2:
set_account();
break;
case 3:
unset_account();
break;
case 4:
subscribe_topic();
break;
case 5:
unsubscribe_topic();
break;
case 6:
int startHour = 10;
int startMin = 0;
int endHour = 23;
int endMin = 0;
MiPushClient.setAcceptTime(this, startHour, startMin, endHour, endMin, null);
break;
case 7:
MiPushClient.pausePush(this, null);
break;
case 8:
MiPushClient.resumePush(this, null);
break;
}
} public void set_alias() {
final EditText editText = new EditText(this);
new AlertDialog.Builder(this)
.setTitle("设置别名")
.setView(editText)
.setPositiveButton("确认", (dialog, which) -> {
String alias = editText.getText().toString();
MiPushClient.setAlias(this, alias, null);
})
.setNegativeButton("取消", null)
.show();
} public void unset_alias() {
final EditText editText = new EditText(this);
new AlertDialog.Builder(this)
.setTitle("撤销别名")
.setView(editText)
.setPositiveButton("确认", (dialog, which) -> {
String alias = editText.getText().toString();
MiPushClient.unsetAlias(this, alias, null);
})
.setNegativeButton("取消", null)
.show(); } public void set_account() {
final EditText editText = new EditText(this);
new AlertDialog.Builder(this)
.setTitle("设置帐号")
.setView(editText)
.setPositiveButton("确认", (dialog, which) -> {
String account = editText.getText().toString();
MiPushClient.setUserAccount(this, account, null);
})
.setNegativeButton("取消", null)
.show(); } public void unset_account() {
final EditText editText = new EditText(this);
new AlertDialog.Builder(this)
.setTitle("撤销帐号")
.setView(editText)
.setPositiveButton("确认", (dialog, which) -> {
String account = editText.getText().toString();
MiPushClient.unsetUserAccount(this, account, null);
})
.setNegativeButton("取消", null)
.show();
} public void subscribe_topic() {
final EditText editText = new EditText(this);
new AlertDialog.Builder(this)
.setTitle("设置标签")
.setView(editText)
.setPositiveButton("确认", (dialog, which) -> {
String topic = editText.getText().toString();
MiPushClient.subscribe(this, topic, null);
})
.setNegativeButton("取消", null)
.show();
} public void unsubscribe_topic() {
final EditText editText = new EditText(this);
new AlertDialog.Builder(this)
.setTitle("撤销标签")
.setView(editText)
.setPositiveButton("确认", (dialog, which) -> {
String topic = editText.getText().toString();
MiPushClient.unsubscribe(this, topic, null);
})
.setNegativeButton("取消", null)
.show();
} @Subscribe(threadMode = ThreadMode.MAIN)
public void onPushEvent(BasePushBean bean) {
TextView tv = new TextView(this);
tv.setTextColor(Color.BLUE);
tv.setText(bean.msg);
getListView().addFooterView(tv);
}
}

Receiver

/**
* 注意,重写的这些方法都运行在非 UI 线程中
*/
public class MiPushReceiver extends PushMessageReceiver { @Override
/*用来接收服务器向客户端发送的透传消息*/
public void onReceivePassThroughMessage(Context context, MiPushMessage message) {
if (message == null) return;
Log.i("bqt", "【onReceivePassThroughMessage】" + message.toString());
printMsg(message);
new Handler(Looper.getMainLooper()).post(() -> PushMsgReceiverHelper.getInstance().onMiPushMsgReceiver(message));
} @Override
/*用来接收服务器向客户端发送的通知消息,这个回调方法会在用户手动点击通知后触发*/
public void onNotificationMessageClicked(Context context, MiPushMessage message) {
Log.i("bqt", "【onNotificationMessageClicked】" + message.toString());
printMsg(message);
} @Override
/*用来接收服务器向客户端发送的通知消息,这个回调方法是在通知消息到达客户端时触发。
另外应用在前台时不弹出通知的通知消息到达客户端也会触发这个回调函数。*/
public void onNotificationMessageArrived(Context context, MiPushMessage message) {
Log.i("bqt", "【onNotificationMessageArrived】" + message.toString());
printMsg(message);
} @Override
/*用来接收客户端向服务器发送命令后的响应结果*/
public void onCommandResult(Context context, MiPushCommandMessage message) {
Log.i("bqt", "【onCommandResult】" + message.toString());
printCmdMsg(message);
} @Override
/*用来接收客户端向服务器发送注册命令后的响应结果*/
public void onReceiveRegisterResult(Context context, MiPushCommandMessage message) {
Log.i("bqt", "【onReceiveRegisterResult】" + message.toString());
String command = message.getCommand();
List<String> arguments = message.getCommandArguments();
String cmdArg1 = ((arguments != null && arguments.size() > 0) ? arguments.get(0) : null);
Log.i("bqt", "command=" + command + " " + cmdArg1);
} private void printMsg(MiPushMessage message) {
String topic = message.getTopic();
String alias = message.getAlias();
String content = message.getContent();
Log.i("bqt", "topic=" + topic + " alias=" + alias + " content=" + content);
} private void printCmdMsg(MiPushCommandMessage message) {
String command = message.getCommand();
List<String> arguments = message.getCommandArguments();
String cmdArg1 = ((arguments != null && arguments.size() > 0) ? arguments.get(0) : null);
String cmdArg2 = ((arguments != null && arguments.size() > 1) ? arguments.get(1) : null);
Log.i("bqt", "command=" + command + " " + cmdArg1 + " " + cmdArg2); switch (command) {
case MiPushClient.COMMAND_REGISTER://注册
if (message.getResultCode() == ErrorCode.SUCCESS) {
Log.i("bqt", "注册成功 mRegId =" + cmdArg1);
}
break;
case MiPushClient.COMMAND_SET_ALIAS://设置别名
if (message.getResultCode() == ErrorCode.SUCCESS) {
Log.i("bqt", "设置别名成功 mAlias =" + cmdArg1);
}
break;
case MiPushClient.COMMAND_UNSET_ALIAS://取消设置别名
if (message.getResultCode() == ErrorCode.SUCCESS) {
Log.i("bqt", "取消设置别名成功 mAlias =" + cmdArg1);
}
break;
case MiPushClient.COMMAND_SET_ACCOUNT://设置账户
if (message.getResultCode() == ErrorCode.SUCCESS) {
Log.i("bqt", "设置账户成功 mAccount =" + cmdArg1);
}
break;
case MiPushClient.COMMAND_UNSET_ACCOUNT://撤销账户
if (message.getResultCode() == ErrorCode.SUCCESS) {
Log.i("bqt", "撤销账户成功 mAccount =" + cmdArg1);
}
break;
case MiPushClient.COMMAND_SUBSCRIBE_TOPIC://订阅标签
if (message.getResultCode() == ErrorCode.SUCCESS) {
Log.i("bqt", "订阅标签成功 mTopic =" + cmdArg1);
}
break;
case MiPushClient.COMMAND_UNSUBSCRIBE_TOPIC://撤销标签
if (message.getResultCode() == ErrorCode.SUCCESS) {
Log.i("bqt", "撤销标签成功 mTopic =" + cmdArg1);
}
break;
case MiPushClient.COMMAND_SET_ACCEPT_TIME://设置接收推送时间
if (message.getResultCode() == ErrorCode.SUCCESS) {
Log.i("bqt", "设置接收推送时间成功 mStartTime =" + cmdArg1 + " mEndTime=" + cmdArg2);
}
break;
default:
Log.i("bqt", "未知命令,Reason=" + message.getReason());
break;
}
}
}

消息处理类

/**
* 处理推送SDK推过来的自定义消息(又叫应用内消息,或者透传消息)
*/
public class PushMsgReceiverHelper {
private static PushMsgReceiverHelper instance = new PushMsgReceiverHelper(); private PushMsgReceiverHelper() {
} public static PushMsgReceiverHelper getInstance() {
return instance;
} /**
* 处理极光推送推过来的自定义消息
*/
public void onJPushMsgReceiver(Bundle bundle) {
} /**
* 处理小米推送推过来的自定义消息
*/
public void onMiPushMsgReceiver(MiPushMessage message) {
Log.i("bqt", "【小米推送】" + message);
if (MiPushTestActivity.isForeground) {
EventBus.getDefault().post(new BasePushBean(message.getContent(), BasePushBean.TYPE_STRING));
}
} /**
* 处理华为光推送推过来的自定义消息
*/
public void onHuaweiPushMsgReceiver(String message) {
} /**
* 处理魅族推送推过来的自定义消息
*/
public void onMeiZhuPushMsgReceiver(String message) {
} }

配置文件

build.gradle

implementation files('libs/MiPush_SDK_Client_3_6_2.jar')

混淆文件:proguard-android.txt

client sdk已经混淆过了,不需要再混淆。请使用keep命令保留client sdk的内容:

-keep class com.bqt.push.receiver.MiPushReceiver {*;}
#可以防止一个误报的 warning 导致无法成功编译,如果编译使用的 Android 版本是 23。
-dontwarn com.xiaomi.push.**

AndroidManifest.xml

<!--====================== 推送SDK需要定义的权限 =====================-->
<!--极光-->
<!--小米-->
<permission
android:name="${applicationId}.permission.MIPUSH_RECEIVE"
android:protectionLevel="signature"/>
<uses-permission android:name="${applicationId}.permission.MIPUSH_RECEIVE"/>
<!--华为-->
<!--魅族-->
<!--========================= 小米推送需要注册的组件 start =========================-->
<receiver
android:name=".receiver.MiPushReceiver"
android:exported="true"
tools:ignore="ExportedReceiver">
<intent-filter>
<action android:name="com.xiaomi.mipush.RECEIVE_MESSAGE"/>
</intent-filter>
<intent-filter>
<action android:name="com.xiaomi.mipush.MESSAGE_ARRIVED"/>
</intent-filter>
<intent-filter>
<action android:name="com.xiaomi.mipush.ERROR"/>
</intent-filter>
</receiver> <receiver
android:name="com.xiaomi.push.service.receivers.NetworkStatusReceiver"
android:exported="true">
<intent-filter>
<action
android:name="android.net.conn.CONNECTIVITY_CHANGE"
tools:ignore="BatteryLife"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver> <receiver
android:name="com.xiaomi.push.service.receivers.PingReceiver"
android:exported="false"
android:process=":pushservice">
<intent-filter>
<action android:name="com.xiaomi.push.PING_TIMER"/>
</intent-filter>
</receiver> <service
android:name="com.xiaomi.push.service.XMJobService"
android:enabled="true"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE"
android:process=":pushservice"/>
<service
android:name="com.xiaomi.push.service.XMPushService"
android:enabled="true"
android:process=":pushservice"/>
<service
android:name="com.xiaomi.mipush.sdk.PushMessageHandler"
android:enabled="true"
android:exported="true"
tools:ignore="ExportedService"/>
<service
android:name="com.xiaomi.mipush.sdk.MessageHandleService"
android:enabled="true"/>
<!--========================= 小米推送需要注册的组件 end =========================-->

2018-4-18

小米推送 简介 集成 MD的更多相关文章

  1. 魅族推送 简介 集成 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  2. 华为推送 简介 集成 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  3. XiaomiPushDemo【小米推送集成,基于V3.6.12版本】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 这个Demo只是记录小米推送的集成,不能运行. 使用步骤 一.项目组织结构图 注意事项: 1.  导入类文件后需要change包名以 ...

  4. 极光推送 JPush 简介 集成 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  5. iOS 小米推送总结和遇到的坑

    极光推送就不赘述了,这里说下小米推送在ios上的坑吧,查了好久也没有查到相关的文章. 极光的强大就不说了,当客户贪图实惠的时候,当人家给你让你用小米推送的时候,我的内心是崩溃的,小米推送???没听过! ...

  6. umeng友盟消息推送功能集成

    umeng友盟消息推送功能集成(本人使用的是eclipse开发) 1.首先请自行观看友盟消息推送集成的API文档. 观看地址如下: http://dev.umeng.com/push/android/ ...

  7. idea + springboot 的java后台服务器通过小米推送

    public class XiaomiPush { // 1.小米推送(我只推送Android且只应用regId发起推送,所以下面只有推送Android的代码 private static final ...

  8. 手把手教你搞定个推iOS推送SDK集成

    以下是一位开发者在集成个推iOS推送SDK过程中的真实经历. 作者:Ezreallp 一次偶然的机会,公司的项目要用到推送,我自己本来就很懒,不愿意去弄整套APNS的流程,刚好之前跟朋友聊起过他们的产 ...

  9. (转载)iOS 极光推送SDK 集成指南

    iOS SDK 集成指南 使用提示 本文匹配的 SDK版本:r1.2.5 以后. 查看最近更新了解最新的SDK更新情况. 产品功能说明 极光推送(JPush)是一个端到端的推送服务,使得服务器端消息能 ...

随机推荐

  1. Python基础笔记(三)

    1. 循环与流程控制 (1) for myList1 = ["A", "B", "C", "D"] # 正序遍历 for ...

  2. 添加第一个控制器(Controllers)

    在MVC体系架构中,输入请求是由控制器Controller来处理的(负责处理浏览器请求,并作出响应).在ASP.NET MVC中Controller本身是一个类(Class)通常继承于System.W ...

  3. jquery开发表格插件项目之知识点累积 二

    $.addClass() 增加样式 $.removeClass() 去除样式 $.toggleClass() 单击增加样式,再单击取消样式 $.hasClass() 判断是否存在样式,存在返回true ...

  4. Codeforces Round #394 (Div. 2) A. Dasha and Stairs 水题

    A. Dasha and Stairs 题目连接: http://codeforces.com/contest/761/problem/A Description On her way to prog ...

  5. HDU 5744 Keep On Movin 贪心

    Keep On Movin 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5744 Description Professor Zhang has k ...

  6. Programming Internal Flash Over the Serial Wire Debug <SWD> Interface -- EFM32

    1 Debug Interface Overview 1.1 Serial Wire Debug Serial Wire Debug (SWD) is a two-wire protocol for ...

  7. 【Go入门教程3】基本类型 和 高级类型

    基本类型 Go 有很多预定义类型,这里简单地把它们分为 基本类型 和 高级类型.Go 的基本类型并不多,而且大部分都与整数相关,如下表所示: 名 称 宽度(字节) 零 值 说 明 bool 1 fal ...

  8. 解决iframe加载的内容有时显示有时不显示

    在ASP.NET MVC项目中遇到了这样的一个问题,假设父页面有一个iframe <iframe id=" width="100%" height="10 ...

  9. android:activity活动的生命周期

    掌握活动的生命周期对任何 Android 开发者来说都非常重要,当你深入理解活动的生命 周期之后,就可以写出更加连贯流畅的程序,并在如何合理管理应用资源方面,你会发挥的 游刃有余.你的应用程序将会拥有 ...

  10. UITableView分割线样式与颜色

    tv.separatorStyle = UITableViewCellSeparatorStyleSingleLine;   //设置样式 tv.separatorColor = [UIColor c ...