Android 推送消息开放接口 OpenPush

我们知道, 在中国不能使用 google 的服务. 在中国销售的手机甚至没有安装 google 的服务.所以, 原本由 google gcm 提供的推送消息服务, 在中国是不可以使用的.

你的 app 要在中国市场的 android 手机上可用, 需要自带消息推送. 这是可以做到的,因为 android 允许 app 使用后台服务.

重要的问题来了, 一大堆 app 在后台运行, 会减少手机电池的续航时间. 所以, 在中国销售的手机 ROM系统有一个特殊任务, 就是杀死这些后台服务. 这样的话, 你的 app 就收不到推送消息了. 为了解决这个问题, 甚至出现了“全家桶”的概念, 就是一家公司的多个 app 互相唤醒保持消息畅通.

其实, 我们 app 只要一个可靠的,不被杀死的推送消息系统, 有那么难吗?

这件事应该由手机厂商来做, 在他们的 Android ROM 中加入一个类似 gcm 的服务. 的确, 小米, 华为都做了这事. 但是, 问题来了, 软件厂商做 app 时必须对它们分别适配, 分别搞一个小米版, 华为版或者搞一个综合版. 还需要携带它们的库文件. 即便这样, 你仍然不能复盖大部分中国市场, 听说 oppo,vivo 已经占销量前两位了, 这两个厂根本就没有内置的消息推送.(如果有的话,至少他们没有广告开发者.)

我曾经看过小米和华为的推送消息 API 文档, 老实说比较复杂, 不容易上手, 放弃了. 我想就算费了老劲搞好了, 也只能管到华为的部分机型.(竟然不是全部!)

如果由某个手机厂商来号召全部手机厂商做统一的推送消息 API, 难度不是一般的大. 因为中国还没有一个绝对老大, 他们还互相不服气. 我想只能由"局外人"来号召他们坐下来谈这件事. 这个局外人只能是 app 厂商, 并且不能很强势如腾讯,百度, 否则, 他们还是不买帐. 那么我们就来做这件事吧.

我认为这个推送消息 API 这样设计,

  1. 实现 API 是厂商的事. 使用 API 是我们 app 的事.
  2. 它应该统一. 一个代码, 到处运行. 写一个 app, 适应所有的手机, 包括以后出现的新的厂商新的手机.只要这个厂商按这个 API 来做它的手机.
  3. 消息服务器不能由 API 指定, 应该由手机厂商决定. 原则上, 消息服务器应该由手机厂商建立和维护. 如果有第三方做这个服务器,那也是这个第三方与手机厂商的合作, 我们 app 不关心到底是谁提供了这个服务. 概念上, 我们认为是手机厂商提供了这个服务.
  4. 尽量少的规范和尽量使用成熟标准.
  5. API 必须简洁, 使用必须简单. 它做它该做的事. 不要做它不该做的事. 现在的消息系统, 甚至包括google gcm 都做了许多与消息推送无关的事.
  6. API 只是代码规范. 它本身不需要其它库文件.现在小米, 华为, 包括 google gcm 都带库文件, 你使用它们的推送都要带相应的库文件. 我认为这样很麻烦. 如果只是 gcm 一家, 那带一个库没有问题. 可是, 我们现在要面对很多家,如果一家一个库文件, 那结果 apk 包就太大了. 并且这样还不能适应新的厂商的手机.
  7. app 不需要去每个手机厂商注册. 手机厂商那么多, 一个一个注册, 很麻烦.用户也不需要另外注册. 我买了你的手机, 就应该使用你的服务.对比一下, google gcm 就很麻烦. app 需要在它的平台上注册获取 push key, 手机用户需要 google play 帐号才能使用.

提出了这么多要求, 那么, 这是不是可以做到的呢? 是可以的. 我们已经做了一个 OpenPush 的 API放到 github 上面了. 搜 OpenPush 就可以找到. 那么它的 API 到底是怎么样的呢?

我们来看它的 app, 下载 OpenPush 的 pushapp 包, 这是一个使用这个 API 的 app 例子.

