OnePsuh集成小米推送使用及源码解读

最近有要做推送的需求,接到这个需求时其实一脸懵逼,不是不知道怎么下手,而是深知Android平台在国内搞推送,真的是很烦,很恶心。
小米、华为、Flyme、极光、友盟、个推、信鸽等等,每一个都有其优势,也有其不足。
如果你只选择接一个,例如小米,那么在华为等手机上进程被杀的情况下是没法接收到推送的。
还有很坑爹的一点,Oppo和Vivo手机,进程被杀情况下以上第三方貌似都没法收到推送,除非加入白名单,或者利用友盟等平台的兄弟app相互唤醒(讲道理,这个是很恶心的东西,但又是很取巧的办法,有时候程序猿就是进退两难,不想做辣鸡应用,但又不得不做辣鸡应用)。

想起很久之前在知乎看到的一张讲IOS推送和Android推送区别的图:

(图片版权说明:因为是很久之前看见保存下来的图,找不到原图出处的知乎答案链接,如果作者看到要求加上版权声明或者要求我删除图片请联系我,谢谢!)

使用

这里以使用OnePush集成小米推送为例,其它平台使用类似。

OnePush依赖

如果只是使用mi-push是不需要要在项目project的build.gradle添加Maven源的,只需要在工程module的build.gradle文件添加OnePush核心模块和OnePush小米推送模块依赖(以写这篇文章时使用的1.2.1版本为准):

1
2
compile 'com.peng.library:one-push-core:1.2.1'
compile 'com.peng.library:one-push-xiaomi:1.2.1'

AppId和AppKey设置

小米推送Android ADK需要使用AppID和AppKey,OnePush作为一个集成,自然需要使用这两个信息。在“小米开放平台——推送运营平台”可以找到这两个信息,如下图:

在获取这两个信息后,填入主应用包名的AndroidManifist.xml文件中:

1
2
3
4
5
6
7
<meta-data
android:name="MI_PUSH_APP_ID"
android:value="\ 2882303761517577233"/>

<meta-data
android:name="MI_PUSH_APP_KEY"
android:value="\ 5701757717233"/>

需要注意的时这里对小米的AppId和AppKey设置需要添加”\ “,这个的原因后面在解读源码中会揭露。

添加推送实现类

然后还要在AndroidManifest.xml的application标签下,添加小米推送实现类:

1
2
3
<meta-data
android:name="OnePush_XiaoMi_101"
android:value="com.peng.one.push.xiaomi.XiaomiPushClient"/>

上面的小米实现类的value是位于one-push-xiaomi:1.2.1模块依赖的类完整路径,如果看到这你第一个想到的关键字是反射,那么恭喜你大概知道思路了,具体后面源码解读中再来看具体实现。

继承BaseOnePushReceiver实现

自定义一个广播接收器,继承BaseOnePushReceiver,实现所有抽象方法,下面是一个最简单实现示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import android.content.Context;
import android.util.Log;
import com.peng.one.push.entity.OnePushCommand;
import com.peng.one.push.entity.OnePushMsg;
import com.peng.one.push.receiver.BaseOnePushReceiver;

public class pushRecv extends BaseOnePushReceiver {
public static final String TAG = "pushRecv";
@Override
public void onReceiveNotificationClick(Context context, OnePushMsg msg) {
Log.d(TAG,"onReceiveNotificationClick"+msg.toString());
}

@Override
public void onReceiveMessage(Context context, OnePushMsg msg) {
Log.d(TAG,"onReceiveMessage"+msg.toString());
}

@Override
public void onCommandResult(Context context, OnePushCommand command) {
Log.d(TAG,"onCommandResult"+command.toString());
}
}

然后再在AndroidManifest.xml中注册这个自定义的广播接收器:

1
2
3
4
5
6
7
8
<receiver android:name=".pushRecv">
<intent-filter>
<action android:name="com.peng.one.push.ACTION_RECEIVE_NOTIFICATION" />
<action android:name="com.peng.one.push.ACTION_RECEIVE_NOTIFICATION_CLICK" />
<action android:name="com.peng.one.push.ACTION_RECEIVE_MESSAGE" />
<action android:name="com.peng.one.push.ACTION_RECEIVE_COMMAND_RESULT" />
</intent-filter>
</receiver>

