简介
概念
Android 的推送主要依赖客户端的 PushService 服务。PushService 是一个独立于应用程序的进程,在应用程序第一次启动时顺带创建,其后则(尽量)一直存活于后台,它主要负责维持与云推送服务器的 WebSocket 长链接。 所以,只要 PushService 存活,那么推送服务器上有任何需要下发到当前设备的消息,都会立刻推送下来;如果 PushService 被杀死,那推送通道中断,Android 设备就收不到任何推送消息(混合推送除外)。PushService 第一次启动,建立起与推送服务器的 WebSocket 长链接之后,也会一次性收到多条服务端缓存的未成功下发的历史消息
作用
用户角度
一般是指 Android 在应用的界面之外通过自动传送信息给用户显示的消息,旨在向用户提供提醒、来自他人的通信信息或您应用中的其他实时信息,帮助用户高效率地发掘有价值的信息。用户可以点按通知来打开应用,或直接从通知中执行操作。
公司角度
- 提升产品活跃度 DAU 、MAU
- 带动功能模块使用率
- 增加产品粘性
- 唤醒沉睡用户
推送方案
-
轮询(Pull)方式
原理
基于Pull方式,应用程序隔固定时间**主动**与服务器进行连接并查询是否有新的消息
缺点
- 成本大,需要自己实现与服务器之间的通信,例如消息排队等;
- 到达率不确定,考虑轮询的频率:太低可能导致消息的延迟;太高,更费客户端的资源(CPU资源、网络流量、系统电量)和服务器资源(网络带宽)
-
SMS(Push)方式
原理
基于Push方式,通过拦截SMS消息并且解析消息内容来了解服务器的意图,并获取其显示内容进行处理
优点
可实现完全的实时操作
缺点
通过短信发送,成本相对较高。因为目前来说,很难找到免费的短消息发送网关来实现这种方案,只能通过向运营商缴纳相应的短信费用,依赖于运营商,这样就会涉及到收费问题、保密问题、服务质量问题、扩展问题等等。
-
C2DM(Cloud to Device Messaging--云端推送)
原理
基于Push方式,C2DM服务负责处理诸如消息排队等事务,并向运行于目标设备上的应用程序分发这些消息。如图:
优点
C2DM提供了一个简单的、轻量级的机制,允许服务器可以通知移动应用程序直接与服务器进行通信,以便于从服务器获取应用程序更新和用户数据。
-
缺点
-
- 依赖于Google官方提供的C2DM服务器,但在国内使用Google服务需要翻墙,成本较大;
- 需要用户手机安装Google服务。但由于Android机型、系统的碎片化 & 国内环境,国内的Android系统都自动去除Google服务,假如要使用C2DM服务,这意味着用户还得去安装Google服务,成本较大。
-
XMPP协议
定义
Extensible Messageing and Presence Protocol,可扩展消息与存在协议,是基于可扩展标记语言(XML)的协议,是目前主流的四种IM协议之一
其他三种
- 即时信息和空间协议(IMPP)
- 空间和即时信息协议(PRIM)
- 即时通讯和空间平衡扩充的进程开始协议SIP(SIMPLE)
原理
XMPP中定义了三个角色,分别是客户端、服务器和网关 客户端
- 通过 TCP/IP与XMPP 服务器连接,然后在之上传输与即时通讯相关的指令(XML);
- 解析组织好的 XML 信息包;
- 理解消息数据类型。
- XMPP的核心:XML流传输协议(在网络上分片断发送XML的流协议),也是即时通讯指令的传递基础,即XMPP用TCP传的是XML流
- 与即时通讯相关的指令,在以前要么用2进制的形式发送(比如QQ),要么用纯文本指令加空格加参数加换行符的方式发送(比如MSN)。
- XMPP传输的即时通讯指令的逻辑与以往相仿,只是协议的形式变成了XML格式的纯文本。
优点
- 开源:可通过修改其源代码来适应我们的应用程序。
- 简单:XML易于解析和阅读;将复杂性从客户端转移到了服务器端
- 可拓展性强:继承了在XML环境中灵活的发展性,可进一步对协议进行扩展,实现更为完善的功能。
缺点
如果将消息从服务器上推送出去,则不管消息是否成功到达客户端手机上。
5. MQTT协议(轻量级的消息发布/订阅协议)
原理
基于Push方式,wmqtt.jar 是IBM提供的MQTT协议的实现
6. 第三方平台推送
- 手机厂商类:小米推送、华为推送。
- 第三方平台类:友盟推送、极光推送、云巴(基于MQTT)
- BAT大厂的平台推送:阿里云移动推送、腾讯信鸽推送、百度云推送、Firebase推送
- 集成请借鉴 Android推送混合开发指南 或者 第三方推送详解
优点
成本低 ,上述的推送大多数是免费的,假如自己实现则消耗过多资源(开发成本和后台管理、统计成本)- 消息到达率高 如果一个手机里有多个App使用了同一家推送服务,那么这些App将共用一条消息通道,即使你家的App推送服务被杀死了,那么只要用户打开了其他集成该推送服务的App,你家的推送就能到达用户
缺点
安全性低 ,依赖于服务商的服务器。- 服务会被杀死,由于Android系统的机制,后台推送 Service 会被各种主动的或是被动的行为给杀死,而服务一旦被杀死,意味着就接收不到推送消息
7. 自己搭建推送服务平台
优点
满足具备较高的推送功能和性能,并且安全性高
缺点
开发成本和后台管理、统计成本都非常高
海外Push推送通道类型
一、FCM通道(由 Google 提供的推送服务) 即Firebase 云消息传递,是由Google 提供的推送服务。由于海外手机大都具有google服务,所以fcm通道是一个优先选择的通道,可以提升整个push推送的到达率。 fcm通道发送到用户手机上主要有两种方式,一种是通知,一种是透传。
通知
特点是发给用户通过手机系统发到用户设备上,不会拉起app进程,app进程不在一般也能收到,所以push消息的到达率较高,但是通知不能自定义样式,只能使用系统的默认的样式。
透传
特点是发送时fcm通道拉起app Push进程,然后将对应的消息透传给客户端,客户端根据对应的消息类型进行展示,透传的好处是客户端完全可以自定义push的样式,增强push的点击率
二、厂商通道 厂商通道主要是包括小米、华为、oppo等手机厂商通道,手机终端厂商推出的推送服务,通过接入厂商SDK,内部服务端可以将消息推送到手机系统的服务端,再下发至客户端内部的厂商SDK,由操作系统进行相应展示,点击后唤起相应APP,这样可以避免APP进程被杀死后消息无法触达用户。但是在海外手机厂商通道没有国内做的完善,一般稳定性不是很高,到达率相对较低,且目前手机厂商通道的消息只能走系统通知,不能走透传自定义push样式,另外海外华为push通道没有回执数据,导致无法统计整个链路完整的数据。但是厂商通道在海外是对fcm通道的一个补充,当fcm通道不稳定和消息丢失后,或者部分手机没有google服务即没有fcm通道时,可以采取厂商通道进行补充发送,提升整体的push到达率.
三、长连接通道 是建立用户设备与服务端的一条链路,可以进行消息数据推送,通过长连接也可以进行APP状态监控,所以长链接推送一定要保证app长连接没有断开,即app进程活着。
优点
长连接推送的好处是app消息的到达率较高,一般可以达到95%以上
缺点
坏处是长连接断掉,整个通道都不可用,所以需要业务团队需要投入大量的研发资源去避免app的长连接进程不被操作系统杀死,进行app进程的保活.
设计技术方案
I. 设置通道的优先级
push在推送过程中选择推送通道的顺序一般是长连接>FCM通道>手机厂商通道,整个原则是有长连接通道优先走长连接通道,当长连接通道断开时,走fcm通道,没有fcm通道再走厂商通道。需要注意的是小米和华为手机在海外一般厂商token和fcm token都有,即两个通道都可以发送,所以当这些厂商走fcm通道失败后,需要在走一遍厂商token,以保证都有发送,提升整体push的到达率
ii. 设置消息的优先级
- 普通优先级。 这是数据消息的默认优先级。应用在前台运行时,普通优先级消息会被立即传递。当设备处于低电耗模式时,此类消息可能会被延迟传递以节省电量。
- 高优先级。FCM 会立即尝试传递高优先级消息,允许 FCM 服务在必要时唤醒休眠设备并运行一些有限的处理。高优先级消息通常应该会使得用户与应用或其通知进行互动。如果 FCM 检测到未引发此行为,系统可能会降低您的消息的优先级。
Iii. 保活
主动保活
如系统或第三方的静态广播、Service拉起机制,JobSchedule、Android账号同步机制,Native保活,这类措施的缺点在于,很多国产手机阉割了这些功能,或者起进程时机不可控,或者受Android版本限制;在上述方法中,Native进程保活起进程时机可控,不耗电,占用额外内存少,且保活率高。
被动保活
将Activity、Service设置为前台进程,这类措施的缺点在于,他们只能降低被系统杀的风险,无法对抗用户主动杀进程的情况;
推送策略
- 合适的时间。防止频繁发送对用户形成打扰
- 合适的方式。例:富文本展示让消息更吸睛
- 合适的内容。选中高点击率的文案
- 合适的人群。消息分组,精细触达目标人群
可借鉴 如何构建APP消息通知策略
创建通知
依赖库
在build.gradle中加入依赖
dependencies {
implementation "com.android.support:support-compat:28.0.0"
}
配置AndroidManifest.xml
<!-- 基本模块(必须)START -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 基本模块 END -->
<application
android:icon="@drawable/notification"
android:theme="@android:style/Theme.Holo.Light"
android:label="@string/app_name"
android:name=".MyLeanCloudApp" >
<!-- 即时通讯和推送 START -->
<!-- 即时通讯和推送都需要 PushService -->
<service android:name="cn.leancloud.push.PushService"/>
<receiver android:name="cn.leancloud.push.LCBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.USER_PRESENT"/>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<!-- 即时通讯和推送 END -->
<!-- 用户反馈 START -->
<activity
android:name="cn.leancloud.feedback.ThreadActivity" >
</activity>
<!-- 用户反馈 END -->
创建基本通知内容
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle(textTitle)
.setContentText(textContent)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
其他推送样式创建请参考android官方文档 android通知
注意点
版本不兼容
在确保推送逻辑无误下,存在有不同android版本不兼容的情况下,需要检查build.gradle里的targetSdkVersion、compileSdkVersion、minSdkVersion是否已经适配该android版本
- targetSdkVersion:目标版本,作用是兼容旧版本
- compileSdkVersion:sdk编译版本
- minSdkVersion:指定app运行的最低设备sdk版本