首先要在 AndroidManifest.xml 声明接收广播消息 OPENPUSH.MESSAGE, 它对应到一个 receiver.

       <receiver android:name=".openpush_receiver"><intent-filter><action android:name="OPENPUSH.MESSAGE" /></intent-filter></receiver>

这个广播只有两种消息, 一个是手机的 token 消息, 一个是推送消息 message.

我们来看看它的源代码

public class openpush_receiver extends BroadcastReceiver
{// 接收广播public void onReceive(Context context, Intent intent){// 获取 tokenString token = intent.getStringExtra("token");if( token != null ){String push_server = intent.getStringExtra("server");....return ;}// 获取消息String message = intent.getStringExtra("message");if( message != null ){// 获取消息 json 格式....return ;}}
}

我们的 app 开始时应该注册推送消息服务程序, 告诉它有消息时广播给我. 下面是注册程序.我们把它写成了 receiver 的 static 过程.

public class openpush_receiver extends BroadcastReceiver
{private static final String TAG = "TEST" ;// 注册public static boolean register( Context context ){// 查找服务程序 ACTION = "OPENPUSH.SERVICE"Intent i = new Intent( "OPENPUSH.SERVICE" );PackageManager pm = context.getPackageManager();List list = pm.queryIntentServices(i, 0);if( list.size() > 0 ){// 找到了它// 向服务程序注册本 app 包名i.putExtra( "packname", context.getPackageName() );context.startService(i);return true ;}// 不存在这个服务return false ;}....}

我们再来看这个 app 主程序,

