一個輕量級、可插拔的Android消息推送框架。一鍵集成推送(極光推送、友盟推送、華爲、小米推送等),提供有效的保活機制,支持推送的拓展,充分解耦推送和業務邏輯,解放你的雙手!java
在提issue前,請先閱讀【提問的智慧】,並嚴格按照issue模板進行填寫,節約你們的時間。android
在使用前,請必定要仔細閱讀使用說明文檔,重要的事情說三遍!!!git
在使用前,請必定要仔細閱讀使用說明文檔,重要的事情說三遍!!!github
在使用前,請必定要仔細閱讀使用說明文檔,重要的事情說三遍!!!apache
集成方便。只需幾行代碼便可實現推送的集成,目前已經提供極光、友盟等推送渠道,除此以外還能夠根據本身的須要進行擴展。json
兼容性強。目前已完美支持Android 9.0。api
功能強大。支持推送相關的註冊、註銷,標籤的增長、刪除、獲取,別名的綁定、解綁、獲取,推送的鏈接狀態獲取等操做,並能返回響應的結果;支持接收推送通知、通知的點擊事件、自定義消息等推送類型。bash
統一的消息訂閱。框架提供了統一的消息訂閱渠道,不管你使用了何種推送方式,均可以在任何地方進行推送消息的訂閱和取消訂閱,方便消息的接收和處理。服務器
支持增長消息過濾器。相似OkHttp中的攔截器,能夠對接收的消息進行全局過濾,過濾出那些咱們真正須要的推送消息。app
提供有效的保活機制。保證接入XPush的應用消息推送的到達率和穩定性,這也是不少推送框架所作不到的。
本框架借鑑了OnePush(目前已不維護了)中的部分思想,加之我3年消息推送的經驗,造成了以下幾個部分:
消息推送客戶端IPushClient
:主要提供消息推送平臺的主要API。
消息推送事件轉發器IPushDispatcher
:主要用於將第三方的消息推送事件轉發爲XPush可識別的事件。
消息推送接收器IPushReceiver
:統一接收IPushDispatcher轉發過來的事件,是事件的接收中心。
推送消息的被觀察者IMessageObservable
:主要負責管理推送消息的訂閱和轉發。
推送消息的過濾策略IMessageFilterStrategy
:主要負責推送消息的過濾處理和管理。
以上5個組成部分能夠根據你自身的業務需求進行自定義。
在後臺發出一則推送消息後:
第三方推送平臺 --- (消息) ---> 第三方推送平臺內部的接收消息的Receiver --->(重寫其接收的方法)---> IPushDispatcher ---> (轉發消息內容爲XPushMsg/XPushCommand)---> IPushReceiver ---> (如不使用XPushManager提供的消息管理,這裏直接結束)
【使用XPushManager提供的消息管理】:---IPushReceiver---> XPushManager -----> IMessageFilterStrategy --->(對消息進行過濾處理)---> IMessageObservable ---> (消息轉發到具體訂閱的地方)
複製代碼
作過Android消息推送的人都知道,Android不只設備碎片化嚴重,推送平臺也是五花八門的。早在2017年工信部就號召全部的廠商來制定統一的Android消息推送平臺,可到如今也沒有下文(究其緣由仍是這其中的利益太大了,誰也不想妥協)。
但是咱們也不能將但願全都寄託在這個徹底沒有定數的事件上,代碼終歸要寫,功能終歸要上,與其受制於人,不如本身革命,搞一個本身能控制的消息推送全平臺解決方案來得靠譜。
可能有人又會說,如今友盟和信鴿都支持廠商推送的集成,爲什麼你本身還要搞一套呢?若是你對推送的及時性和到達率都沒什麼要求的話,其實也是無所謂的(實踐證實,並很差用)。在這裏我須要說明的是,你不可能把本身的命運交到別人的手裏,推送有別於其餘的業務,相對來講比較複雜,須要處理大批量的事件消息,對服務器的要求比較大,你願意把你的推送消息交給第三方推送平臺去處理?再說了,你能強制大家後臺接入指定第三方的推送平臺?若是都不能,與其受制於人,何不把這些命運把握在本身的手上,那麼寫出來的功能本身也安心啊。
以前在QQ交流羣裏一直有人但願我開源一個消息推送框架,其實我在上一家公司的時候就寫了一個推送框架,只不過捆綁業務太深,加之避開泄密之嫌,也就沒有開源的必要。這次的推送框架徹底是從新寫了一個,加之全新的設計,會使框架更加通用,靈活。
1.先在項目根目錄的 build.gradle 的 repositories 添加:
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
複製代碼
2.添加XPush主要依賴:
dependencies {
...
//推送核心庫
implementation 'com.github.xuexiangjys.XPush:xpush-core:1.0.0'
//推送保活庫
implementation 'com.github.xuexiangjys.XPush:keeplive:1.0.0'
}
複製代碼
3.添加第三方推送依賴(根據本身的需求進行添加,固然也能夠所有添加)
dependencies {
...
//選擇你想要集成的推送庫
implementation 'com.github.xuexiangjys.XPush:xpush-jpush:1.0.0'
implementation 'com.github.xuexiangjys.XPush:xpush-umeng:1.0.0'
implementation 'com.github.xuexiangjys.XPush:xpush-huawei:1.0.0'
implementation 'com.github.xuexiangjys.XPush:xpush-xiaomi:1.0.0'
}
複製代碼
1.註冊消息推送接收器。方法有兩種,選其中一種就好了。
若是你想使用XPushManager
提供的消息管理,直接在AndroidManifest.xml中註冊框架默認提供的XPushReceiver
。固然你也能夠繼承XPushReceiver
,並重寫相關方法。
若是你想實現本身的消息管理,可繼承AbstractPushReceiver
類,重寫裏面的方法,並在AndroidManifest.xml中註冊。
<!--自定義消息推送接收器-->
<receiver android:name=".push.CustomPushReceiver">
<intent-filter>
<action android:name="com.xuexiang.xpush.core.action.RECEIVE_CONNECT_STATUS_CHANGED" />
<action android:name="com.xuexiang.xpush.core.action.RECEIVE_NOTIFICATION" />
<action android:name="com.xuexiang.xpush.core.action.RECEIVE_NOTIFICATION_CLICK" />
<action android:name="com.xuexiang.xpush.core.action.RECEIVE_MESSAGE" />
<action android:name="com.xuexiang.xpush.core.action.RECEIVE_COMMAND_RESULT" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
<!--默認的消息推送接收器-->
<receiver android:name="com.xuexiang.xpush.core.receiver.impl.XPushReceiver">
<intent-filter>
<action android:name="com.xuexiang.xpush.core.action.RECEIVE_CONNECT_STATUS_CHANGED" />
<action android:name="com.xuexiang.xpush.core.action.RECEIVE_NOTIFICATION" />
<action android:name="com.xuexiang.xpush.core.action.RECEIVE_NOTIFICATION_CLICK" />
<action android:name="com.xuexiang.xpush.core.action.RECEIVE_MESSAGE" />
<action android:name="com.xuexiang.xpush.core.action.RECEIVE_COMMAND_RESULT" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
複製代碼
注意,若是你的Android設備是8.0及以上的話,靜態註冊的廣播是沒法正常生效的,解決的方法有兩種:
動態註冊消息推送接收器
修改推送消息的發射器
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//Android8.0靜態廣播註冊失敗解決方案一:動態註冊
XPush.registerPushReceiver(new CustomPushReceiver());
//Android8.0靜態廣播註冊失敗解決方案二:修改發射器
XPush.setIPushDispatcher(new Android26PushDispatcherImpl(CustomPushReceiver.class));
}
複製代碼
2.在AndroidManifest.xml的application標籤下,添加第三方推送客戶端實現類.
須要注意的是,這裏註冊的PlatformName
和PlatformCode
必需要和推送客戶端實現類中的一一對應才行。
<!--name格式:XPush_[PlatformName]_[PlatformCode]-->
<!--value格式:對應客戶端實體類的全類名路徑-->
<!--若是引入了xpush-jpush庫-->
<meta-data
android:name="XPush_JPush_1000"
android:value="com.xuexiang.xpush.jpush.JPushClient" />
<!--若是引入了xpush-umeng庫-->
<meta-data
android:name="XPush_UMengPush_1001"
android:value="com.xuexiang.xpush.umeng.UMengPushClient" />
<!--若是引入了xpush-huawei庫-->
<meta-data
android:name="XPush_HuaweiPush_1002"
android:value="com.xuexiang.xpush.huawei.HuaweiPushClient" />
<!--若是引入了xpush-xiaomi庫-->
<meta-data
android:name="XPush_MIPush_1003"
android:value="com.xuexiang.xpush.xiaomi.XiaoMiPushClient" />
複製代碼
3.添加第三方AppKey和AppSecret.
這裏的AppKey和AppSecret須要咱們到各自的推送平臺上註冊應用後得到。注意若是使用了xpush-xiaomi,那麼須要在AndroidManifest.xml添加小米的AppKey和AppSecret(注意下面的「\ 」必須加上,不然獲取到的是float而不是String,就會致使id和key獲取不到正確的數據)。
<!--極光推送靜態註冊-->
<meta-data
android:name="JPUSH_CHANNEL"
android:value="default_developer" />
<meta-data
android:name="JPUSH_APPKEY"
android:value="a32109db64ebe04e2430bb01" />
<!--友盟推送靜態註冊-->
<meta-data
android:name="UMENG_APPKEY"
android:value="5d5a42ce570df37e850002e9" />
<meta-data
android:name="UMENG_MESSAGE_SECRET"
android:value="4783a04255ed93ff675aca69312546f4" />
<!--華爲HMS推送靜態註冊-->
<meta-data
android:name="com.huawei.hms.client.appid"
android:value="101049475"/>
<!--小米推送靜態註冊,下面的「\ 」必須加上,不然將沒法正確讀取-->
<meta-data
android:name="MIPUSH_APPID"
android:value="\ 2882303761518134164"/>
<meta-data
android:name="MIPUSH_APPKEY"
android:value="\ 5371813415164"/>
複製代碼
4.在Application中初始化XPush
初始化XPush的方式有兩種,根據業務須要選擇一種方式就好了:
/**
* 靜態註冊初始化推送
*/
private void initPush() {
XPush.debug(BuildConfig.DEBUG);
//靜態註冊,指定使用友盟推送客戶端
XPush.init(this, new UMengPushClient());
XPush.register();
}
複製代碼
/**
* 動態註冊初始化推送
*/
private void initPush() {
XPush.debug(BuildConfig.DEBUG);
//動態註冊,根據平臺名或者平臺碼動態註冊推送客戶端
XPush.init(this, new IPushInitCallback() {
@Override
public boolean onInitPush(int platformCode, String platformName) {
String romName = RomUtils.getRom().getRomName();
if (romName.equals(SYS_EMUI)) {
return platformCode == HuaweiPushClient.HUAWEI_PUSH_PLATFORM_CODE && platformName.equals(HuaweiPushClient.HUAWEI_PUSH_PLATFORM_NAME);
} else if (romName.equals(SYS_MIUI)) {
return platformCode == XiaoMiPushClient.MIPUSH_PLATFORM_CODE && platformName.equals(XiaoMiPushClient.MIPUSH_PLATFORM_NAME);
} else {
return platformCode == JPushClient.JPUSH_PLATFORM_CODE && platformName.equals(JPushClient.JPUSH_PLATFORM_NAME);
}
}
});
XPush.register();
}
複製代碼
經過調用XPush.register()
,便可完成推送的註冊。
經過調用XPush.unRegister()
,便可完成推送的註銷。
經過調用XPush.getPushToken()
,便可獲取消息推送的Token(令牌)。
經過調用XPush.getPlatformCode()
,便可獲取當前使用推送平臺的碼。
經過調用XPush.addTags()
,便可添加標籤(支持傳入多個)。
經過調用XPush.deleteTags()
,便可刪除標籤(支持傳入多個)。
經過調用XPush.getTags()
,便可獲取當前設備全部的標籤。
須要注意的是,友盟推送目前暫不支持標籤的獲取,華爲推送不支持標籤的全部操做,小米推送每次只支持一個標籤的操做。
經過調用XPush.bindAlias()
,便可綁定別名。
經過調用XPush.unBindAlias()
,便可解綁別名。
經過調用XPush.getAlias()
,便可獲取當前設備所綁定的別名。
須要注意的是,友盟推送目前暫不支持別名的獲取,華爲推送不支持別名的全部操做。
經過調用XPushManager.get().register()
方法,註冊消息訂閱MessageSubscriber
,便可在任意地方接收到推送的消息。
經過調用XPushManager.get().unregister()
方法,便可取消消息的訂閱。
這裏須要注意的是,消息訂閱的回調並不必定是在主線程,所以在回調中若是進行了UI的操做,必定要確保切換至主線程。下面演示代碼中使用了個人另外一個開源庫XAOP,只經過@MainThread
註解就能自動切換至主線程,可供參考。
/**
* 初始化監聽
*/
@Override
protected void initListeners() {
XPushManager.get().register(mMessageSubscriber);
}
private MessageSubscriber mMessageSubscriber = new MessageSubscriber() {
@Override
public void onMessageReceived(CustomMessage message) {
showMessage(String.format("收到自定義消息:%s", message));
}
@Override
public void onNotification(Notification notification) {
showMessage(String.format("收到通知:%s", notification));
}
};
@MainThread
private void showMessage(String msg) {
tvContent.setText(msg);
}
@Override
public void onDestroyView() {
XPushManager.get().unregister(mMessageSubscriber);
super.onDestroyView();
}
複製代碼
經過調用XPushManager.get().addFilter()
方法,可增長對訂閱推送消息的過濾處理。對於一些咱們不想處理的消息,能夠經過消息過濾器將它們篩選出來。
經過調用XPushManager.get().removeFilter()
方法,便可去除消息過濾器。
/**
* 初始化監聽
*/
@Override
protected void initListeners() {
XPushManager.get().addFilter(mMessageFilter);
}
private IMessageFilter mMessageFilter = new IMessageFilter() {
@Override
public boolean filter(Notification notification) {
if (notification.getContent().contains("XPush")) {
showMessage("通知被攔截");
return true;
}
return false;
}
@Override
public boolean filter(CustomMessage message) {
if (message.getMsg().contains("XPush")) {
showMessage("自定義消息被攔截");
return true;
}
return false;
}
};
@Override
public void onDestroyView() {
XPushManager.get().removeFilter(mMessageFilter);
super.onDestroyView();
}
複製代碼
對於通知的點擊事件,咱們能夠處理得更優雅,自定義其點擊後的動做,打開咱們想讓用戶看到的頁面。
咱們能夠在全局消息推送的接收器IPushReceiver
中的onNotificationClick
回調中,增長打開指定頁面的操做。
@Override
public void onNotificationClick(Context context, XPushMsg msg) {
super.onNotificationClick(context, msg);
//打開自定義的Activity
Intent intent = IntentUtils.getIntent(context, TestActivity.class, null, true);
intent.putExtra(KEY_PARAM_STRING, msg.getContent());
intent.putExtra(KEY_PARAM_INT, msg.getId());
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
ActivityUtils.startActivity(intent);
}
複製代碼
須要注意的是,這須要你在消息推送平臺推送的通知使用的是自定義動做
或者打開指定頁面
類型,而且傳入的Intent uri 內容知足以下格式:
title:通知的標題
content:通知的內容
extraMsg:通知附帶的拓展字段,可存放json或其餘內容
keyValue:通知附帶的鍵值對
xpush://com.xuexiang.xpush/notification?title=這是一個通知&content=這是通知的內容&extraMsg=xxxxxxxxx&keyValue={"param1": "1111", "param2": "2222"}
複製代碼
固然你也能夠自定義傳入的Intent uri 格式,具體可參考項目中的XPushNotificationClickActivity和AndroidManifest.xml
推送平臺 | 平臺名 | 平臺碼 | 模塊名 | 客戶端類 |
---|---|---|---|---|
極光推送 | JPush | 1000 | xpush-jpush | com.xuexiang.xpush.jpush.JPushClient |
友盟推送 | UMengPush | 1001 | xpush-umeng | com.xuexiang.xpush.umeng.UMengPushClient |
華爲推送 | HuaweiPush | 1002 | xpush-huawei | com.xuexiang.xpush.huawei.HuaweiPushClient |
小米推送 | MIPush | 1003 | xpush-xiaomi | com.xuexiang.xpush.xiaomi.XiaoMiPushClient |
極光推送平臺全部特性都支持。
友盟推送在進行XPush初始化的時候,除了在主進程中註冊,還須要在channel中註冊。
友盟推送不支持Tag和alias的獲取
友盟推送不支持監聽推送的鏈接狀態。
華爲推送在註冊以前須要安裝最新的推送服務,不然將沒法註冊成功(庫會自動彈出升級或者安裝提示)
華爲推送不支持全部Tag和alias的操做。
華爲推送不支持接收通知到達事件。
小米推送一次只能操做一個Tag。
小米推送註銷無結果反饋。
小米推送不支持監聽推送的鏈接狀態。
因爲Android推送平臺的衆多,目前本項目不可能也不必提供全部推送平臺的集成庫。若是你想使用的推送平臺在我這沒有找到對應的集成庫的話,那麼就須要你本身寫一個了。
其實拓展一個第三方推送庫也不是很難,只要遵循如下4步驟就能夠完成了:
1.新建一個Android Library Module,而後將你準備集成的推送平臺的依賴內容導入進來。這裏包括引入推送依賴庫或SDK、配置AndroidManifest.xml
。
2.建立該推送平臺的客戶端XXXClient,實現IPushClient接口,而且重寫對應的方法。其中init
、register
、unRegister
、getPlatformCode
、getPlatformName
這5個方法是必須重寫的。
IPushClient接口方法詳細以下:
public interface IPushClient {
/**
* 初始化【必須】
*
* @param context
*/
void init(Context context);
/**
* 註冊推送【必須】
*/
void register();
/**
* 註銷推送【必須】
*/
void unRegister();
/**
* 綁定別名【別名是惟一的】
*
* @param alias 別名
*/
void bindAlias(String alias);
/**
* 解綁別名
*
* @param alias 別名
*/
void unBindAlias(String alias);
/**
* 獲取別名
*/
void getAlias();
/**
* 增長標籤
*
* @param tag 標籤
*/
void addTags(String... tag);
/**
* 刪除標籤
*
* @param tag 標籤
*/
void deleteTags(String... tag);
/**
* 獲取標籤
*/
void getTags();
/**
* @return 獲取推送令牌
*/
String getPushToken();
/**
* 注意千萬不要重複【必須】
* @return 獲取平臺碼
*/
int getPlatformCode();
/**
* 注意千萬不要重複【必須】
* @return 獲取平臺名
*/
String getPlatformName();
}
複製代碼
XPush
的transmitXXX方法,將通知、透傳消息、通知點擊事件、以及其餘事件,轉發到XPush。主要調用如下五個方法:
(1)XPush.transmitMessage(): 轉發自定義(透傳)消息.
(2)XPush.transmitNotification(): 轉發通知到達消息.
(3)XPush.transmitNotificationClick(): 轉發通知點擊事件.
(4)XPush.transmitCommandResult(): 轉發IPushClient命令執行結果.
(5)XPush.transmitConnectStatusChanged(): 轉發推送鏈接狀態發生改變的事件.
以上即完成了推送平臺的集成。剩下的就是在初始化XPush的時候對推送平臺進行選擇了.若是你看完了仍是不會的話,你能夠參考項目中的xpush-xiaomi和xpush-huawei.
推送消息轉譯實體,攜帶消息的原始數據
字段名 | 類型 | 備註 |
---|---|---|
mId | int | 消息ID / 狀態 |
mTitle | String | 通知標題 |
mContent | String | 通知內容 |
mMsg | String | 自定義(透傳)消息 |
mExtraMsg | String | 消息拓展字段 |
mKeyValue | String | 消息鍵值對 |
推送通知,由XPushMsg轉化而來
字段名 | 類型 | 備註 |
---|---|---|
mId | int | 消息ID / 狀態 |
mTitle | String | 通知標題 |
mContent | String | 通知內容 |
mExtraMsg | String | 消息拓展字段 |
mKeyValue | String | 消息鍵值對 |
自定義(透傳)消息,由XPushMsg轉化而來
字段名 | 類型 | 備註 |
---|---|---|
mMsg | String | 自定義(透傳)消息 |
mExtraMsg | String | 消息拓展字段 |
mKeyValue | String | 消息鍵值對 |
IPushClient執行相關命令的結果信息實體
字段名 | 類型 | 備註 |
---|---|---|
mType | int | 命令類型 |
mResultCode | int | 結果碼 |
mContent | String | 命令內容 |
mExtraMsg | String | 拓展字段 |
mError | String | 錯誤信息 |
命令的類型
命令名 | 命令碼 | 備註 |
---|---|---|
TYPE_REGISTER | 2000 | 註冊推送 |
TYPE_UNREGISTER | 2001 | 註銷推送 |
TYPE_ADD_TAG | 2002 | 添加標籤 |
TYPE_DEL_TAG | 2003 | 刪除標籤 |
TYPE_GET_TAG | 2004 | 獲取標籤 |
TYPE_BIND_ALIAS | 2005 | 綁定別名 |
TYPE_UNBIND_ALIAS | 2006 | 解綁別名 |
TYPE_GET_ALIAS | 2007 | 獲取別名 |
TYPE_AND_OR_DEL_TAG | 2008 | 添加或刪除標籤 |
命令的結果碼
結果名 | 結果碼 | 備註 |
---|---|---|
RESULT_OK | 0 | 成功 |
RESULT_ERROR | 1 | 失敗 |
推送鏈接狀態
狀態名 | 狀態碼 | 備註 |
---|---|---|
DISCONNECT | 10 | 已斷開 |
CONNECTING | 11 | 鏈接中 |
CONNECTED | 12 | 已鏈接 |
# XPush的混淆
-keep class * extends com.xuexiang.xpush.core.IPushClient{*;}
-keep class * extends com.xuexiang.xpush.core.receiver.IPushReceiver{*;}
# 極光推送混淆
-dontwarn cn.jpush.**
-keep class cn.jpush.** { *; }
-dontwarn cn.jiguang.**
-keep class cn.jiguang.** { *; }
-keep class * extends cn.jpush.android.service.JPushMessageReceiver{*;}
# umeng推送
-dontwarn com.umeng.**
-dontwarn com.taobao.**
-dontwarn anet.channel.**
-dontwarn anetwork.channel.**
-dontwarn org.android.**
-dontwarn org.apache.thrift.**
-dontwarn com.xiaomi.**
-dontwarn com.huawei.**
-dontwarn com.meizu.**
-keep class com.taobao.** {*;}
-keep class org.android.** {*;}
-keep class anet.channel.** {*;}
-keep class com.xiaomi.** {*;}
-keep class com.huawei.** {*;}
-keep class com.meizu.** {*;}
-keep class org.apache.thrift.** {*;}
-keep class com.alibaba.sdk.android.**{*;}
-keep class com.ut.**{*;}
-keep class com.ta.**{*;}
# 華爲推送
-keep class com.huawei.hms.**{*;}
-keep class com.huawei.android.hms.agent.**{*;}
# 小米推送
-keep class * extends com.xiaomi.mipush.sdk.PushMessageReceiver{*;}
複製代碼