(4.2.12)浅谈第三方推送[推送基础]:百度推送、小米推送、华为推送

市面上目前做免费推送服务的有很多,友盟、极光、百度、小米、华为等,由于android机型的多样性,在使用单独的一种推送时,往往会造成一些机型无法获取(当然,内部原因可能很复杂)。

Android 第三方 Push 推送方案使用调查

因此往往需要同时集成多个第三方推送,并且能做到:

  • 自动识别机型以选取对应的SDK
  • 也希望设定阀门,在多次建联失败时,可以自动切换SDK,以尝试不同的推送服务
  • 记录状态,自动选定上次记录的推送服务SDK

目前,采用了百度、小米和华为的推送SDK,层次上以百度为主覆盖大量机型,小米和华为为辅覆盖专有机型。
三种SDK在基本的使用方法上大同小异,现简单加以说明:

什么是推送

在移动互联网时代,移动端的开发都必须涉及 客户端/服务端的概念,但是从字面上看,服务端和客户端是完全独立的两套逻辑

客户端可以主动的向服务端请求数据,譬如最常见的登录,用户输入账户密码,点击确定按钮—客户端主动把信息抛给给服务端,并等待服务端返回—-服务端返回校验状态–客户端拿到,并呈现相应的UI状态

注意,上述流程的起点是客户端主动发起请求那么问题来了,一旦服务端的数据发生了变更,如何主动告知客户端

那么问题来了,一旦服务端的数据发生了变更,如何主动告知客户端呢? 譬如,你的服务器收到了一个紧急邮件,但是你没在电脑前边,服务器如果通知到你呢?

这种服务器主动发起的信息交互,就是推送

关于推送的具体概念和不同实现方式,可以自行查看http://www.cnblogs.com/liangqihui/p/3539984.html

  1. 轮训方式 客户端不断向服务器主动请求
  2. 长连接方式 客户端和服务端维持一个长连接,类似一个双向流通的管道,有信息就丢进去,对方一直在保持监听

端内推送、端外推送、第三方推送这些名词到底是啥意思的?

在进行一下概念之前,先声明一点,也存在一些app的端内推送和端外推送是混合在一起的,譬如完全使用第三方的推送构建自己的聊天或业务逻辑,再譬如完全不依赖第三方,把自己的端内推送做的牛逼到可以用作端外

其实这些概念的界限很模糊,我们就kdzl本身来谈一下:

  • 端内推送和端外推送是一对性质相同的概念,这里的端其实指的就是我们的应用app本身

    • 端内推送,意味是我们应用自己构建了与自己服务器的长连接,这个长连接有很大程度上依赖于我们应用进程本身,譬如我们kdzl使用的PB模式的通道,就是建立在底层自己实现了的一个TCP连接上,时刻保持着与我们自己的服务器的连接状态,接收相关信息
    • 端外推送,往往意味着独立于应用实现了的推送服务,这个服务不依赖于我们自身,可以是google android提供的GCM,也可以是公司自己开发的一套推送机制,但就国内而言往往是有其他的公司开发的SDK,我们直接集成就可以,也
  • 第三方推送则是一个独立的概念,主要描述了推送的一种实现方式,主要涉及推送整个流程中是否涉及第三方的服务器

好了,我们结合实际的kdzl分析下:

  • 端内推送 = 我们自己的实现了的PB格式的信息长连接,主要涉及我们自己的业务逻辑,,,譬如用户A给用户B发了一条聊天信息,或者A处理了B的某个流程,都需要端内推送告知用户B状态改变了
  • 端外推送 = 第三方推送(百度推送、华为推送、小米推送),只实现 位于通知栏的状态提醒,不牵扯业务逻辑

现在可以看出来,kdzl的推送分为了两种,而且基本是相互独立的,这点大家要先明白

什么是第三方推送

“第三方推送”向开发者提供的消息推送服务;通过利用云端与客户端之间建立稳定、可靠的长连接来为开发者提供向客户端应用推送实时消息服务。

为了使用第三方推送,往往需要继承对应第三方平台的相关资源文件,这些文件一般被封装为一个SDK,借助SDK,应用的开发者可以通过少量的代码,就可以将推送服务接入的APP应用中,同时可选择使用(1)自己搭建服务器使用对应第三方平台服务API 或者(2)直接使用第三方平台服务控制台的方式进行通知信息的发送。