   public void onCreate(Bundle savedInstanceState){......// 如果本手机没有这个服务 ...if( ! openpush_receiver.register( this ) )....}

好了, 涉及到推送消息的 app 代码全部在这里了.

你可能有个疑问, 那个名称叫 "OPENPUSH.SERVICE" 的服务程序在那里 ?

噢, 那是手机厂商内置到 ROM 中的一个服务程序, 它正是推送消息服务程序. 这是手机厂商要做的事,不是我们 app 的事, 我们只要找到这个程序并把自己注册给它, 然后坐等它广播 token 和推送消息.

提示一下, "OPENPUSH.SERVICE" 不是包名, 它只是 ACTION 名称. 厂商实现它的推送消息服务程序可能叫 com.mi.xxx 或者 com.huawei.zzz 或者其它名称. 我们不关心它到底叫什么, 只要它能响应"OPENPUSH.SERVICE" 这个 ACTION 就可以了.

推送消息

通常我们有一个 app 消息服务器,负责推送消息. 这个消息首先被送到手机厂商的推送消息服务器.

那么这个推送消息服务器的地址在那里? 我们看上面的代码, token 中就有它的地址

       // 获取 tokenString token = intent.getStringExtra("token");if( token != null ){String push_server = intent.getStringExtra("server");...}

这是一个什么样的服务器 ? 我们规定这是一个 http 服务器, 所以它可能是这样的

       push_server = "http://www.anybody.com/openpush/"

我们只要给这个 http 服务器 POST 消息就可以了. 这个消息格式必须是这样的,

       // 消息采用 json 格式, 前 4 个字段一定要有, 其它内容自定义{"token" : "<token>","packname" : "com.test.xxx", app 包名称"subject" : "hello","timeout" : 120, 秒......}

我们编写的 app 测试程序, 演示了如何 POST 消息.( 这本来应该是 app 消息服务器做的事. )

如何编写 推送消息服务程序 ?

如果你是手机厂商, 自然要问这个问题. 我的回答是, 你编写的程序必须响应 "OPENPUSH.SERVICE" 这个 ACTION,其实这个 ACTION 并没有任何实质动作. 它只是用来告诉 android 系统, 我就是一个推送消息服务程序.

其次, 它要响应注册, 对应的 app 代码是

   // 找到了它// 向服务程序注册本 app 包名i.putExtra( "packname", context.getPackageName() );context.startService(i);

还有, 它要向 app 广播 token 和推送消息.

注意, 我们的 API 并没有规定, 推送消息是如何被转发到手机的, 这是推送消息服务程序要干的事,没有任何指导或强制规范. 推送消息服务器是如何编写, 那也没有什么指导或强制规范,能用就行.唯一提示是, 注意省电.

推送消息服务程序写好后, 建议使用这个 pushapp 做基本测试.

我们在 github 上的 OpenPush 项目中提供了一个这样的源代码, 推送消息服务程序 OpenPush. 可以做为参考或者在它基础上改进后使用. 至于服务器端的程序, 那就自己编写吧, 应该不是什么难事.

如何演进 ?

这件事看起来很美妙. 我们写 app 不再需要关心有没有可靠的推送消息了, 也不需要跟手机厂商"斗智斗勇", 搞什么“全家桶”以及研究“如何让app消息不被杀掉”.

但是, 我要说"但是"了. 目前还没有一个厂商采用 OpenPush. 这仅仅是我们的"愿景", 甚至可能是"远景". 那么现在,我们可以做什么 ?

我们可以在 app 中自带 OpenPush, 先检查系统有没有 OpenPush, 如果没有, 把自带的 OpenPush 安装上.只要你安装上了 OpenPush, 其它 app 也可以用, 所以你这个 OpenPush 其实是共享的.

你可以使用 github 上面的 OpenPush 源代码, 修改一下, 例如修改服务器地址和通讯方式, 打包成自己的 OpenPush.apk.如果你比较懒的话, guthub 上那个 OpenPush 是可以直接使用的. 实际上它是加密电话 headcall app 正在使用的.

把这个 OpenPush.apk 文件放到 app 的 assets 目录下打包.

这么做, 在 openpush_receiver.java 中增加安装在 assets 中的 OpenPush.apk 文件

public class openpush_receiver extends BroadcastReceiver
{// 注册public static boolean register( Context context ){// 查找服务程序Intent i = new Intent( "com.messagepush.openpush" );PackageManager pm = context.getPackageManager();List list = pm.queryIntentServices(i, 0);if( list.size() > 0 ){// 告诉服务程序本 app 包名i.putExtra( "packname", context.getPackageName() );context.startService(i);return true ;}// 不存在这个服务{// 安装 公共服务openpush_install( context );return false ;}}.....// 安装 openpush : /assets/OpenPush.apkstatic void openpush_install( Context context ){try{String sdcard = Environment.getExternalStorageDirectory().getPath() ;String path = sdcard + "/OpenPush.apk" ;File file = new File(path);file.createNewFile();FileOutputStream fout = new FileOutputStream(file);InputStream fin = context.getAssets().open("OpenPush.apk");byte[] buf = new byte[1024];int i = 0;while ((i = fin.read(buf)) > 0)fout.write(buf, 0, i);fin.close();fout.close();Uri uri = Uri.fromFile( new File(path) );Intent intent = new Intent();intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.setAction(android.content.Intent.ACTION_VIEW);intent.setDataAndType(uri, "application/vnd.android.package-archive");context.startActivity(intent);} catch (IOException e) { }}

看起来问题解决了 ? 其实没有. 因为你安装的 OpenPush 只是应用程序, 它不是系统级的. 随时可能被系统秒杀.如果手机里多有几个使用 OpenPush 的 app, 那么它被唤醒的机会就多. 这样就形成了不同厂商的 app 共同保护一个 OpenPush (或许就是你的那个). 是不是有点象"全家桶" ?

我们的路线图是, OpenPush 被大家的 app 用多了, 有些手机厂商就会把它安装到 ROM 里去, 它就成了系统级的服务.时间长了, 它就成了手机 ROM 必配.

Android 推送消息开放接口 OpenPush相关推荐

  1. 1分钟实现Android推送消息

    前言 在应用中会遇到给用户推送消息的功能,在这里我推荐极光,里面有快速集成,比较方便 第一步: 创建应用.拿到apkkey 给应用设置你的项目的包名.互相关联 第二步: 设置你的应用名字(随意)上传你 ...

  2. android 动态推送权限,提升Android推送消息到达率方法介绍!

    推送消息的到达率除了用户终端的网络信号影响之外,有很大一部分是系统屏蔽原因造成的,我们经常提的一个词"app保活"其实就是为了提升推送消息的到达率,但是及时给app做了保活仍然会被 ...

  3. .net android 推送消息,android – FCM(Firebase云消息传递)推送通知与Asp.Net

    Firebase云消息传递的C#服务器端代码 using System; using System.Collections.Generic; using System.IO; using System ...

  4. Android中集成Jpush实现推送消息通知与根据别名指定推送附示例代码下载

    场景 经常会有后台服务向Android推送消息通知的情况. 实现 首先在Android Studio中新建一个Android应用 在Project根目录的build.gradle中配置了jcenter ...

  5. java 通过企业微信推送消息

    首先我们要知道企业微信推送消息的步骤,企业微信官方提供了多个API供我们调用,这里我们只讲我们需要的API: 企业微信的官方开放的API地址:https://work.weixin.qq.com/ap ...

  6. 微信公众号如何无限制的定向推送消息--模板消息的应用

    微信公众号如何无限制的定向推送消息–模板消息的应用 最近开发的OA平台有一个需求:将待办消息推送到微信公众号的指定用户.但是为了避免用户受到垃圾消息的骚扰,微信对相关的接口做了非常严格的限制. 查阅开 ...

  7. 用JPUSH极光推送实现服务端向安装了APP应用的手机推送消息(C#服务端接口)

    这次公司要我们做一个功能,就是当用户成功注册以后,他登录以后要收到消息,当然这个消息是安装了我们的手机APP应用的手机咯. 极光推送的网站的网址是:https://www.jpush.cn/ 极光推送 ...

  8. Android,ios,安卓app推送消息通知,java后台向手机推送app的通知教程

    文章目录 一.业务介绍 1.1 产品简介 1.2 名词解释 1.3 消息推送流程 二.应用创建 三.客户端 SDK 集成 3.1 Android 3.2 iOS 四.服务端推送 4.1 服务端消息下发 ...

  9. android推送服务不被关闭,Android APP被关闭后无法收到推送消息(尝试)

    1.   Android端进程被杀死后,目前自带的保护后台接收消息活跃机制.暂时没有什么好的机制保持任何情况下都活跃 文章参考:http://blog.csdn.net/marswin89/artic ...

最新文章

  1. iptables基础知识.详解
  2. activiti自己定义流程之整合(五):启动流程时获取自己定义表单
  3. 根据卡号获取银行卡名字
  4. 超过屏幕长度字符省略
  5. html ie8上传图片,图片上传本地预览兼容ie8
  6. html菜单不动属性,html5规定元素的上下文菜单属性contextmenu
  7. Word2016中出现多级标题自动编号不连续问题
  8. simulink 汽车低压电网简单仿真
  9. 变电站计算机监控 规范,110kV变电站计算机监控系统技术规范书.docx
  10. Endnote x7.5 破解 注册 激活
  11. Eclipse中,使用Darkest主题,static方法在main中不是斜体的解决办法
  12. gdb 调试 redis-cli 命令发送接收流程
  13. 微信小程序订阅消息wx.requestSubscribeMessage使用要点和requestSubscribeMessage:can only be invoked by userTAPgestur
  14. 查询手机号的归属地及运营商接口
  15. 国外计算机从什么开始学,从零开始学电脑知识 1(国外英语资料).doc
  16. 房屋租赁管理系统API
  17. 基金从业考试考前必背
  18. 广州“粤A000F1”车牌拍出74万天价(图)
  19. 华为Lite OS的物联网攻略
  20. MySQL使用空间索引问题

热门文章

  1. LeetCode 725 分隔链表
  2. 关闭烦人的Windows XP系统哔哔声
  3. 我所热衷的编程生涯 连载(11)
  4. 【Nature 子刊】I型HLA基因中和癌症相关的体细胞突变--转载
  5. signature=c4909c704a84f06fbd526ac646c599dd,각변위 방식을 이용한 캡슐의 오리엔테이션 측정 방법...
  6. varchar 和 char 的区别
  7. 欧盟《一般数据保护条例》(GDPR)你需要知道的
  8. HTTP状态码code类型
  9. 当前最为流行的可视化大屏都是怎么做的?
  10. PS进阶篇——如何PS软件钢笔工具抠图(三)