初始化OnePush

在Application中初始化OnePush(注意:这里因为只用了小米推送,所以直接在判断平台时返回一个选项):

1
2
3
4
5
6
7
8
9
if (BuildConfig.APPLICATION_ID.equals(processName)) {
OnePush.init(this, new OnOnePushRegisterListener() {
@Override
public boolean onRegisterPush(int platformCode, String platformName) {
return platformCode == 101;
}
});
OnePush.register();
}

可能直接看上面那段代码会对processName这个参数产生疑惑,这是当前进程名称,可以封装为一个ProcessUtil工具类,然后写一个静态方法,需要时就根据以下方法取得:

1
2
3
4
5
6
7
8
9
10
11
12
13
public static String getProcessName(Context context, int pid) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> runningsList = am.getRunningAppProcesses();
if (runningsList == null) {
return null;
}
for (int i = 0; i < runningsList.size(); i++) {
if (runningsList.get(i).pid == pid) {
return runningsList.get(i).processName;
}
}
return null;
}

推送测试

在完成以上快速集成步骤之后,可以在小米推送运营平台上推送一条测试消息看看到达情况。

推送平台配置推送的工具如下:

在配置完测试推送后,可以点击“完成”发送一条测试的推送消息到App上,正常来说App会秒到,当然碰上拥塞时需要排队,消息到达可能会有延迟的情况。

消息到达:

服务端对接小米推送

虽然小米推送提供了一个推送消息配置后台,但正常情况下,一个App接入推送不止小米一家,就算只接入小米推送,在小米提供的推送运营平台上的工具上进行用户消息推送运营也是很反人类的工作,所以这就需要服务端去对接小米推送服务器。

这里不对服务端具体实现对接做讨论,只是模拟服务端调用,说明问题。

参照Mi-Push的服务端接入指南官方文档可以看到向所有设备推送消息接口为:https://api.xmpush.xiaomi.com/v3/message/all

插个嘴:正常情况下很少用到向所有设备推送,产品逻辑应该区分用户群、标签等推送。

再吐槽一句:小米推送的文档真的反人类啊!!!空格被吃掉了?或者参数加个粗不行??不说了,看下文档截图吧,以payload为例,能不踩坑就得出这个参数的我敬你是条汉子

好了吐槽完,正式开始模拟服务端调用接口进行推送。

参照文档,得出以下参数列表:

参数 类型 说明
payload String 消息的内容(需要做urlencode处理)
restricted_package_name String App的包名。V2版本支持一个包名,V3版本支持多包名(中间用逗号分割)
pass_through Integer 0 表示通知栏消息,1 表示透传消息
title String 展示在通知栏的标题
description String 展示在通知栏中的描述
notify_type Integer DEFAULT_ALL = -1;DEFAULT_SOUND = 1; // 使用默认提示音提示;DEFAULT_VIBRATE = 2; // 使用默认震动提示;DEFAULT_LIGHTS = 4; // 使用默认led灯光提示;
time_to_live long 可选项,如果用户离线,设置消息在服务器保存的时间,默认两周

在了解清楚接口和请求参数后,下面可以利用PostMan模拟以下接口调用:
这里有两个需要注意的点:

  1. header的content-type在post请求中需要设置为:application/x-www-form-urlencoded
  2. header添加Authorization参数,值为:key=你应用的AppScrect

请求参数及发起模拟请求后如果看到如下就成功了,接着的工作只需要交给后端处理对接问题:

接口调用成功后客户端会收到响应的推送消息:

至此使用部分介绍结束。

源码解读

知其然,亦知其所以然。
(不看过源码怎么放心使用一个开源框架哈哈哈哈哈)
这里的源码解读分成两大部分,分别是one-push-core模块和one-push-xiaomi模块。
这里按照OnePush业务流程来解读它是怎么工作的。

OnePush初始化

OnePush初始化需要在主进程中进行,前面给了一个获取当前进程名称,没仔细说明,这里解释一下:
因为一个APP很可能在跑的不只是一个进程,而无论是以“:”开头的私有进程还是全局进程,在进程初始化的时候都会调用Application的onCreate方法,如果没在onCreate中判断,那就可能回造成很多不必在所有进程初始化的单例,对象等被创建出一份毫无意义的实例,所以正常的做法是在Application中的onCreate方法中判断进程的名称然后根据需要进行不同的初始化工作。

