公司的 app 一直使用的是极光推送,最近反馈比较多的是推送消息收不到,看来需要找新的推送服务了,在国内目前手机品牌占有率比较多的是华为和小米,且这两家都有自己的推送服务,同时一个合作的友商说他们使用的是友盟推送,推送率还不错,那么就测试这三个推送服务了。

按照集成的难易程度排序

友盟推送

接入步骤

官网有提供了视频和文档,很详细,而且很简单。

小米推送

接入步骤

  1. 在小米推送运营平台创建应用,地址点这里, 获取到 AppID , AppKey

  2. 把从小米下载的 jar 放到 libs 下

  3. 在 AndroidManifest.xml 中添加权限

    1. <uses-permission android:name="android.permission.INTERNET" />
    2. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    3. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    4. <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    5. <uses-permission android:name="android.permission.GET_TASKS" />
    6. <uses-permission android:name="android.permission.VIBRATE"/>
    7. <permission android:name="com.xxx.xxx.permission.MIPUSH_RECEIVE" android:protectionLevel="signature" />
    8. <uses-permission android:name="com.xxx.xxx.permission.MIPUSH_RECEIVE" />
  4. 配置推送服务需要的service和receiver

    1. <service
    2. android:enabled="true"
    3. android:process=":pushservice"
    4. android:name="com.xiaomi.push.service.XMPushService"/>
    5. <service
    6. android:name="com.xiaomi.push.service.XMJobService"
    7. android:enabled="true"
    8. android:exported="false"
    9. android:permission="android.permission.BIND_JOB_SERVICE"
    10. android:process=":pushservice" />
    11. <!--注:此service必须在3.0.1版本以后(包括3.0.1版本)加入-->
    12. <service
    13. android:enabled="true"
    14. android:exported="true"
    15. android:name="com.xiaomi.mipush.sdk.PushMessageHandler" />
    16. <service android:enabled="true"
    17. android:name="com.xiaomi.mipush.sdk.MessageHandleService" />
    18. <!--注:此service必须在2.2.5版本以后(包括2.2.5版本)加入-->
    19. <receiver
    20. android:exported="true"
    21. android:name="com.xiaomi.push.service.receivers.NetworkStatusReceiver" >
    22. <intent-filter>
    23. <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    24. <category android:name="android.intent.category.DEFAULT" />
    25. </intent-filter>
    26. </receiver>
    27. <receiver
    28. android:exported="false"
    29. android:process=":pushservice"
    30. android:name="com.xiaomi.push.service.receivers.PingReceiver" >
    31. <intent-filter>
    32. <action android:name="com.xiaomi.push.PING_TIMER" />
    33. </intent-filter>
    34. </receiver>
  5. 自定义一个BroadcastReceiver类

    1. public class MiMessageReceiver extends PushMessageReceiver {
    2. private static final String TAG = "MiMessageReceiver";
    3. private String mRegId;
    4. private String mTopic;
    5. private String mAlias;
    6. private String mAccount;
    7. private String mStartTime;
    8. private String mEndTime;
    9. @Override
    10. public void onNotificationMessageClicked(Context context, MiPushMessage message) {
    11. Log.v(MyApplication.TAG,
    12. "onNotificationMessageClicked is called. " + message.toString());
    13. if (!TextUtils.isEmpty(message.getTopic())) {
    14. mTopic = message.getTopic();
    15. Log.e(TAG, mTopic);
    16. } else if (!TextUtils.isEmpty(message.getAlias())) {
    17. mAlias = message.getAlias();
    18. Log.e(TAG, mAlias);
    19. }
    20. }
    21. @Override
    22. public void onNotificationMessageArrived(Context context, MiPushMessage message) {
    23. Log.v(MyApplication.TAG,
    24. "onNotificationMessageArrived is called. " + message.toString());
    25. String log = "Arrived a notification message. Content is " + message.getContent();
    26. if (!TextUtils.isEmpty(message.getTopic())) {
    27. mTopic = message.getTopic();
    28. } else if (!TextUtils.isEmpty(message.getAlias())) {
    29. mAlias = message.getAlias();
    30. }
    31. }
    32. @Override
    33. public void onCommandResult(Context context, MiPushCommandMessage message) {
    34. Log.v(TAG,
    35. "onCommandResult is called. " + message.toString());
    36. String command = message.getCommand();
    37. List<String> arguments = message.getCommandArguments();
    38. String cmdArg1 = ((arguments != null && arguments.size() > 0) ? arguments.get(0) : null);
    39. String cmdArg2 = ((arguments != null && arguments.size() > 1) ? arguments.get(1) : null);
    40. String log;
    41. if (MiPushClient.COMMAND_REGISTER.equals(command)) {
    42. if (message.getResultCode() == ErrorCode.SUCCESS) {
    43. mRegId = cmdArg1;
    44. Log.e(TAG, "Register push success.");
    45. } else {
    46. Log.e(TAG, "Register push fail.");
    47. }
    48. } else {
    49. log = message.getReason();
    50. }
    51. }
    52. @Override
    53. public void onReceiveRegisterResult(Context context, MiPushCommandMessage message) {
    54. Log.v(TAG,
    55. "onReceiveRegisterResult is called. " + message.toString());
    56. String command = message.getCommand();
    57. List<String> arguments = message.getCommandArguments();
    58. String cmdArg1 = ((arguments != null && arguments.size() > 0) ? arguments.get(0) : null);
    59. if (MiPushClient.COMMAND_REGISTER.equals(command)) {
    60. if (message.getResultCode() == ErrorCode.SUCCESS) {
    61. mRegId = cmdArg1;
    62. Log.e(TAG, "Register push success.");
    63. } else {
    64. Log.e(TAG, "Register push fail.");
    65. }
    66. }
    67. }
    68. }
  6. 在 AndroidManifest.xml 中注册该广播

    1. <receiver
    2. android:name=".MiMessageReceiver"
    3. android:exported="true">
    4. <intent-filter>
    5. <action android:name="com.xiaomi.mipush.RECEIVE_MESSAGE"/>
    6. </intent-filter>
    7. <intent-filter>
    8. <action android:name="com.xiaomi.mipush.MESSAGE_ARRIVED"/>
    9. </intent-filter>
    10. <intent-filter>
    11. <action android:name="com.xiaomi.mipush.ERROR"/>
    12. </intent-filter>
    13. </receiver>
  7. 在 Application 中初始化推送服务

    1. private void initMiPush() {
    2. //初始化push推送服务
    3. if (shouldInit()) {
    4. MiPushClient.registerPush(this, MI_APP_ID, MI_APP_KEY);
    5. }
    6. //打开Log
    7. LoggerInterface newLogger = new LoggerInterface() {
    8. @Override
    9. public void setTag(String tag) {
    10. // ignore
    11. }
    12. @Override
    13. public void log(String content, Throwable t) {
    14. Log.d(TAG, content, t);
    15. }
    16. @Override
    17. public void log(String content) {
    18. Log.d(TAG, content);
    19. }
    20. };
    21. Logger.setLogger(this, newLogger);
    22. }
    23. private boolean shouldInit() {
    24. ActivityManager am = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE));
    25. List<ActivityManager.RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();
    26. String mainProcessName = getPackageName();
    27. int myPid = android.os.Process.myPid();
    28. for (ActivityManager.RunningAppProcessInfo info : processInfos) {
    29. if (info.pid == myPid && mainProcessName.equals(info.processName)) {
    30. return true;
    31. }
    32. }
    33. return false;
    34. }