为了实现推送服务,实质上需要以下4个模块:

  • App应用(App Client)
    自己开发的应用,需要接入push,只需要和pushService打交道提出请求即可

  • pushService(Push Client)
    运行在手机上的推送服务,直接代理App应用与“第三方推送服务器”打交道
    用于与服务器建立稳定push通道,上报标签、 LBS信息,通知推送(含富媒体)等
    集成SDK后,一般由SDK维护

  • 第三方推送服务器(推送控制台,Push Server)
    pushService监听的服务器,该服务器用于发送通知或者信息,同时也会处理设置标签、用户记录等操作

  • 自己的业务服务器(App Server)
    实现自己的业务功能,往往需要接入“第三方推送服务器”所设定的一些API,从而可以自动的发送通知,而不再需要人工登录“推送控制台”进行信息推送

典型应用交互流程

参数说明

  • TMID
    用户标识唯一标识,一部用户终端。
    此标识在应用通过开放接口注册到PUSH平台时会获得,需要应用客户端将此标识传递给应用服务端
    在不同的平台有不同的叫法:小米regid,百度channeid+userid,华为token

流程简要

注册流程

  1. 请求TMID—-注册请求,委托推送服务去开启推送服务
    一般在app启动(activity或者application的onCreate等函数中,不确定,不同平台有不同设定)时,通过调用对应的SDK方法,请求PushService,为当前设备注册并开启推送服务

  2. 请求分配TMID—-接收到应用请求,向“第三方服务器”发起注册请求
    该方法一般由SDK默认实现和控制,应用开发者只需要在步骤1中调用对应的接口方法后,pushservice会向服务器提出申请
    该申请一般是异步申请

  3. TMID应答
    该pushService一直运行在手机中,该service在接收到“第三方服务器”给出的应答后,会发送广播,通知对应的接受者,并转发信息
    该方法一般由SDK默认实现和控制,

  4. TMID响应
    App应用往往需要继承SDK提供“receiver接收器”,并进行注册。
    pushService发出的广播,会被所继承的“接收器”中的对应方法接收,并调用

  5. 上报TMID
    App应用获取到“第三方推送服务器”分配给自己的TMID时,需要将TMID上传给“自己的业务服务器”,从而可以长久保存该ID,并且告知业务服务器通过该TMID,可向对应的业务用户发送通知。
    譬如,1:1的聊天信息,需要做定向推送,A发送给B的信息,需要得知B的TMID码
    再譬如,非定向信息,覆盖全部用户的热定新闻通知,不需要TMID码,全部推送即可。然而实际上,虽然“业务服务器”没有给出TMID码,其实是第三方服务器对“所有该App的TMID码”进行了推送。实质上和上个例子一样

推送流程

我们以“1:1的聊天信息”为例,A发送给B信息:

  1. 根据TMID推送信息
    业务服务器调用“第三方平台”给出的对应API方法,向“推送服务器”发出推送信息的申请,定向推送需要给出B用户的TMID码

  2. 根据TMID找到手机并下发
    第三方的推送服务器会通过TMID码找到对应的手机,并定向发出推送信息

  3. PushService转发信息
    该service一直运行在手机中,监听“ 第三方的推送服务器”的推送,获取到推送信息, 会发送广播,通知对应的接受者,并转发信息

  4. 信息响应
    App应用往往需要继承SDK提供“receiver接收器”,并进行注册。
    pushService发出的广播,会被所继承的“接收器”中的对应方法接收,并调用。
    可以在该方法中实现自己的业务操作。

事件流程

App应用中设定标签,设定别名等操作的过程,与注册流程基本一致

自拟的平台优先级 百度>小米>华为

为什么百度排第一呢,后台和客服反映说百度推送一堆问题,为什么还是采用百度第一呢? 原因两点:

  1. 百度推送的注册流程成功率高
  2. 百度推送的相互启动概率高,,,也就是说pushService能保持长久存活

非典型交互流程

应用死掉