再看一遍OnePush使用中初始化的代码:

1
2
3
4
5
6
7
8
9
if (BuildConfig.APPLICATION_ID.equals(processName)) {
OnePush.init(this, new OnOnePushRegisterListener() {
@Override
public boolean onRegisterPush(int platformCode, String platformName) {
return platformCode == 101;
}
});
OnePush.register();
}

这次我们顺着init方法一路看下去,先看看OnePush中的init方法:

1
2
3
4
5
6
7
8
/**
*Initialize One Push
* @param application
* @param listener
*/
public static void init(Application application, OnOnePushRegisterListener listener){
OnePushContext.getInstance().init(application, listener);
}

可以看到,init方法传进去2个参数,分别是Application对象和OnOnePushRegisterListener接口实现,而且OnePsuh的初始化实际上是在OnePushContext中进行的,OnePushContext是一个静态内部类实现的单例模式。

先来看看OnOnePushRegisterListener接口,里面只有一个方法,这个方法的作用是用来判断要不要初始化当前推送平台服务的:

1
2
3
4
5
6
7
8
9
10
11
12
public interface OnOnePushRegisterListener {
/**
* When you start the use of registration
*
* the code and name is you defined meta-data in the AndroidManifest.xml
* like OnePush_name_code
* @param platformCode The code of the platform
* @param platformName The name of the platform
* @return
*/
boolean onRegisterPush(int platformCode,String platformName);
}

接着,进入OnePushContext中的init方法。
一进入这个方法,下面这段代码就立马吸引了眼球:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
try {
//find all support push platform
Bundle metaData = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA).metaData;
if (metaData != null) {
Set<String> allKeys = metaData.keySet();
if (allKeys != null && !allKeys.isEmpty()) {
Iterator<String> iterator = allKeys.iterator();
while (iterator.hasNext()) {
String key = iterator.next();
if (key.startsWith(META_DATA_PUSH_HEADER)) {
mAllSupportPushPlatformMap.put(key, metaData.getString(key));
}
}
}
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}

这段代码的作用是去把AndroidManifest.xml文件中的metaData信息都取出来,存放在一个mAllSupportPushPlatformMap中,这个mAllSupportPushPlatformMap是一个LinkedHashMap,在OnePushContext中作为成员变量存在,并在类加载过程中就进行了初始化:

1
2
//all support push platform map
private LinkedHashMap<String, String> mAllSupportPushPlatformMap = new LinkedHashMap<>();

如果只用小米推送,那么这个时候打断点调试可以看到这个LinkedHashMap如下:

接着看一下接下来一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Iterator<Map.Entry<String, String>> iterator = mAllSupportPushPlatformMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> next = iterator.next();
String metaPlatformName = next.getKey();
String metaPlatformClassName = next.getValue();
StringBuilder stringBuilder = new StringBuilder(metaPlatformName).delete(0, 8);
int len = stringBuilder.length();
int lastIndexSymbol = stringBuilder.lastIndexOf(METE_DATA_SPLIT_SYMBOL);
int platformCode = Integer.parseInt(stringBuilder.substring(lastIndexSymbol + 1, len));
String platformName = stringBuilder.substring(0, lastIndexSymbol);
try {
Class<?> currentClz = Class.forName(metaPlatformClassName);
Class<?>[] interfaces = currentClz.getInterfaces();
List<Class<?>> allInterfaces = Arrays.asList(interfaces);
if (allInterfaces.contains(IPushClient.class)) {
//create object with no params
IPushClient iPushClient = (IPushClient) currentClz.newInstance();
if (listener.onRegisterPush(platformCode, platformName)) {
this.mIPushClient = iPushClient;
this.mPlatformCode = platformCode;
this.mPlatformName = platformName;
//invoke IPushClient initContext method
OneLog.i("current register platform is "+metaPlatformName);
iPushClient.initContext(application);
break;
}
} else {
throw new IllegalArgumentException(metaPlatformClassName + "is not implements " + IPushClient.class.getName());
}

} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("can not find class " + metaPlatformClassName);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}

在这段代码里面,看起来好像很复杂的样子,其实一个个看下来逻辑都是很清晰的,下面来一点点剥洋葱。