华为推送

接入步骤(HMS-SDK版本:2.4.0.300):

  1. 把从华为 Push 推送官网下载的 aar ,位于:...\HMS-2.4.0.300\HWHMS-SDK-v2.4.0.300\libs\HMS-SDK-2.4.0.300.aar,放到工程目录的 aars 下(没有该目录的新建一个)

  2. 在 AndroidManifest.xml 文件的 Application 节点添加: meta-data 和自定义的 Receiver,如下(其中 meta-data 中的 appId 是在网页上创建应用的 id,我的是一个 8 位的数字):

    1. <meta-data
    2. android:name="com.huawei.hms.client.appid"
    3. android:value="appId">
    4. </meta-data>
    5. <!-- 第三方相关 :接收Push消息(注册、Push消息、Push连接状态)广播 -->
    6. <receiver android:name=".HuaweiPushReceiver">
    7. <intent-filter>
    8. <!-- 必须,用于接收token -->
    9. <action android:name="com.huawei.android.push.intent.REGISTRATION"/>
    10. <!-- 必须,用于接收消息 -->
    11. <action android:name="com.huawei.android.push.intent.RECEIVE"/>
    12. <!-- 可选,用于点击通知栏或通知栏上的按钮后触发onEvent回调 -->
    13. <action android:name="com.huawei.android.push.intent.CLICK"/>
    14. <!-- 可选,查看push通道是否连接,不查看则不需要 -->
    15. <action android:name="com.huawei.intent.action.PUSH_STATE"/>
    16. </intent-filter>
    17. <meta-data
    18. android:name="CS_cloud_ablitity"
    19. android:value="@string/hwpush_ability_value"/>
    20. </receiver>
  3. 在 AndroidManifest.xml 文件中添加权限

    1. <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    2. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    3. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    4. <uses-permission android:name="android.permission.WAKE_LOCK" />
    5. <uses-permission android:name="android.permission.INTERNET"/>
    6. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  4. 在 MainActivity 或者 BaseAcitivty 中初始化华为 Push ,放在 onCreate() 中初始化华为 Push

    1. private void initHuaweiPush(Context context) {
    2. HuaweiIdSignInOptions options = new HuaweiIdSignInOptions.Builder(HuaweiIdSignInOptions.DEFAULT_SIGN_IN)
    3. .build();
    4. mClient = new HuaweiApiClient.Builder(context)
    5. .addApi(HuaweiPush.PUSH_API)
    6. .addConnectionCallbacks(new HuaweiApiClient.ConnectionCallbacks() {
    7. @Override
    8. public void onConnected() {
    9. getToken();
    10. runOnUiThread(new Runnable() {
    11. @Override
    12. public void run() {
    13. tv.setText("HUAWEI onConnected, IsConnected: " + mClient.isConnected());
    14. }
    15. });
    16. Log.e(TAG, "HUAWEI onConnected, IsConnected: " + mClient.isConnected());
    17. }
    18. @Override
    19. public void onConnectionSuspended(final int i) {
    20. runOnUiThread(new Runnable() {
    21. @Override
    22. public void run() {
    23. tv.setText("HUAWEI onConnectionSuspended, cause: " + i + ", IsConnected:" +
    24. " " +
    25. mClient.isConnected());
    26. }
    27. });
    28. Log.e(TAG, "HUAWEI onConnectionSuspended, cause: " + i + ", IsConnected:" +
    29. " " +
    30. mClient.isConnected());
    31. }
    32. })
    33. .addOnConnectionFailedListener(new HuaweiApiClient.OnConnectionFailedListener() {
    34. @Override
    35. public void onConnectionFailed(@NonNull final ConnectionResult
    36. connectionResult) {
    37. runOnUiThread(new Runnable() {
    38. @Override
    39. public void run() {
    40. tv.setText("HUAWEI onConnectionFailed, ErrorCode: " + connectionResult.getErrorCode());
    41. }
    42. });
    43. Log.e(TAG, "HUAWEI onConnectionFailed, ErrorCode: " + connectionResult.getErrorCode());
    44. }
    45. })
    46. .build();
    47. mClient.connect();
    48. }
    49. @Override
    50. protected void onStart() {
    51. super.onStart();
    52. mClient.connect();
    53. }
    54. private void getToken() {
    55. if (!isConnected()) {
    56. tv.setText("get token failed, HMS is disconnect.");
    57. return;
    58. }
    59. // 同步调用方式,不会返回token,通过广播的形式返回。
    60. new Thread(new Runnable() {
    61. @Override
    62. public void run() {
    63. PendingResult<TokenResult> token = HuaweiPush.HuaweiPushApi.getToken(mClient);
    64. token.await();
    65. }
    66. }).start();
    67. }
    68. public boolean isConnected() {
    69. if (mClient != null && mClient.isConnected()) {
    70. return true;
    71. } else {
    72. return false;
    73. }
    74. }
  5. 新建 HuaweiPushReceiver ,继承 PushReceiver,重写 onToken() ,onPushMsg(),onEvent(),onPushState(),在 onToken() 中可以获取到 token。

    1. public class HuaweiPushReceiver extends PushReceiver {
    2. private static final String TAG = "Huawei PushReceiver";
    3. @Override
    4. public void onToken(Context context, String token, Bundle extras) {
    5. String belongId = extras.getString("belongId");
    6. String content = "get token and belongId successful, token = " + token + ",belongId = " + belongId;
    7. Log.d(TAG, content);
    8. }
    9. @Override
    10. public boolean onPushMsg(Context context, byte[] msg, Bundle bundle) {
    11. try {
    12. String content = "-------Receive a Push pass-by message: " + new String(msg, "UTF-8");
    13. Log.d(TAG, content);
    14. } catch (Exception e) {
    15. e.printStackTrace();
    16. }
    17. return false;
    18. }
    19. public void onEvent(Context context, PushReceiver.Event event, Bundle extras) {
    20. if (Event.NOTIFICATION_OPENED.equals(event) || Event.NOTIFICATION_CLICK_BTN.equals(event)) {
    21. int notifyId = extras.getInt(BOUND_KEY.pushNotifyId, 0);
    22. if (0 != notifyId) {
    23. NotificationManager manager = (NotificationManager) context
    24. .getSystemService(Context.NOTIFICATION_SERVICE);
    25. manager.cancel(notifyId);
    26. }
    27. String content = "--------receive extented notification message: " + extras.getString
    28. (BOUND_KEY.pushMsgKey);
    29. Log.d(TAG, content);
    30. }
    31. super.onEvent(context, event, extras);
    32. }
    33. @Override
    34. public void onPushState(Context context, boolean pushState) {
    35. try {
    36. String content = "---------The current push status: " + (pushState ? "Connected" :
    37. "Disconnected");
    38. Log.d(TAG, content);
    39. } catch (Exception e) {
    40. e.printStackTrace();
    41. }
    42. }
    43. }
  6. 获取到 token 以后就连接成功了。可以测试推送了。

