本文中涉及到的全部代碼現已在Github上開源,地址: github.com/xuexiangjys…java
極光推送是國內最先作第三方消息推送平臺的公司,在消息推送界仍是相對有影響力的。我最先是在2016年接觸到極光消息推送的,那時候公司須要作消息推送業務,可是因爲以前沒作過消息推送,且自建消息推送平臺代價過高,並且穩不穩定誰也不敢打包票,因而就選擇了當時較爲有名的極光推送。android
那麼當時我爲何選擇極光推送呢?git
1.免費。免費版本的每一個 Appkey 的最高推送頻率爲 600 次/分鐘,並且沒有推送數量限制,者對於消息推送業務剛起步的企業來講,徹底夠用了。github
2.上手簡單,文檔齊全。平臺官網上的文檔很是詳細,下載下來的演示demo也很是豐富,經過簡單的幾行代碼就能夠輕鬆接入。json
3.功能豐富。比起小米推送、華爲推送、信鴿推送、友盟推送來講,極光推送的功能是最全的。想具體瞭解這幾種推送的可參見個人開源框架XPush.bash
4.社區支持度高。就拿咱們Android來講,不只支持原生集成,還支持React Native、Flutter、Weex、HBuilder、Cordova等混合開發方式。服務器
那麼極光推送真的有那麼好嗎?其實也不全是,我在使用的過程當中也發現了一些問題:網絡
1.推送的到達率差一點。只要應用退到後臺被系統回收或者被用戶殺死,基本就很難再收到推送了。這點天然比不上那些手機廠商的推送。併發
2.沒有免費開放廠商通道推送集成。想要集成廠商通道推送的話,還須要充錢成爲VIP才行。app
不過若是你是消息推送的初學者的話,我想極光推送確定是你不二的選擇。那麼下面來跟着我學習如何使用極光推送吧!
本文是基於
jpush:3.5.4
和jcore:2.2.6
版本介紹的,暫只介紹最新推薦的使用方法,那些過期的用法這裏我就很少介紹了,想了解的能夠去極光推送官方文檔查看。
在接入極光推送前,首先須要獲取到應用的AppKey,它是應用的惟一標識。
1.建立極光推送開發者賬號
要建立極光推送開發者賬號,請訪問極光推送官方網站: www.jiguang.cn/push
2.建立應用
進入極光控制檯後,點擊「建立應用」按鈕,填寫應用名稱便可建立應用成功。同時點擊「推送設置」,在 Android 版塊填上你的應用包名,選擇保存便可。
3.獲取應用的AppKey
在極光控制檯點擊"應用設置"中的"應用信息",獲取應用的AppKey。
使用 jcenter 自動集成的開發者,不須要在項目中添加 jar 和 so,jcenter 會自動完成依賴;在 AndroidManifest.xml 中不須要添加任何 JPush SDK 相關的配置,jcenter 會自動導入。
1.配置項目的build.gradle
文件
android {
defaultConfig {
applicationId "com.xxx.xxx" //JPush平臺上註冊的應用包名.
...
ndk {
//選擇要添加的對應 cpu 類型的 .so 庫。
abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a'
//,'x86', 'x86_64', 'mips', 'mips64'
}
manifestPlaceholders = [
JPUSH_PKGNAME: defaultConfig.applicationId,
JPUSH_APPKEY : "你的 Appkey ",//值來自開發者平臺取得的AppKey
JPUSH_CHANNEL: "default_developer",
]
}
}
dependencies {
...
//引入JPush依賴庫
implementation 'cn.jiguang.sdk:jpush:3.5.4'
implementation 'cn.jiguang.sdk:jcore:2.2.6'
}
複製代碼
2.配置項目的AndroidManifest.xml
文件
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xuexiang.jpush">
<application>
<!-- 1.這個是自定義Service,要繼承極光JCommonService,能夠在更多手機平臺上使得推送通道保持的更穩定 -->
<service
android:name=".PushService"
android:enabled="true"
android:exported="false"
android:process=":pushcore">
<intent-filter>
<action android:name="cn.jiguang.user.service.action" />
</intent-filter>
</service>
<!-- 2.用戶自定義接收消息器,全部你想要知道的消息都在這裏-->
<receiver android:name=".core.push.PushMessageReceiver">
<intent-filter>
<action android:name="cn.jpush.android.intent.RECEIVE_MESSAGE" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
</application>
</manifest>
複製代碼
1.首先你須要先去下載SDK,下載地址: docs.jiguang.cn/jpush/resou…
2.解壓SDK,將壓縮包下的libs內容複製到項目的libs下
3.配置項目的build.gradle
文件
android {
defaultConfig {
applicationId "com.xxx.xxx" //JPush平臺上註冊的應用包名.
...
ndk {
//選擇要添加的對應 cpu 類型的 .so 庫。
abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a'
//,'x86', 'x86_64', 'mips', 'mips64'
}
manifestPlaceholders = [
JPUSH_PKGNAME: defaultConfig.applicationId,
JPUSH_APPKEY : "你的 Appkey ",//值來自開發者平臺取得的AppKey
JPUSH_CHANNEL: "default_developer",
]
}
sourceSets {
//設置libs目錄爲so包的加載目錄
main {
jniLibs.srcDirs = ['libs']
}
}
}
複製代碼
4.配置項目的AndroidManifest.xml
文件
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.xxx.xxx">
<permission
android:name="${applicationId}.permission.JPUSH_MESSAGE"
android:protectionLevel="signature" />
<!-- Required 一些系統要求的權限,如訪問網絡等-->
<uses-permission android:name="${applicationId}.permission.JPUSH_MESSAGE" />
<uses-permission android:name="android.permission.RECEIVE_USER_PRESENT" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 用於開啓 debug 版本的應用在6.0 系統上 層疊窗口權限 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- Optional for location -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_TASKS" />
<application>
<!-- Required SDK核心功能-->
<activity
android:name="cn.jpush.android.ui.PushActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:theme="@android:style/Theme.NoTitleBar">
<intent-filter>
<action android:name="cn.jpush.android.ui.PushActivity" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="${applicationId}" />
</intent-filter>
</activity>
<!-- Required SDK 核心功能-->
<!-- 可配置android:process參數將PushService放在其餘進程中 -->
<service
android:name="cn.jpush.android.service.PushService"
android:exported="false"
android:process=":pushcore">
<intent-filter>
<action android:name="cn.jpush.android.intent.REGISTER" />
<action android:name="cn.jpush.android.intent.REPORT" />
<action android:name="cn.jpush.android.intent.PushService" />
<action android:name="cn.jpush.android.intent.PUSH_TIME" />
</intent-filter>
</service>
<!-- since 3.0.9 Required SDK 核心功能-->
<provider
android:name="cn.jpush.android.service.DataProvider"
android:authorities="${applicationId}.DataProvider"
android:exported="false" />
<!-- since 1.8.0 option 可選項。用於同一設備中不一樣應用的JPush服務相互拉起的功能。 -->
<!-- 若不啓用該功能可刪除該組件,將不拉起其餘應用也不能被其餘應用拉起 -->
<service
android:name="cn.jpush.android.service.DaemonService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="cn.jpush.android.intent.DaemonService" />
<category android:name="${applicationId}" />
</intent-filter>
</service>
<!-- since 3.1.0 Required SDK 核心功能-->
<provider
android:name="cn.jpush.android.service.DownloadProvider"
android:authorities="${applicationId}.DownloadProvider"
android:exported="true" />
<!-- Required SDK核心功能-->
<receiver
android:name="cn.jpush.android.service.PushReceiver"
android:enabled="true"
android:exported="false">
<intent-filter android:priority="1000">
<!--Required 顯示通知欄 -->
<action android:name="cn.jpush.android.intent.NOTIFICATION_RECEIVED_PROXY" />
<category android:name="${applicationId}" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.USER_PRESENT" />
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
<!-- Optional -->
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED" />
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
<!-- Required SDK核心功能-->
<receiver
android:name="cn.jpush.android.service.AlarmReceiver"
android:exported="false" />
<!--since 3.3.0 Required SDK核心功能-->
<activity
android:name="cn.jpush.android.service.JNotifyActivity"
android:exported="true"
android:taskAffinity="jpush.custom"
android:theme="@android:style/Theme.Translucent.NoTitleBar">
<intent-filter>
<action android:name="cn.jpush.android.intent.JNotifyActivity" />
<category android:name="${applicationId}" />
</intent-filter>
</activity>
<!-- *********************下面這兩個是須要你本身定義的**************************** -->
<!-- since 3.3.0 Required SDK 核心功能-->
<!-- 1.這個是自定義Service,要繼承極光JCommonService,能夠在更多手機平臺上使得推送通道保持的更穩定 -->
<service
android:name=".PushService"
android:enabled="true"
android:exported="false"
android:process=":pushcore">
<intent-filter>
<action android:name="cn.jiguang.user.service.action" />
</intent-filter>
</service>
<!-- 2.用戶自定義接收消息器,全部你想要知道的消息都在這裏-->
<receiver android:name=".core.push.PushMessageReceiver">
<intent-filter>
<action android:name="cn.jpush.android.intent.RECEIVE_MESSAGE" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
<meta-data
android:name="JPUSH_CHANNEL"
android:value="${JPUSH_CHANNEL}" />
<!-- 值來自開發者平臺取得的AppKey-->
<meta-data
android:name="JPUSH_APPKEY"
android:value="${JPUSH_APPKEY}" />
</application>
</manifest>
複製代碼
1.在Application中初始化JPush
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
initJPush();
}
}
/**
* 初始化極光推送
*/
private void initJPush() {
JPushInterface.setDebugMode(BuildConfig.DEBUG);
//只須要在應用程序啓動時調用一次該 API 便可
JPushInterface.init(this);
}
複製代碼
2.在應用的第一個頁面申請權限(可選)
因爲Android手機定製ROM太多,部分手機的通知欄權限默認是關閉的,須要用戶手動打開。若是不打開通知欄權限的話,即便你連上了推送,也沒法收到推送消息。
/**
* 申請定位、存儲和通知欄的權限
*
* @param activity
*/
public static void requestPermission(Activity activity) {
//打開通知欄的權限
if (JPushInterface.isNotificationEnabled(activity) == 0) {
new AlertDialog.Builder(activity)
.setCancelable(false)
.setMessage("通知權限未打開,是否前去打開?")
.setPositiveButton("是", (d, w) -> JPushInterface.goToAppNotificationSettings(activity))
.setNegativeButton("否", null)
.show();
}
//申請定位、存儲權限
JPushInterface.requestPermission(activity);
}
複製代碼
當完成以上步驟後,可直接運行程序,並查看logcat日誌,設置過濾條件爲"JIGUANG",若是出現"Register succeed"和"registrationId:xxxxxxxxxxxxxx"字樣,即爲集成成功!以下圖所示:
注意事項:
配置項目的proguard-rules.pro
文件。
-dontoptimize
-dontpreverify
-dontwarn cn.jpush.**
-keep class cn.jpush.** { *; }
-dontwarn cn.jiguang.**
-keep class cn.jiguang.** { *; }
-keep class cn.jiguang.** { *; }
-keep class * extends cn.jpush.android.service.JPushMessageReceiver{*;}
複製代碼
1.上面已經講過了,推送初始化建議在自定義的 Application 中的 onCreate 中調用,且推送初始化只須要調用一次便可。
JPushInterface.init(Context context);
複製代碼
2.推送初始化成功後,平臺會返回一個惟一的token令牌,那就是RegistrationID
,獲取它的方法以下:
JPushInterface.getRegistrationID(Context context);
複製代碼
3.獲取當前推送的鏈接狀態方法以下:
JPushInterface.getConnectionState(Context context)
複製代碼
1.中止推送。在某些業務中,咱們須要臨時暫停推送,例如帳戶退出登錄等,這個時候咱們能夠調用以下方法:
JPushInterface.stopPush(Context context);
複製代碼
須要注意的是,這裏的中止推送只是個本地客戶端的操做,並不會通知到推送服務平臺。其表現效果相似設備斷網,將不會收到任何推送消息,而且極光推送全部的其餘 API 調用都無效,除了resumePush
恢復推送服務的方法。
2.恢復推送。當調用了中止推送的方法後,只有調用恢復推送的方法後,極光推送服務才能正常工做。方法以下:
JPushInterface.resumePush(Context context);
複製代碼
3.獲取推送的工做狀態。想要知道當前推送服務是否正在工做,可經過以下方法:
JPushInterface.isPushStopped(Context context);
複製代碼
別名在極光推送中尤其重要,一般咱們用得最多的就是根據別名進行推送。咱們一般的作法是用戶登錄後,業務平臺會返回一個平臺生成的惟一識別號做爲推送的別名,而後後臺須要推送的時候,就直接拿着這個別名通知極光推送服務進行消息推送。
1.綁定別名alias。
JPushInterface.setAlias(Context context, int sequence, String alias);
複製代碼
2.解綁別名alias。
JPushInterface.deleteAlias(Context context, int sequence);
複製代碼
3.獲取綁定的別名alias。
JPushInterface.getAlias(Context context, int sequence);
複製代碼
注意事項:
1.這裏的sequence
主要就是操做識別碼,用於識別操做類型,由使用者本身定義。
2.以上全部的方法返回的都是void(都是異步操做),方法的返回都在自定義的消息接收器中,就是上面繼承JPushMessageReceiver由使用者自定義的廣播接收器中獲取。
3.別名相關操做的結果都在JPushMessageReceiver
的onAliasOperatorResult
方法中回調,須要獲取別名操做結果的可重寫該方法。
標籤比如一個分組,當咱們須要對某一類特殊羣體進行消息推送時,即可使用標籤進行推送。
1.增長標籤Tags。這是一個增量請求。
JPushInterface.addTags(Context context, int sequence, Set<String> tags);
複製代碼
2.刪除標籤Tags。
JPushInterface.deleteTags(Context context, int sequence, Set<String> tags);
複製代碼
3.獲取標籤Tags。
JPushInterface.getAllTags(Context context, int sequence);
複製代碼
4.設置標籤Tags。這是一個全量請求,會覆蓋以前設置的標籤。
JPushInterface.setTags(Context context, int sequence, Set<String> tags);
複製代碼
5.清除全部標籤。
JPushInterface.cleanTags(Context context, int sequence);
複製代碼
6.查詢指定 tag 與當前用戶綁定的狀態。
JPushInterface.checkTagBindState(Context context, int sequence, String tag);
複製代碼
注意事項:
1.這裏的sequence
和別名方法中的同樣,也是操做識別碼,用於識別操做類型,由使用者本身定義。
2.以上全部的方法返回的都是void(都是異步操做),方法的返回都在自定義的消息接收器中,就是上面繼承JPushMessageReceiver由使用者自定義的廣播接收器中獲取。
3.標籤相關操做的結果都在JPushMessageReceiver
的onTagOperatorResult
方法中回調,須要獲取標籤操做結果的可重寫該方法。
4.checkTagBindState
方法的結果是在JPushMessageReceiver
的onCheckTagOperatorResult
方法中回調,須要獲取標籤查詢匹配結果的可重寫該方法。
這裏的操做主要包括:註冊、別名(綁定、解綁、獲取)、標籤(添加、刪除、獲取、設置、清除、狀態檢查)、手機號設置等。因爲極光提供的這些操做都是異步的,且方法不能直接返回結果和提供回調接口,所以只能經過重寫
JPushMessageReceiver
中相應的方法獲取。
全部的操做結果均可以從JPushMessageReceiver
提供的回調方法中獲取。可是JPushMessageReceiver
最多隻能做爲消息的中轉站,使用起來極爲不便,所以咱們能夠結合一些事件機制來處理,將這些結果包裝爲一個個推送事件向外發出去,這樣只須要在須要的地方訂閱一下事件就能夠獲取到結果了。下面我以RxBus爲例簡單編寫,使用的庫是個人開源庫RxUtil2
1.定義操做事件的類型,用於識別操做類型。上文中提到的sequence
參數就可使用它。
/**
* 推送事件的類型
*/
@IntDef({TYPE_REGISTER, TYPE_UNREGISTER, TYPE_CONNECT_STATUS_CHANGED, TYPE_ADD_TAGS, TYPE_DEL_TAGS, TYPE_GET_TAGS, TYPE_BIND_ALIAS, TYPE_UNBIND_ALIAS, TYPE_GET_ALIAS})
@Retention(RetentionPolicy.SOURCE)
public @interface EventType {
/**
* 註冊推送
*/
int TYPE_REGISTER = 2000;
/**
* 取消註冊推送
*/
int TYPE_UNREGISTER = 2001;
/**
* 推送鏈接狀態發生變化
*/
int TYPE_CONNECT_STATUS_CHANGED = 2002;
/**
* 綁定別名
*/
int TYPE_BIND_ALIAS = 2010;
/**
* 解綁別名
*/
int TYPE_UNBIND_ALIAS = 2011;
/**
* 獲取別名
*/
int TYPE_GET_ALIAS = 2012;
/**
* 添加標籤[增量]
*/
int TYPE_ADD_TAGS = 2020;
/**
* 刪除標籤
*/
int TYPE_DEL_TAGS = 2021;
/**
* 獲取標籤
*/
int TYPE_GET_TAGS = 2022;
/**
* 設置標籤[全量]
*/
int TYPE_SET_TAGS = 2023;
/**
* 清除全部標籤
*/
int TYPE_CLEAN_TAGS = 2024;
/**
* 查詢指定 tag 與當前用戶綁定的狀態
*/
int TYPE_CHECK_TAG_BIND_STATE = 2025;
}
複製代碼
2.定義推送事件的載體.
該載體只須要定義三個成員變量:mType(事件類型)、mIsSuccess(是否成功)、mData(攜帶的數據)。以下所示:
/**
* 推送事件的載體
*/
public final class PushEvent {
public static final String KEY_PUSH_EVENT = "com.xuexiang.jpushsample.core.push.event.KEY_PUSH_EVENT";
/**
* 事件類型
*/
private int mType;
/**
* 是否成功(也能夠定義爲int型的結果碼)
*/
private boolean mIsSuccess;
/**
* 攜帶的數據(也能夠定義爲String型的數據)
*/
private Object mData;
public PushEvent(@EventType int type) {
mType = type;
}
public PushEvent(@EventType int type, boolean isSuccess) {
mType = type;
mIsSuccess = isSuccess;
}
public PushEvent(@EventType int type, Object data) {
mType = type;
mData = data;
}
public int getType() {
return mType;
}
public PushEvent setType(@EventType int type) {
mType = type;
return this;
}
public boolean isSuccess() {
return mIsSuccess;
}
public PushEvent setSuccess(boolean success) {
mIsSuccess = success;
return this;
}
public Object getData() {
return mData;
}
public PushEvent setData(Object data) {
mData = data;
return this;
}
}
複製代碼
3.事件處理併發送.
在JPushMessageReceiver
中重寫指定的方法,並將結果轉譯爲一個個PushEvent
發送出去。
/**
* 極光推送消息接收器
*/
public class PushMessageReceiver extends JPushMessageReceiver {
private static final String TAG = "JPush-Receiver";
//======================下面的都是操做的回調=========================================//
@Override
public void onRegister(Context context, String registrationId) {
Log.e(TAG, "[onRegister]:" + registrationId);
RxBusUtils.get().post(KEY_PUSH_EVENT, new PushEvent(EventType.TYPE_REGISTER, true, registrationId));
}
/**
* 鏈接狀態發生變化
*
* @param context
* @param isConnected 是否已鏈接
*/
@Override
public void onConnected(Context context, boolean isConnected) {
Log.e(TAG, "[onConnected]:" + isConnected);
RxBusUtils.get().post(KEY_PUSH_EVENT, new PushEvent(EventType.TYPE_CONNECT_STATUS_CHANGED, isConnected));
}
/**
* 全部和標籤相關操做結果
*
* @param context
* @param jPushMessage
*/
@Override
public void onTagOperatorResult(Context context, JPushMessage jPushMessage) {
Log.e(TAG, "[onTagOperatorResult]:" + jPushMessage);
PushEvent pushEvent = new PushEvent(jPushMessage.getSequence(), jPushMessage.getErrorCode() == 0)
.setData(JPushInterface.getStringTags(jPushMessage.getTags()));
RxBusUtils.get().post(KEY_PUSH_EVENT, pushEvent);
}
/**
* 全部和別名相關操做結果
*
* @param context
* @param jPushMessage
*/
@Override
public void onAliasOperatorResult(Context context, JPushMessage jPushMessage) {
Log.e(TAG, "[onAliasOperatorResult]:" + jPushMessage);
PushEvent pushEvent = new PushEvent(jPushMessage.getSequence(), jPushMessage.getErrorCode() == 0)
.setData(jPushMessage.getAlias());
RxBusUtils.get().post(KEY_PUSH_EVENT, pushEvent);
}
/**
* 標籤狀態檢測結果
*
* @param context
* @param jPushMessage
*/
@Override
public void onCheckTagOperatorResult(Context context, JPushMessage jPushMessage) {
Log.e(TAG, "[onCheckTagOperatorResult]:" + jPushMessage);
PushEvent pushEvent = new PushEvent(jPushMessage.getSequence(), jPushMessage.getErrorCode() == 0)
.setData(jPushMessage);
RxBusUtils.get().post(KEY_PUSH_EVENT, pushEvent);
}
}
複製代碼
4.在須要獲取結果的地方訂閱或者取消事件。
@Override
protected void initListeners() {
//訂閱推送事件
mPushEvent = RxBusUtils.get().onMainThread(KEY_PUSH_EVENT, PushEvent.class, this::handlePushEvent);
}
/**
* 處理推送事件,獲取操做的結果
* @param pushEvent
*/
private void handlePushEvent(PushEvent pushEvent) {
String content = pushEvent.getData().toString();
switch (pushEvent.getType()) {
case TYPE_BIND_ALIAS:
if (pushEvent.isSuccess()) {
tvAlias.setText(content);
XToastUtils.success("別名[" + content + "]綁定成功");
} else {
XToastUtils.error("別名[" + content + "]綁定失敗");
}
break;
case TYPE_UNBIND_ALIAS:
//別名解綁
break;
case TYPE_GET_ALIAS:
//獲取別名
break;
case TYPE_ADD_TAGS:
//添加標籤
break;
case TYPE_DEL_TAGS:
//刪除標籤
break;
case TYPE_GET_TAGS:
//獲取標籤
break;
case TYPE_SET_TAGS:
//設置標籤
break;
case TYPE_CLEAN_TAGS:
//清除標籤
break;
case TYPE_CHECK_TAG_BIND_STATE:
//檢查標籤
break;
........
default:
break;
}
}
@Override
public void onDestroyView() {
if (mPushEvent != null) {
//取消訂閱推送事件
RxBusUtils.get().unregister(KEY_PUSH_EVENT, mPushEvent);
mPushEvent = null;
}
super.onDestroyView();
}
複製代碼
點擊參見自定義JPushMessageReceiver的源碼
自定義消息,又稱之爲透傳消息。顧名思義是由使用者本身定義一套解析格式的消息,這種消息在接收到後不會有任何界面上的展現,攜帶內容爲String型,一般的作法是傳一個json。這種比較靈活的消息推送方式是最經常使用的一種。可是這裏須要注意的是,這種消息是一種應用內的消息,一旦應用被殺死,將沒法及時收到該消息。
1.自定義消息體(CustomMessage)介紹
字段名 | 類型 | 字段說明 |
---|---|---|
messageId | String | 消息ID,對應推送平臺上的消息惟一號 |
message | String | 對應推送消息界面上的「自定義消息內容」字段 |
extra | String | 保存服務器推送下來的附加字段。這是個 JSON 字符串,對應推送消息界面上的「可選設置」裏的附加字段。 |
title | String | 消息的標題(沒多大做用) |
2.自定義消息接收
若是想要接收自定義消息,只需重寫JPushMessageReceiver
中的onMessage
方法便可。在onMessage
方法中將會回調CustomMessage
自定義消息體。
普統統知消息,就是在系統通知欄上顯示的消息。可是若是通知的內容爲空,則不會在通知欄上展現通知。
1.通知消息體(NotificationMessage)介紹
字段名 | 類型 | 字段說明 |
---|---|---|
messageId | String | 消息ID,對應推送平臺上的消息惟一號 |
notificationId | int | 通知欄的 Notification ID,用於清除 Notification |
notificationTitle | String | 通知的標題,對應推送通知界面上的「通知標題」字段 |
notificationContent | String | 通知的內容,對應推送通知界面上的「通知內容」字段 |
notificationExtras | String | 附加字段,對應推送通知界面上的「可選設置」裏的附加字段 |
notificationTitle | String | 通知的標題,對應推送通知界面上的「通知標題」字段 |
2.普統統知消息接收
若是想要接收自定義消息,只需重寫JPushMessageReceiver
中的onNotifyMessageArrived
方法便可。在onNotifyMessageArrived
方法中將會回調NotificationMessage
通知消息體。
3.通知消息被點擊
在作消息推送開發的時候,咱們必定會有一個需求:但願用戶點擊通知後,可以自動跳轉到咱們應用的某個頁面。這個頁面多是某一個活動宣傳頁面,也有多是某個新聞或者視頻頁面。這個時候,咱們就須要對通知消息點擊後的動做進行自定義。
那麼咱們該如何自定義通知消息被點擊後的動做呢?很簡單,咱們只須要重寫JPushMessageReceiver
中的onNotifyMessageOpened
方法,在方法中讀取傳遞過來的參數,而後結合頁面路由機制(例如:ARouter)直接跳轉至指定頁面便可。
下面我將經過兩種不一樣的途徑來實現 點擊通知消息後跳轉至某一特定界面:
1.重寫JPushMessageReceiver
中的onNotifyMessageOpened
方法。
public class PushMessageReceiver extends JPushMessageReceiver {
/**
* 點擊通知回調
*
* @param context
* @param message 通知消息
*/
@Override
public void onNotifyMessageOpened(Context context, NotificationMessage message) {
Log.e(TAG, "[onNotifyMessageOpened]:" + message);
//自定義打開到通知欄點擊後的容器頁
Intent intent = parseNotificationMessage(IntentUtils.getIntent(context, NotificationTransferActivity.class, null, true), message);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
ActivityUtils.startActivity(intent);
}
/**
* 解析極光通知消息:NotificationMessage
*/
public static Intent parseNotificationMessage(@NonNull Intent intent, NotificationMessage message) {
//這只是一個例子,暫時把跳轉的目標頁設爲 "通知信息展現"
intent.putExtra("pageName", "通知信息展現");
//通知標題
intent.putExtra("title", message.notificationTitle);
//通知內容
intent.putExtra("content", message.notificationContent);
//通知附帶拓展內容
intent.putExtra("extraMsg", message.notificationExtras);
//通知附帶鍵值對
intent.putExtra("keyValue", message.notificationExtras);
return intent;
}
}
複製代碼
2.經過DeepLink
技術和通知欄中可選設置的自定義(打開指定頁面)
相結合的方法。
(1)首先須要在AndroidManifest.xml
中定義deeplink攔截。
<!--通知被點擊以後跳轉的頁面-->
<activity android:name=".activity.NotificationTransferActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="com.xuexiang.jpush"
android:path="/notification"
android:scheme="jpush" />
</intent-filter>
</activity>
複製代碼
(2)在容器界面NotificationTransferActivity
中解析傳遞過來的參數。
/**
* 通知欄點擊後的容器頁
*
* deeplink格式
*
* jpush://com.xuexiang.jpush/notification?pageName=通知信息展現&title=這是一個通知&content=這是通知的內容&extraMsg=xxxxxxxxx&keyValue={"param1": "1111", "param2": "2222"}
*
*/
@Router(path = "/push/notification/transfer")
public class NotificationTransferActivity extends BaseActivity {
@AutoWired
String pageName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
XRouter.getInstance().inject(this);
Uri uri = getIntent().getData();
Bundle bundle = getIntent().getExtras();
if (uri != null) {
//deeplink跳轉
pageName = uri.getQueryParameter("pageName");
bundle = Utils.parseNotificationDeepLinkUri(uri, bundle);
}
if (!StringUtils.isEmpty(pageName)) {
//打開指定頁面
if (openPage(pageName, bundle) == null) {
XToastUtils.toast("頁面未找到!");
finish();
}
} else {
XToastUtils.toast("頁面未找到!");
finish();
}
}
/**
* DeepLink的格式:
* jpush://com.xuexiang.jpush/notification?pageName=xxxxx&title=這是一個通知&content=這是通知的內容&extraMsg=xxxxxxxxx&keyValue={"param1": "1111", "param2": "2222"}
* @param uri
* @param bundle
* @return
*/
public static Bundle parseNotificationDeepLinkUri(@NonNull Uri uri, Bundle bundle) {
if (bundle == null) {
bundle = new Bundle();
}
bundle.putString("pageName", uri.getQueryParameter("pageName"));
//通知標題
bundle.putString("title", uri.getQueryParameter("title"));
//通知內容
bundle.putString("content", uri.getQueryParameter("content"));
//通知附帶拓展內容
bundle.putString("extraMsg", uri.getQueryParameter("extraMsg"));
//通知附帶鍵值對
bundle.putString("keyValue", uri.getQueryParameter("keyValue"));
return bundle;
}
}
複製代碼
注意:上面的openPage
方法主要使用了個人開源XPage,主要的做用就是Fragment頁面路由,加載一個Fragment頁面。
(3)發通知消息的時候,記得設置上自定義(打開指定頁面)
的連接,以下圖所示:
jpush://com.xuexiang.jpush/notification
對應上面AndroidManifest.xml
中配置的信息。jpush://com.xuexiang.jpush/notification?pageName=xxxxx&title=這是一個通知&content=這是通知的內容&extraMsg=xxxxxxxxx&keyValue={"param1": "1111", "param2": "2222"}
複製代碼
一樣的,自定義消息和通知消息都是在
JPushMessageReceiver
的回調方法中獲取,和上面的操做結果相似,JPushMessageReceiver
最多隻是做爲消息的中轉站,若是咱們想要在任何頁面都可以訂閱到接收到的消息,那麼咱們依舊能夠和上面處理得同樣,使用RxBus將這些消息向外發送出去。
下面我給出實現的簡要步驟:
1.定義消息的類型,這裏暫時就是自定義消息和通知消息。
/**
* 消息的類型
*/
@IntDef({TYPE_CUSTOM, TYPE_NOTIFICATION})
@Retention(RetentionPolicy.SOURCE)
public @interface MessageType {
/**
* 自定義消息
*/
int TYPE_CUSTOM = 1000;
/**
* 普統統知消息
*/
int TYPE_NOTIFICATION = 1001;
}
複製代碼
2.定義推送消息的載體.
目前爲了偷懶,暫時就只定義了兩個成員變量:mType(消息類型)和mMessage(消息數據)。以下所示:
/**
* 推送消息
*/
public final class PushMessage {
public static final String KEY_PUSH_MESSAGE = "com.xuexiang.jpushsample.core.push.event.KEY_PUSH_MESSAGE";
/**
* 消息類型
*/
private int mType;
/**
* 消息數據
*/
private Object mMessage;
public static PushMessage wrap(@MessageType int type, Object message) {
return new PushMessage(type, message);
}
public PushMessage(@MessageType int type, Object message) {
mType = type;
mMessage = message;
}
public int getType() {
return mType;
}
public PushMessage setType(int type) {
mType = type;
return this;
}
public <T> T getMessage() {
return (T) mMessage;
}
public PushMessage setMessage(Object message) {
mMessage = message;
return this;
}
public String getMessageType() {
switch (mType) {
case TYPE_CUSTOM:
return "自定義消息";
case TYPE_NOTIFICATION:
return "普統統知消息";
default:
return "未知消息";
}
}
}
複製代碼
3.消息接收並分發.
在JPushMessageReceiver
中重寫onMessage
和onNotifyMessageArrived
方法,並將結果轉譯爲一個個PushMessage
發送出去。
/**
* 極光推送消息接收器
*/
public class PushMessageReceiver extends JPushMessageReceiver {
private static final String TAG = "JPush-Receiver";
/**
* 收到自定義消息回調
*
* @param context
* @param message 自定義消息
*/
@Override
public void onMessage(Context context, CustomMessage message) {
Log.e(TAG, "[onMessage]:" + message);
RxBusUtils.get().post(KEY_PUSH_MESSAGE, PushMessage.wrap(MessageType.TYPE_CUSTOM, message));
}
/**
* 收到通知回調
*
* @param context
* @param message 通知消息
*/
@Override
public void onNotifyMessageArrived(Context context, NotificationMessage message) {
Log.e(TAG, "[onNotifyMessageArrived]:" + message);
RxBusUtils.get().post(KEY_PUSH_MESSAGE, PushMessage.wrap(MessageType.TYPE_NOTIFICATION, message));
}
}
複製代碼
此外,若是因業務須要,在消息發送出去以前,咱們還能夠在發送前添加一個過濾器處理,對一些重複、無效的消息進行過濾,或者對同時接收到的消息進行消息合併等操做。
4.在須要獲取推送消息的地方訂閱。
@Override
protected void initListeners() {
//訂閱消息
RxBusUtils.get().onMainThread(KEY_PUSH_MESSAGE, PushMessage.class, this::handlePushMessage);
}
/**
* 處理接收到的推送消息
*/
private void handlePushMessage(PushMessage pushMessage) {
tvType.setText(pushMessage.getMessageType());
tvMessage.setText(pushMessage.getMessage().toString());
}
@Override
public void onDestroyView() {
//取消訂閱
RxBusUtils.get().unregisterAll(KEY_PUSH_MESSAGE);
super.onDestroyView();
}
複製代碼
好啦,以上就是《極光推送之Android客戶端使用指南--基礎篇》的所有內容,本文主要介紹了極光推送最經常使用也是最基礎的幾部份內容,相信若是你能徹底掌握上面的內容的話,推送基本上也算是得心應手了.下面我還將深刻挖掘極光推送的幾個高級使用,敬請期待吧!