try之前那段代码是分离platformCode和platformName的作用的,但这里有一个点反应出来,那就是代码是固定模式检测你设置在metaData里的数据的,这说明了一个问题,那就是使用的骚年们,不要玩火乱来哈哈哈哈哈~

下面看看try里面的实现,回到上面的代码,metaPlatformClassName里面拿到的是value值,也就是完整的类型路径,然后通过反射的方式获取到类,再获取实现的接口,判断到如果接口包含有IPushClient的实现就会通过反射实例化一个IPushClient对象,这个时候前面说的OnOnePushRegisterListener接口的onRegisterPush就发挥作用了,这个时候就会通过这个方法的返回来决定要不要注册当前平台。


为了避免一些思路跟不上的读者理解更清晰,这里再回顾一下这儿方法在Application中的实现情况(因为是只用了小米推送,所以就只写了一句return platformCode == 101;):

1
2
3
4
5
6
new OnOnePushRegisterListener() {
@Override
public boolean onRegisterPush(int platformCode, String platformName) {
return platformCode == 101;
}
}

当然接入多个平台推送时就会灵活判断然后决定注册哪一个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
new OnOnePushRegisterListener() {
@Override
public boolean onRegisterPush(int platformCode, String platformName) {
boolean result = false;
if (RomUtils.isMiuiRom()) {
result= platformCode == 101;
} else if (RomUtils.isHuaweiRom()) {
result= platformCode == 107;
} else if(RomUtils.isFlymeRom()){
result = platformCode == 103;
} else {
result= platformCode == 104;
}
return result;
}
}

回到上面,在判断到小米平台返回true后,进入if条件,然后把当前OnePushContext中的mIPushClient、mPlatformCode和mPlatformName赋值,接着实现IPushClient实例中的initContext(application)方法。

因为IPushClient接口的具体实现在这里对应的是XiaomiPushClient,下面来看看XiaomiPushClient中的initContext(application)方法实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public void initContext(Context context) {
this.mContext = context.getApplicationContext();
//读取小米对应的appId和appSecret
try {
Bundle metaData = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA).metaData;
mAppId = metaData.getString(MI_PUSH_APP_ID);
mAppKey = metaData.getString(MI_PUSH_APP_KEY);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
OneLog.i("can't find MI_PUSH_APP_ID or MI_PUSH_APP_KEY in AndroidManifest.xml");
}
}

这就简洁明了了,就是读取我们设置在AndroidManifest.xml中的信息并赋值IPushClient实例的mAppId和mAppKey。

初始化工作基本完成了,后面的就是清空mAllSupportPushPlatformMap缓存和对没任何推送服务开启的判断。

接着我们又回头看一下在Application中初始化的流程:

1
2
3
4
5
6
7
8
9
if (BuildConfig.APPLICATION_ID.equals(processName)) {
OnePush.init(this, new OnOnePushRegisterListener() {
@Override
public boolean onRegisterPush(int platformCode, String platformName) {
return platformCode == 101;
}
});
OnePush.register();
}

在调用完OnePush中的init后接着就调用OnePush中的register方法,同样这个方法具体实现在OnePushContext:

1
2
3
4
5
6
/**
* Registered push
*/
public static void register(){
OnePushContext.getInstance().register();
}

其实看完前面的初始化过程基本就知道接下来会发生什么了,进入OnePushContext看看,就会看到实际上是调用IPushClient方法实现的:

1
2
3
public void register() {
mIPushClient.register();
}

下面看看XiaomiPushClient中的具体实现方法:

1
2
3
4
5
6
7
8
@Override
public void register() {
if (TextUtils.isEmpty(mAppId) || TextUtils.isEmpty(mAppKey)) {
throw new IllegalArgumentException("xiaomi push appId or appKey is not init," +
"check you AndroidManifest.xml is has MI_PUSH_APP_ID or MI_PUSH_APP_KEY meta-data flag please");
}
MiPushClient.registerPush(mContext, mAppId, mAppKey);
}

看到 MiPushClient.registerPush(mContext, mAppId, mAppKey);这一句是不是会心一笑~

这里其实就是注册小米推送sdk的代码了,具体可参照小米官方文档,这里就不细说了。

小米官方推送Android SDK接入文档:https://dev.mi.com/console/doc/detail?pId=41#_2_0