非华为手机使用华为推送需要安装-华为移动服务.apk

各个版本EMUI对push的支持情况

华为手机上:

Emui3.0上,Push广播有很大概率被限制,如: Mate7 3.0版本,荣耀6plus,P7 3.0版本,4X, 4A等。

Emui3.1上,Push广播基本不被限制,但个别型号机型存在问题,如:荣耀5x等。

Emui4.0及以上,Push广播有较高概率被限制,不被限制的机型如:荣耀畅玩4C,荣耀畅玩4X,Mate S,P8 MAX等。

Emui4.1 , ROM升级到了最新版本的(80%已升),通知消息不走广播,不会被限制,透传消息走广播,会被限制。

Emui5.0以上 ,通知消息不走广播,不会被限制,透传消息走广播,会被限制。

如广播被限制,需要将应用设为开机启动项。所以对于及时性或到达率要求非常高的应用,我们建议应用要考虑替代方案。

非华为手机:

第三方手机(如:小米、OPPO、三星等),由于rom的限制,需要将应用 设为开机启动项。

测试设备

  • Samsung S4(Android 5.0)
  • HTC D820u(Android 6.0)
  • Huawei P8(Android 6.0)
  • Xiaomi Note(Android 7.0)
  • Samsung S7(Android 7.0)
  • LG Nexus 6(Android 7.0)
  • Huawei Mate8(Android 7.0)
  • Huawei Mate9(Android 7.0)