一直想找个机会,好好的分析下,这些很浅显的问题:

  • 什么叫Deaded?
    • 整个进程组被手动或第三方管理软件kill 了,这是死掉了么?(Yes)
    • 整个应用没有一个Activity在Task栈中,甚至没有Task栈,但是却有后台service在运行,这个应用是Deaded 么?(No)
    • 整个应用没有一个Service在启动,没有Task栈,但是有Receiver正在活动期间,那么这个应用是Deaded 么?(No)

如果,我们非要从一个外在形式上来评判一个应用是Alive还是Deaded,那么我们可以使用当前进程的Application是否存在作为评判,那么唤醒一个应用其实就是意味着做了初始化Application的行为:

  • 什么叫唤醒Alive一个应用?
    • 启动Application下的任意一个Activity,会导致Application的初始化;
    • 启动Application下的任意一个Service,会导致Application的初始化;
    • 启动Application下的任意一个Receiver,会导致Application的初始化;
    • 看上去四大组件都会导致Application的初始化;

事实上,我们经常说“有些应用会后台自启动”,“后台偷跑流量”,这里所谓的自启动,其实并没有启动任何一个Activity,也就是根本没有构建Task,而只是启动了某个Service或者Receiver,从而势必引发至少一个进程和对应Applicaiton,我们视作Alive状态

好了,现在我们得知Application可以作为应用是唤醒状态Alive 或者 死亡deaded状态 的标准了:

  1. 如果主进程的Application存在,那么我们就认为app是Alive,否则app是deaded
  2. 如果当前进程Application存在(针对Service或Receive可能跨进程),那么当前进程是Alive,和主进程app的存活无关系

那么,应用被唤醒了,就意味着 应用可能维持的通信长连接已经建立了么?

  • 唤醒一个应用,只意味着启动某个service或者receiver,和调用 Application.OnCreate函数里的操作
    • 如果你的长连接通道的建立是在以上模块中构建的,那么长连接会被建立
    • 如果不是,那么就不会被建立。譬如,你是在启动页Activity中建立长连接,并把相关信息存储到application,那么你用启动service方式,就不会导致长连接的建立

相信看到这里你基本也清楚了,应用被唤醒 与 应用具体的业务逻辑没有半毛钱关系(长连接的建立也属于业务逻辑分部),如果你想实现某个业务部分,那就必须在被唤醒的模块中 调用或者初始化

设置中的“允许 应用 自启动”对于推送到底是影响了什么?

如何唤醒被杀死的android app

上篇文章里其实也有提及,唤醒应用的方式

  1. 广播,而且是静态注册的广播
  2. 服务,启动一个service

在本处,我们主要关注下,广播这一块。我们知道,第三方推送SDK维护的PushService其实往往是运行在一个单独的进程中的(但是很大可能和app主进程同组,这点注意下,一会会提及) ,这个进程和我们应用app进程是分割开的

我们注册推送SDK的时候,所有的官方文档都会让我静态一个Receiver类,作为监听器。回顾下上文提到的“推送流程 3-4”,PushService维持一个长连接,如果收到了来自PushServer的信息,则跨进程的发送广播给我们的应用,试图唤醒我们的的应用

第三方PushService唤醒App Receiver的方式

我们可以大胆猜测,这种inten方式应该如《如何唤醒被杀死的android app》一文中所讲:

我们一般发广播都是局限在app内部,所以通常都是这么发的:

Intent intent = new Intent();
intent.setAction("my.broadcast.test");
sendBroadcast(intent);

或者这么发:

Intent intent = new Intent(context, TestBroadcastReceiver.class);
sendBroadcast(intent);

静态的系统广播,例如:开机广播,用户开屏广播,USB插入和拔出广播等,在app运行期间可以用静态注册的接收器正常接收,但是在app被杀死后就无法收到了,Android系统做了屏蔽,把被杀死的app的系统静态广播都过滤了,所以想让app被杀死后仍然通过静态注册的接收器接收系统广播是做不到的

静态注册的自定义广播也会遇到类似问题,尤其是在定制版的系统中

采用下面这种方式发送广播即使app被杀死后,静态广播也能正常收到:

Intent intent = new Intent();
            Context c = null;
            try {
                c = createPackageContext("com.example.broadcasttest", Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
//            intent.setPackage(getPackageName());
//            intent.setComponent(pkgName, className);
//            intent.setComponent(pkgNameContext, className);
            intent.setClassName(c, "com.example.broadcasttest.TestBroadcastReceiver");
//            intent.setClassName("com.example.broadcasttest", "com.example.broadcasttest.TestBroadcastReceiver");
            intent.setAction("my.broadcast.test");
            intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
            sendBroadcast(intent);

接收放广播的配置(app内的自定义推送Receiver)要把exported设置成true,否则就无法收到app以外的广播发送,只能收到app内部的广播发送

广播唤醒的缺陷

正如文中所说:

以上通过广播唤醒在一些手机上可以正常唤醒app,例如小米3;但是在魅族手机上就没办法唤醒了,需要到安全中心把app的自启动权限开启后才能正常唤醒,由此可见,一些手机厂商可能对于静态广播的接收做了一些优化导致静态广播还是没办法被接收,所以会唤醒失败

即便 intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)

相信到这里大家也有所明悟了,为什么推送有时候收不到,我们让客户开启自启动权限,就可以收到了,原因如下:

  • App的自启动权限,会限制 PushService的自启动权限;

    • App被kill的时候,PushService作为同组进程,会被同时kill了,如果自启动被限制,则PushService都无法重启,从而导致 整个“推送流程”在环节3就被停止,app自然无法收到推送
  • App的自启动权限,会影响自身被唤醒的限制,也就是receiver的正常接收

    • App被kill了,如果自启动被限制,则其静态注册的Receiver可能被系统屏蔽掉,以防止其自动唤醒,从而导致在 “推送流程”在环节4上被停止

这也是为什么有时开启app的自启动权限,就能导致第三方推送恢复正常的原因了。 至于app被唤醒后,触发通知栏,但是通知栏信息未显示的原因,我们在后续文章中会讲解。

推送的“信息”

信息推送是一个动词,我们上边主要关注了“推送”这个动作的实现方式,我们知道了实现这个动作所需要的 四大天王,缺一不可

那么作为这个动作的受体,到底是什么呢?

我们可以简单地认为是一串文本信息,譬如一句话: “你好”

到这里,我们回归下最开始的意图,我们使用第三方推送,是期望能在手机的通知栏弹出一栏信息,根据 执行弹出动作的主体可以分为两种类型:

  1. 通知类型 弹出通知栏的动作由PushService完成,由服务端直接拟定
  2. 透传信息类型 弹出通知栏的动作由应用自身完成,先解析数据,再弹窗

相对而言,透传信息的自由度更高,我们可以自行处理收到信息后的状态,譬如弹窗,开启引用,或者不弹窗

我们现在在百度和华为平台上使用了透传信息,而小米则使用了通知

为什么还要使用通知呢?

其实这和我们之前说的“非典型交互流程”有关

我们知道, pushservice 在收到信息后,会发送广播,试图唤醒我们的应用,然后将信息传递过去

那么唤醒不成功呢? 自然无法将信息传递过去,应用本身不知道信息,处于dead状态,自然就不会弹窗提醒了

然而通知类型则不需要唤醒了,因为弹窗动作直接由pushservice完成啦,管你app是死是活,都能弹出来提示

而在小米手机上,pushservice是一种系统支持的服务,你杀都杀不死,所以我们在一般在小米手机上使用通知方式

那通知有这个好处,为什么我们在三个平台上,都使用通知呢?

很简单呀,一旦使用通知,相当于把全部责任给 pushservice, 如果pushservice越坚挺,我们就都使用通知

然而实际上,只有小米和华为这种手机厂商自拟的pushservice,在自己手机上 pushservice 才有这么牛逼

因为,是小米手机我们就用小米推送

华为为什么不用通知?

华为的透传信息也是系统级别的,能保持 pushservice 坚挺就足够了,,,我们还是期望多些自由度

透传或通知到了,就一定会弹窗么?

肯定不是了,弹窗只是一个动作,很有可能被“通知中心”之类的限制,你弹,它限制,你弹,它限制,自然出不来了

你可能感兴趣的:(android,百度,推送,华为,小米)