到这里,OnePush整合小米推送的基础工作已经初始化完成了。

另外像小米推送SDK规定的要在AndroidManifest.xml中申明的权限,注册服务等这些初始化的都在one-push-xiaomi这个模块中去完成,因为权限的android:name属性需要用到应用包名,one-push-xiaomi模块中的AndroidManifest.xml中通过读取工程module的build.gradle中的defaultConfig中的applicationId来完成:

1
2
3
4
<permission
android:name="${applicationId}.permission.MIPUSH_RECEIVE"
android:protectionLevel="signature"/>
<uses-permission android:name="${applicationId}.permission.MIPUSH_RECEIVE"/>

OnePush推送消息接收

下面来看看OnePush对推送到达的消息是怎么处理的。

接收这个环节要从小米推送SDK官方文档说起:
官方文档2.2中有说到,要接入SDK,需要自定义一个BroadcastReceiver(继承PushMessageReceiver),直接引用文档:

为了接收消息,您需要自定义一个继承自PushMessageReceiver类的BroadcastReceiver,实现其中的onReceivePassThroughMessage,onNotificationMessageClicked,onNotificationMessageArrived,onCommandResult和onReceiveRegisterResult方法,然后把该receiver注册到AndroidManifest.xml文件中。onReceivePassThroughMessage用来接收服务器发送的透传消息,onNotificationMessageClicked用来接收服务器发来的通知栏消息(用户点击通知栏时触发),onNotificationMessageArrived用来接收服务器发来的通知栏消息(消息到达客户端时触发,并且可以接收应用在前台时不弹出通知的通知消息),onCommandResult用来接收客户端向服务器发送命令消息后返回的响应,onReceiveRegisterResult用来接受客户端向服务器发送注册命令消息后返回的响应。

嗯,知道了有这么个事。
所以这会儿看回one-push-xiaomi这块的代码,里面还有个XiaomiPushReceiver广播接收器,这个是在AndroidManifest.xml中静态注册的:

1
2
3
4
5
6
7
8
9
10
11
12
13
<receiver
android:exported="true"
android:name="com.peng.one.push.xiaomi.XiaomiPushReceiver">
<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>

再看XiaomiPushReceiver,里面重写了PushMessageReceiver中的onReceivePassThroughMessage、onNotificationMessageClicked、onNotificationMessageArrived、onCommandResult和onReceiveRegisterResult五个方法,下面是这5个方法的说明:

方法 作用
onReceivePassThroughMessage 接收服务器向客户端发送的透传消息
onNotificationMessageClicked 接收服务器向客户端发送的通知消息,用户手动点击消息后触发
onNotificationMessageArrived 接收服务器向客户端发送的通知消息,在通知消息到达客户端时触发。另外应用在前台时不弹出通知的通知消息到达客户端也会触发
onCommandResult 用来接收客户端向服务器发送命令后的响应结果
onReceiveRegisterResult 用来接收客户端向服务器发送注册命令后的响应结果

当推送服务器有消息推送下来时,PushMessageReceiver中的onNotificationMessageArrived会被调用,自然就走到了XiaomiPushReceiver中的onNotificationMessageArrived方法,进到这个方法,可以看到这个方法里面代码如下:

1
OneRepeater.transmitNotification(context,message.getNotifyId(),message.getTitle(),message.getDescription(),message.getContent(), message.getExtra());

可以看到,这里会将消息传送到OneRepeater中的transmitNotification方法中处理,这个时候再进入transmitNotification方法看看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* Repeater notice
*
* @param context
* @param notifyId
* @param title
* @param content
* @param extraMsg
*/
public static void transmitNotification(Context context, int notifyId, String title
, String content, String extraMsg, Map<String, String> keyValue) {
transmit(context, OnePushAction.RECEIVE_NOTIFICATION
, new OnePushMsg(notifyId, title, content, null, extraMsg, keyValue));
}

实际上transmitNotification是一个转发消息的方法,里面把消息封装成一个Parcelable序列化的对象OnePushMsg,这个时候来看一下这个序列化对象的构造方法就会知道里面有什么了:

1
2
3
4
5
6
7
8
public OnePushMsg(int notifyId, String title, String content, String msg, String extraMsg,Map<String,String> keyValue) {
this.notifyId = notifyId;
this.title = title;
this.content = content;
this.msg = msg;
this.extraMsg = extraMsg;
this.keyValue = keyValue;
}