测试数据

三家推送比较

  1. 华为推送在非华为手机上必须安装华为移动服务,这点比较的坑,用户可能不会同意安装的,那就没得玩了,只适合在华为手机上使用。
  2. 华为推送还得区别 Emui 的版本,这玩意也不是个小坑,虽然官方QQ群公告说 Emui 5.0 以后都可以收到消息推送,但是不知道靠谱不靠谱
  3. 友盟推送的话,在测试阶段,发现三星S7(Android 7.0),三星S4(Android 5.0),华为P8(Android 6.0)无法获取到 token,没有 token ,那就推送不了了。
  4. 小米推送还可以,但是在三星 S4(Android 5.0) 上无法接收到推送。
  5. 综上,app 需要集成华为推送和小米推送比较的靠谱点,针对华为手机使用华为推送,其他手机使用小米推送。
  6. 使用中的大坑,在华为手机上假如华为移动服务不是最新版本或者被卸载了,推送服务无法使用。必须在 app 中提示用户更新或安装,真是一个大坑,关键是更新界面丑的要死,还会出现更新失败的情况,坑人呀。
  7. 针对小米推送,在非小米设备上会出现重启以后无法获得推送,因为是重启以后,小米的 XMPushService 没有起来,目前采用的办法是监听手机启动广播,然后启动小米的 XMPushService。