在OnePushMsg中,定义了一个OnePush推送消息的基本结构,相当于把小米推送、华为推送等待平台的消息转化成OnePushMsg通用消息结构来处理。

继续回头看前面提到的的transmit方法,这个方法实现如下:

1
2
3
4
5
6
7
8
9
/**
* The main method to repeater information
* @param context
* @param action
* @param data
*/
private static void transmit(Context context, String action, Parcelable data) {
TransmitDataManager.sendPushData(context, action, data);
}

OnePush定义了一个工具类来处理消息发送和解析,在TransmitDataManager中的sendPushData中,实际上是进行一个广播消息的发送:

1
2
3
Intent intent = new Intent(action);
intent.putExtra(INTENT_DATA_PUSH, data);
context.sendBroadcast(intent);

那么利用小米推送SDK收到推送消息后,转化成OnePush消息对象然后发送了个广播,接下来到哪里处理了呢?
莫方,这个时候想一下我们在前面说如何使用的环节降到的自定义广播接收器,如果忘了可以看下面,再拿出来看看:

1
2
3
4
5
6
7
8
<receiver android:name=".pushRecv">
<intent-filter>
<action android:name="com.peng.one.push.ACTION_RECEIVE_NOTIFICATION" />
<action android:name="com.peng.one.push.ACTION_RECEIVE_NOTIFICATION_CLICK" />
<action android:name="com.peng.one.push.ACTION_RECEIVE_MESSAGE" />
<action android:name="com.peng.one.push.ACTION_RECEIVE_COMMAND_RESULT" />
</intent-filter>
</receiver>

注意看 这个,实际上就是广播发送时的action: OnePushAction.RECEIVE_NOTIFICATION,我们看看这个final变量的定义就豁然开朗了:

1
String RECEIVE_NOTIFICATION = "com.peng.one.push.ACTION_RECEIVE_NOTIFICATION";

好,接着看一下我们使用时定义的pushRecv广播接收器的父类,也就是BaseOnePushReceiver,这个类实现了其中一个接口是IPushReceiver,这个接口定义了以下四个方法,分别为:

  • onReceiveNotification(Context context, OnePushMsg msg);
  • onReceiveNotificationClick(Context context, OnePushMsg msg);
  • onReceiveMessage(Context context, OnePushMsg msg);
  • onCommandResult(Context context, OnePushCommand command);

这四个方法实际上是没有实现的,是要在使用时定义的pushRecv中来实现的,我们看看BaseOnePushReceiver中是怎么处理这四个方法的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
public final void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Parcelable parcelable = TransmitDataManager.parsePushData(intent);
if (OnePushAction.RECEIVE_COMMAND_RESULT.equals(action)) {
onCommandResult(context, (OnePushCommand) parcelable);
} else if (OnePushAction.RECEIVE_NOTIFICATION.equals(action)) {
onReceiveNotification(context, (OnePushMsg) parcelable);
} else if (OnePushAction.RECEIVE_NOTIFICATION_CLICK.equals(action)) {
onReceiveNotificationClick(context, (OnePushMsg) parcelable);
} else if (OnePushAction.RECEIVE_MESSAGE.equals(action)) {
onReceiveMessage(context, (OnePushMsg) parcelable);
}
OneLog.i(String.format("%s--%s", action, String.valueOf(parcelable)));
}

先是把Parcelable 解析出来,然后根据action分别调用子类(pushRecv)中实现的方法,这个时候消息就会到达我们使用时静态注册的广播接收器中,我们就可以根据自己需要来做相关处理了。

上面解读了消息到达安装了客户端的手机上的处理逻辑,对于消息点击后的处理等操作,实际上思路类似,这里就不再进行一一解读。

总结一下这个流程:

  1. 小米推送服务端推送消息
  2. 客户端接收到消息,在小米推送SDK要求定义的广播接收器中接收到消息(one-push-xiaomi模块中定义)
  3. 接收到消息后转化成OnePushMsg类型通用消息结构
  4. 转发到使用OnePush框架客户端,自行处理后续步骤
文章作者: Kevin Wu
文章链接: https://kevinwu.cn/p/4d192447/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 KevinWu的博客
支付宝打赏