Android 推送集成华为,小米,友盟的更多相关文章

  1. HWPushDemo【华为推送集成,基于2.6.1.301版本】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 这个Demo只是记录华为推送的集成,不能运行. 另外,因为可能用到存储权限,所以还需要搭配运行时权限申请功能. 使用步骤 一.项目组 ...

  2. ANDROID 推送到底哪家强(转)

    之前在群里有同学问我关于推送的一些问题,解答之后我觉得这个话题还挺有用,因为几乎大部分人都会遇到这个问题,那姑且就写篇文章总结给你们吧. 1. 为什么要用推送? 推送功能可谓是现如今任何一个 App ...

  3. Android推送技术研究

    前言 最近研究Android推送的实现, 研究了两天一夜, 有了一点收获, 写下来既为了分享, 也为了吐槽. 需要说明的是有些东西偏底层硬件和通信行业, 我对这些一窍不通, 只能说说自己的理解. 为什 ...

  4. Android推送方案

    一. 常见的推送原理: 1)轮询(Pull)方式:应用程序应当阶段性的与服务器进行连接并查询是否有新的消息到达,你必须自己实现与服务器之间的通信,例如消息排队等.而且你还要考虑轮询的频率,如果太慢可能 ...

  5. 转:Android推送技术研究

    Android推送技术研究 字数5208 阅读4026 评论5 喜欢35 前言 最近研究Android推送的实现, 研究了两天一夜, 有了一点收获, 写下来既为了分享, 也为了吐槽. 需要说明的是有些 ...

  6. android推送方式

    本文介绍在Android中实现推送方式的基础知识及相关解决方案.推送功能在手机开发中应用的场景是越来起来了,不说别的,就我们手机上的新闻客户端就时不j时的推送过来新的消息,很方便的阅读最新的新闻信息. ...

  7. Android推送服务(1)几种实现方式

    1.几种常见的解决方案实现原理 1)轮询(Pull)方式:应用程序应当阶段性的与服务器进行连接并查询是否有新的消息到达,你必须自己实现与服务器之间的通信,例如消息排队等.而且你还要考虑轮询的频率,如果 ...

  8. Android推送服务——百度云推送

    一.推送服务简介 消息推送,顾名思义,是由一方主动发起,而另一方与发起方以某一种方式建立连接并接收消息.在Android开发中,这里的发起方我们把它叫做推送服务器(Push Server),接收方叫做 ...

  9. Mosquitto搭建Android推送服务(一)MQTT简介

    总体概要: MQTT系列文章分为4部分 1.MQTT简介 2.mosquitto服务器搭建 3.编写Mosquitto的可视化工具 4.使用Mosquitto完成Android推送服务 文章钢要: 对 ...

随机推荐

  1. 使用Oracle Data Integrator Studio创建资料档案库

    一.Creating the Database Schema /*第1步:创建临时表空间 */ create temporary tablespace user_temp tempfile 'C:\a ...

  2. ISCSI测试

    Initiator为应用客户端,服务端Target包括设备服务器端和队列管理两部分.服务端两种共享方式:1.在服务端共享分区2.在服务端以文件方式作为共享设备共享出来 构建ISCSI网络存储 测试环境 ...

  3. oracle11g-R2静默安装报错[INS-32013]解决方案

    问题描述: oracle静默安装很强大...,参数搞不对.安装就扯dan了....这个报错搞了一个下午.终于搞定了如释负重.... 如果当初选择仅仅安装oracle软件就没多事情.想一步完成(数据库软 ...

  4. weblogic静默安装指导

    Linux图形化很少,再生产上.静默安装基本上是家常便饭... 心得: Oracle的官方文档很全,值得后续学习指导文件 weblogic10.3.6官方文档 https://docs.oracle. ...

  5. Oracle自学笔记(一)

    1.创建用户并指定表空间 create user gy_3004 identified by gy_3004 default tablespace gy_3004_data temporary tab ...

  6. Java线程(十一):Fork/Join-Java并行计算框架

    并行计算在处处都有大数据的今天已经不是一个新奇的词汇了.如今已经有单机多核甚至多机集群并行计算.注意,这里说的是并行,而不是并发.严格的将,并行是指系统内有多个任务同一时候运行,而并发是指系统内有多个 ...

  7. 【Android开发经验】怎样查看android-support-v4支持包中的源代码

    在support-v4包里面.加入了非常多的支持控件,比方ViewPager,Fragment等,为了解决一些问题,我们有时候想要看一下实现源代码,可是点进去之后.源代码并不会显示出来,会出现以下的情 ...

  8. 【laravel5.*】添加ide_helper.php 助手

    1.参照文档:https://github.com/barryvdh/laravel-ide-helper#automatic-phpdoc-generation-for-laravel-facade ...

  9. [转载]TortoiseGit安装与使用

    原文地址:TortoiseGit安装与使用作者:了凡春秋 之前一直用SVN做项目开发,确实感觉这些版本控制工具非常实用,尤其是在一个团队开发项目的时候.最近偶然看到一个新的版本管理工具Git,它本来是 ...

  10. Java交替打印两个字符串

    一.使用volatile关键字 public class Main { volatile int x = 0; Main() { new Thread(() -> { while (x < ...