Android整合極光推送和踩過的坑(一)
轉載請標明出處
整合步驟以及整合過程遇到的坑:
這部分主要闡述了整合極光推送的sdk的步驟,以及我在整合過程中遇到的一些問題。整合步驟只是摘出了極光SDK中必須的骨子的部分,可以滿足一般專案Push需求,這裡只做了通知訊息,自定義的穿透訊息請詳見極光的SDK整合文件。我主要是總結一下,整合過程中需要注意和可能出問題的地方(詳見注的說明),如果你也遇到了類似的問題,希望可以通過這篇文章能迅速把坑填了。LZ表示,這些坑好心塞~
一.jcenter 自動整合步驟
1.確認android studio的 Project 根目錄的主 gradle 中配置了jcenter支援。(新建project預設配置就支援
,一般不需要配置,只要確認一下就好)buildscript { repositories { jcenter() } ...... } allprojects { repositories { jcenter() } }
2.在 module 的 gradle 中新增依賴和AndroidManifest的替換變數。
android { ...... defaultConfig { applicationId "com.xxx.xxx" //JPush上註冊的包名. ...... ndk { //選擇要新增的對應cpu型別的.so庫。 abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a' // 還可以新增 'x86', 'x86_64', 'mips', 'mips64' } manifestPlaceholders = [ JPUSH_PKGNAME : applicationId, JPUSH_APPKEY : "你的appkey", //JPush上註冊的包名對應的appkey. JPUSH_CHANNEL : "自定義渠道名稱", //使用者渠道統計的渠道名稱 ] ...... } ...... } dependencies { ...... compile 'cn.jiguang.sdk:jpush:3.0.5' compile 'cn.jiguang.sdk:jcore:1.1.2' ...... }
注 : 1. 如果在新增以上 abiFilter 配置之後android Studio出現以下提示:
NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin
則在 Project 根目錄的gradle.properties檔案中新增:
android.useDeprecatedNdk=true
二. AndroidManifest加許可權
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.******"> <uses-permission android:name="android.permission.INTERNET"/> <!-- 訪問當前網路狀態許可權 --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <!-- 獲取手機資訊 --> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION"/> <!--2017.5.27 極光推送許可權 ym start--> <uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.RECEIVE_USER_PRESENT"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_SETTINGS"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <permission android:name="com.******(包名).permission.JPUSH_MESSAGE" android:protectionLevel="signature"/> <uses-permission android:name="com.******(包名).permission.JPUSH_MESSAGE"/> <!--2017.5.27 極光推送許可權 ym end-->
注 :
1.記得修改極光自定義許可權的包名。
2.【訪問當前網路狀態許可權】和【獲取手機資訊】專案裡一般已經新增,這裡檢查一下,缺的補上。【極光推送許可權】是極光要求,但是專案裡可能沒有的,注意檢視。
<permission android:name="com.******(包名).permission.JPUSH_MESSAGE" android:protectionLevel="signature"/> <uses-permission android:name="com.carspass.permission.JPUSH_MESSAGE"/>
三. 整合 JPush Android SDK 的混淆,否則打包後極光不好使
-
請下載4.x及以上版本的proguard.jar, 並替換你Android Sdk "tools\proguard\lib\proguard.jar"
-
請在工程的混淆檔案中新增以下配置:
-dontoptimize -dontpreverify -dontwarn cn.jpush.** -keep class cn.jpush.** { *; } -dontwarn cn.jiguang.** -keep class cn.jiguang.** { *; }
注 : 別忘了往混淆檔案里加這段程式碼。我第一次整合的時候給忘卻了,後來大神找我說minifyEnabled true(minifyEnabled主要用來控制是否執行混淆的。true表示混淆), 極光打包以後不好使,提醒我忘記在混淆檔案中加這段程式碼了。
dontwarn表示打包混淆的時候,消除極光的警告。 keep表示保持極光的一些類,不被混淆。
四. JPushManger極光推送管理類
/** * Created by ym on 2017/5/27. * 極光推送管理類 */ public class JPushManager { private String TAG = "JPushManager"; private final String KEY = "JpushConfig"; private Context context; private SharePreferenceUtil sp; public JPushManager(Context context) { this.context = context; sp = new SharePreferenceUtil(context); } /** * 初始化極光,一般可以放到程式的啟動Activity或是Application的onCreate方法中呼叫 */ public void initJPush() { JPushInterface.setDebugMode(true); // 設定開啟日誌,釋出時請關閉日誌 JPushInterface.init(context); // 初始化 JPush } /** * 退出極光,一般是程式退出登入時候,具體還是需要看專案的實際需求 */ public void stopJPush() { JPushInterface.stopPush(context); //setAliasAndTags("", "");//通過清空別名來停止極光 } /** * 極光推送恢復正常工作 */ public void resumeJPush() { JPushInterface.resumePush(context); } /** * 設定AliasAndTag,設定多組tag,如果不需要設定tag的化,直接將此引數設為null;(這個方法設定別名,tag傳null沒有問題) * 一般在程式登入成功,註冊成功等地方呼叫。別名一般是使用者的唯一標識,如userId等 * * @param alias * @param tags */ public void setAliasAndTags(final String alias, Set<String> tags) { if (TextUtils.isEmpty(alias)) { //Toast.makeText(context, "別名為空", Toast.LENGTH_SHORT).show(); return; } // 呼叫 Handler 來非同步設定別名 AliasAndTagsInfo aliasAndTagsInfo = new AliasAndTagsInfo(); aliasAndTagsInfo.setAlias(alias); aliasAndTagsInfo.setTag(tags); mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_ALIAS, aliasAndTagsInfo)); } // /** // * 設定AliasAndTag,設定一組tag,如果不需要設定tag的化,直接將此引數設為null;(這個方法設定別名,不設定tag,tag傳null會走6002,tag引數錯誤) // */ // public void setAliasAndTags(final String alias, String tag) { // if (TextUtils.isEmpty(alias)) { // // Toast.makeText(context, "別名為空", Toast.LENGTH_SHORT).show(); // return; // } // // 呼叫 Handler 來非同步設定別名 // AliasAndTagsInfo aliasAndTagsInfo = new AliasAndTagsInfo(); // aliasAndTagsInfo.setAlias(alias); // Set<String> tags = new HashSet<String>(); // tags.add(tag); // aliasAndTagsInfo.setTag(tags); // mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_ALIAS, // aliasAndTagsInfo)); // } private final TagAliasCallback mAliasCallback = new TagAliasCallback() { @Override public void gotResult(int code, String alias, Set<String> tags) { String logs; switch (code) { case 0: logs = "Set tag and alias success"; Log.d(TAG, logs); // 建議這裡往 SharePreference 裡寫一個成功設定的狀態。成功設定一次後,以後不必再次設定了。 saveAlias(alias); break; case 6002: logs = "Failed to set alias and tags due to timeout. Try again after 60s."; Log.d(TAG, logs); // 延遲 60 秒來呼叫 Handler 設定別名 mHandler.sendMessageDelayed( mHandler.obtainMessage(MSG_SET_ALIAS, alias), 1000 * 60); break; default: logs = "Failed with errorCode = " + code; Log.d(TAG, logs); } } }; /** * 儲存別名到屬性檔案。 * * @param alias */ private void saveAlias(String alias) { sp.putString(KEY, alias); } /** * 從屬性檔案取得別名 * * @param userName * @return */ private String getAlias(String userName) { return sp.getString(KEY); } private static final int MSG_SET_ALIAS = 1001; private final Handler mHandler = new Handler() { @Override public void handleMessage(android.os.Message msg) { super.handleMessage(msg); AliasAndTagsInfo aliasAndTagsInfo = (AliasAndTagsInfo) msg.obj; switch (msg.what) { case MSG_SET_ALIAS: Log.d(TAG, "Set alias in handler."); LogUtil.e("ym", aliasAndTagsInfo.getAlias()); // 呼叫 JPush 介面來設定別名。 JPushInterface.setAliasAndTags(context, aliasAndTagsInfo.getAlias(), aliasAndTagsInfo.getTag(), mAliasCallback); break; default: Log.d(TAG, "Unhandled msg - " + msg.what); } } }; public class AliasAndTagsInfo implements Serializable { private static final long serialVersionUID = 1L; private String alias; private Set<String> tag; public String getAlias() { return alias; } public void setAlias(String alias) { this.alias = alias; } public Set<String> getTag() { return tag; } public void setTag(Set<String> tag) { this.tag = tag; } } }
注 :
1.這裡提供了兩個同時設定別名和標籤的同名方法。不設定tag的話可以直接傳null,但是傳null的話,這兩個過載的方法傳的引數會一樣,系統會不知道我們調的哪個方法。於是乎,我就把第一個註釋了……然後就自己給自己挖了個很大的坑。親測發現第一個方法Set<String>tags的位置傳null,沒問題。第二個String tag,傳null,極光的介面回調回來走的6002,說tag的引數傳的有問題。然後仔細一看,我相當於把一個null物件放到了Set<String>tags裡,然後傳給了極光。這裡可以在原來基礎上加個判空,然後再往Set裡add。就跟第一種方法是一樣的了。我現在只是把第二種方法註釋掉了,沒有做修改。如果專案需求只要求設定一個標籤,用第二種方法的話,自行加判空處理就好。
public void setAliasAndTags(final String alias, Set<String> tags) {} public void setAliasAndTags(final String alias, String tag) {}
2.專案需求只要求設定別名,沒有要求設定標籤的話。可以按照sdk文件上的setAlias()的方法設定就行。我們專案也是隻要求設定別名,但是我怕產品回頭又要設定標籤,索性就直接用了上面的方法,方便以後修改。
3.這裡設定別名是非同步操作的,我們的大神有指出說我設定別名放到了登入回撥裡是不合理的,說有可能極光伺服器down掉了,會卡死在登入介面,然後使用者手動殺死程序再進來,這是已經是登入成功的狀態,直接會進入首頁。這樣會導致極光設定別名失敗。
但是我分析之後,個人覺得這個設定別名的操作是非同步執行了,不存在大神說的那種卡死的情況。第一次設定的時候,會調這個方法。類似於我們做banner輪播圖的時候,先發一條觸發輪播的開始一樣。發完就完事了,大神說的在登入回撥中我設定極光別名的程式碼下邊,開啟首頁等操作的程式碼會繼續執行,並不會卡死。
mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_ALIAS, aliasAndTagsInfo));
第一次發完以後,會走handler中的handleMessage(),調極光的介面
// 呼叫 JPush 介面來設定別名。 JPushInterface.setAliasAndTags(context, aliasAndTagsInfo.getAlias(), aliasAndTagsInfo.getTag(), mAliasCallback);
然後再回調中0表示設定成功,6002表示設定失敗,設定失敗以後會延遲60s以後重新調handler設定別名。不存在大神說的設定失敗,就失敗的問題。
private final TagAliasCallback mAliasCallback = new TagAliasCallback() { @Override public void gotResult(int code, String alias, Set<String> tags) { String logs; switch (code) { case 0: logs = "Set tag and alias success"; Log.d(TAG, logs); // 建議這裡往 SharePreference 裡寫一個成功設定的狀態。成功設定一次後,以後不必再次設定了。 saveAlias(alias); break; case 6002: logs = "Failed to set alias and tags due to timeout. Try again after 60s."; Log.d(TAG, logs); // 延遲 60 秒來呼叫 Handler 設定別名 mHandler.sendMessageDelayed( mHandler.obtainMessage(MSG_SET_ALIAS, alias), 1000 * 60); break; default: logs = "Failed with errorCode = " + code; Log.d(TAG, logs); } } };
五. 在Application的onCreate()中初始化極光
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); //2017.5.27 極光推送初始化 ym start JPushManager jPushManager = new JPushManager(this); jPushManager.initJPush(); String registrationID = JPushInterface.getRegistrationID(MyApplication.this); LogUtil.e("ym", "registrationID" + registrationID);//美圖測試機100d85590976ac4ac55 //2017.5.27 極光推送初始化 ym end } }
注 :
1. 關於獲取 RegistrationID,官方說有兩種方法可以拿。
SDK 初次註冊成功後,開發者通過在自定義的 Receiver 裡監聽Action - cn.jpush.Android.intent.REGISTRATION來獲取對應的 RegistrationID。註冊成功後,也可以通過此函式獲取
public static String getRegistrationID(Context context)。
Lz親測,第一種是誤導,應該在application中才能拿到!!!而不是自定義Receiver!我又看到別人也有說第一種拿不到的情況。
不知道什麼原因,按理說,在註冊極光成功以後,極光會發一個廣播,我們可以在廣播中拿到
RegistrationID
,但是親測發現根本不走自定義的Reciver的這個廣播,SDK文件中說是可以拿到的,但是人家這廣播我都接受不到,所以拿不到,如果有誰知道是什麼原因,請告之!萬分感謝!
RegistrationID
所以我採用的是在
application
裡拿RegistrationID
。有在自定義String registrationID = JPushInterface.getRegistrationID(MyApplication.this); LogUtil.e("ym", "registrationID" + registrationID);//美圖測試機100d85590976ac4ac55
Receiver
裡拿到的請留言~,讓我知道一下自己問題出在哪裡,相互學習嘛。如果你也拿不到,就跟我似的在裡拿吧。當然如果專案需求根本沒有要根據
application
RegistrationID個推,後臺也不需要你這個
繫結使用者的話,那就無關緊要了,那就不需要拿
RegistrationID
了。
RegistrationID
2.這個JPushManager網上有用單例初始化的,靜態Context會導致記憶體洩露。
public class JPushManager { private String TAG = "JPushManager"; private final String KEY = "JpushConfig"; private static JPushManager jPushManager; private static Context context; public static JPushManager newInstence(Context context) { JPushManager.context = context; if (jPushManager == null) { jPushManager = new JPushManager(); } return jPushManager; }
於是就改成下面這樣的,這樣Context就不是靜態的了!但是同樣會導致記憶體洩露。但是恰恰下面這種是單例導致記憶體洩露最典型的例子。由於單例的靜態特性使得其生命週期跟應用的生命週期一樣長,所以如果使用不恰當的話,很容易造成記憶體洩漏。
當建立這個單例的時候,由於需要傳入一個Context,所以這個Context的生命週期的長短至關重要:public class JPushManager { private String TAG = "JPushManager"; private final String KEY = "JpushConfig"; private static JPushManager jPushManager; private Context context; public JPushManager(Context context) { this.context = context; } public static JPushManager newInstence(Context context) { if (jPushManager == null) { jPushManager = new JPushManager(context); } return jPushManager; }
1、如果此時傳入的是 Application 的 Context,因為 Application 的生命週期就是整個應用的生命週期,所以這將沒有任何問題。
2、如果此時傳入的是 Activity 的 Context,當這個 Context 所對應的 Activity 退出時,由於該 Context 的引用被單例物件所持有,其生命週期等於整個應用程式的生命週期,所以當前 Activity 退出時它的記憶體並不會被回收,這就造成洩漏了。
正確的做法:public class JPushManager { private String TAG = "JPushManager"; private final String KEY = "JpushConfig"; private static JPushManager jPushManager; private Context context; public static JPushManager newInstence() { this.context = getApplicationContext(); if (jPushManager == null) { jPushManager = new JPushManager(); } return jPushManager; }
六. 極光推送自定義的廣播接受者,用於獲取推送到通知欄的訊息內容、訊息附加的引數欄位處理訊息的跳轉
/** * Created by ym on 2017/5/27. * 自定義極光推送的廣播接受者 */ public class MyJPushReceiver extends BroadcastReceiver { private static final String TAG = "JPush"; @Override public void onReceive(Context context, Intent intent) { Bundle bundle = intent.getExtras(); LogUtil.e(TAG, "[MyReceiver] onReceive - " + intent.getAction() + ", extras: " + printBundle(bundle)); if (JPushInterface.ACTION_REGISTRATION_ID.equals(intent.getAction())) { String regId = bundle.getString(JPushInterface.EXTRA_REGISTRATION_ID); LogUtil.e(TAG, "[MyReceiver] 接收Registration Id : " + regId); } else if (JPushInterface.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) { LogUtil.e(TAG, "[MyReceiver] 接收到推送下來的自定義訊息: " + bundle.getString(JPushInterface.EXTRA_MESSAGE)); // processCustomMessage(context, bundle); } else if (JPushInterface.ACTION_NOTIFICATION_RECEIVED.equals(intent.getAction())) { LogUtil.e(TAG, "[MyReceiver] 接收到推送下來的通知"); int notificationId = bundle.getInt(JPushInterface.EXTRA_NOTIFICATION_ID); LogUtil.e(TAG, "[MyReceiver] 接收到推送下來的通知的ID: " + notificationId); } else if (JPushInterface.ACTION_NOTIFICATION_OPENED.equals(intent.getAction())) { LogUtil.e(TAG, "[MyReceiver] 使用者點選打開了通知"); //解析json String string = bundle.getString(JPushInterface.EXTRA_EXTRA);//json串 LogUtil.e(TAG, "=====###########" + string); try { JSONObject jsonObject = new JSONObject(string); String type = jsonObject.getString("type"); LogUtil.e(TAG, "type:" + type); switch (type) { case "1"://開啟應用 if (isBackground(context)) { Intent i = new Intent(context, ACT_Main.class); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); context.startActivity(i); } break; case "2"://開啟建立訂單頁 String sourse_id = jsonObject.getString("sourse_id"); if (!TextUtils.isEmpty(sourse_id)) { Intent intentOrder = new Intent(context, ACT_PlaceOrder.class); intentOrder.putExtra("id", Integer.parseInt(sourse_id)); intentOrder.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intentOrder); } break; case "3"://開啟品牌 String brand_id = jsonObject.getString("brand_id"); String bra_name = jsonObject.getString("bra_name"); if (!TextUtils.isEmpty(brand_id)){ Intent intentBrand = new Intent(context, ACT_BrandCarList.class); intentBrand.putExtra("id", brand_id); intentBrand.putExtra("title", bra_name); intentBrand.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intentBrand); } break; case "4"://開啟指定頁面 String http_url = jsonObject.getString("http_url"); if (!TextUtils.isEmpty(http_url)){ Intent intentWeb = new Intent(context, ACT_Web.class); intentWeb.putExtra("title", ""); intentWeb.putExtra("url", http_url); intentWeb.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intentWeb); } break; case "5"://開啟議價詳情 String bargainid = jsonObject.getString("bargainid"); if (!TextUtils.equals(bargainid, "0") && !TextUtils.isEmpty(bargainid)) {//bargainid=0是議價已取消,不跳轉 Intent bargainIntent = new Intent(context, ACT_BargainingDetail.class); bargainIntent.putExtra("id", bargainid); bargainIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(bargainIntent); } break; } } catch (JSONException e) { e.printStackTrace(); } } else if (JPushInterface.ACTION_RICHPUSH_CALLBACK.equals(intent.getAction())) { LogUtil.e(TAG, "[MyReceiver] 使用者收到到RICH PUSH CALLBACK: " + bundle.getString(JPushInterface.EXTRA_EXTRA)); //在這裡根據 JPushInterface.EXTRA_EXTRA 的內容處理程式碼,比如開啟新的Activity, 開啟一個網頁等.. } else if (JPushInterface.ACTION_CONNECTION_CHANGE.equals(intent.getAction())) { boolean connected = intent.getBooleanExtra(JPushInterface.EXTRA_CONNECTION_CHANGE, false); LogUtil.e(TAG, "[MyReceiver]" + intent.getAction() + " connected state change to " + connected); } else { LogUtil.e(TAG, "[MyReceiver] Unhandled intent - " + intent.getAction()); } } // 列印所有的 intent extra 資料 private static String printBundle(Bundle bundle) { StringBuilder sb = new StringBuilder(); for (String key : bundle.keySet()) { if (key.equals(JPushInterface.EXTRA_NOTIFICATION_ID)) { sb.append("\nkey:" + key + ", value:" + bundle.getInt(key)); } else if (key.equals(JPushInterface.EXTRA_CONNECTION_CHANGE)) { sb.append("\nkey:" + key + ", value:" + bundle.getBoolean(key)); } else if (key.equals(JPushInterface.EXTRA_EXTRA)) { if (TextUtils.isEmpty(bundle.getString(JPushInterface.EXTRA_EXTRA))) { LogUtil.e(TAG, "This message has no Extra data"); continue; } try { JSONObject json = new JSONObject(bundle.getString(JPushInterface.EXTRA_EXTRA)); Iterator<String> it = json.keys(); while (it.hasNext()) { String myKey = it.next().toString(); sb.append("\nkey:" + key + ", value: [" + myKey + " - " + json.optString(myKey) + "]"); } } catch (JSONException e) { LogUtil.e(TAG, "Get message extra JSON error!"); } } else { sb.append("\nkey:" + key + ", value:" + bundle.getString(key)); } } return sb.toString(); } /** * 判斷程序是否在後臺 * * @param context * @return */ public static boolean isBackground(Context context) { ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses(); for (RunningAppProcessInfo appProcess : appProcesses) { if (appProcess.processName.equals(context.getPackageName())) { LogUtil.i("ym", appProcess.processName + "前臺"); return false; } else { LogUtil.i("ym", appProcess.processName + "後臺"); return true; } } return false; } }
注:注意開啟Activity的intent的flag,這裡主要講整合極光不坐贅述。有需要可以檢視 Activity的啟動模式和Intent標記位。
七. AndroidManifest中加極光推送自定義的廣播接受者
注意:記得修改包名,我直接複製的之前專案的,導致忘記修改包名,推送訊息就是不走MyJPushReceiver。<!--2017.5.27 極光推送自定義的廣播接收器 ym start--> <receiver android:name=".module.MyJPushReceiver" android:enabled="true" android:exported="false"> <intent-filter> <action android:name="cn.jpush.android.intent.REGISTRATION"/> <!-- Required 使用者註冊SDK的intent --> <action android:name="cn.jpush.android.intent.MESSAGE_RECEIVED"/> <!-- Required 使用者接收SDK訊息的intent --> <action android:name="cn.jpush.android.intent.NOTIFICATION_RECEIVED"/> <!-- Required 使用者接收SDK通知欄資訊的intent --> <action android:name="cn.jpush.android.intent.NOTIFICATION_OPENED"/> <!-- Required 使用者開啟自定義通知欄的intent --> <action android:name="cn.jpush.android.intent.NOTIFICATION_CLICK_ACTION"/> <action android:name="cn.jpush.android.intent.CONNECTION"/> <!-- 接收網路變化 連線/斷開 since 1.6.3 --> <category android:name="com.*******(包名)"/> </intent-filter> </receiver> <!--2017.5.27 極光推送自定義的廣播接收器 ym end-->
八. 設定別名
在登入成功的回撥中設定別名,這裡用的token做的別名,大家可以根據需求自行更換。這裡對token加鹽以後做Md5加密處理以後做的別名。我們專案不涉及到加標籤tag的需求,所以我這裡直接傳的null。
//2017.5.31 給極光設定別名 ym start String access_token = object.getString("access_token"); String alias = MD5Util.md5(access_token + Contants.Alias); LogUtil.e("ym", "極光別名:" + alias); JPushManager jPushManager = new JPushManager(ACT_Login.this); jPushManager.setAliasAndTags(alias, null); //2017.5.31 給極光設定別名 ym end
九. 清除別名
極光sdk文件上說,清除別名直接把別名設定成空串就行。但是一位大神親測說設定成空串的做法有的時候會清除別名失敗。建議設定成和自己別名差異很大的字元。如果你遇到把別名設定成空串,退出登入以後仍能接收到推送的情況,可以試試。
在退出登入成功的回撥中清除別名,這樣使用者退出登入以後就不會收到Push了。使用者再次登入的時候會重新設定別名。
//2017.6.2 清除極光推送的別名 ym start JPushManager jPushManager = new JPushManager(act); jPushManager.setAliasAndTags("*********(和別名區別很大的符合要求的字元)", null); //2017.6.2 清除極光推送的別名 ym end
sdk文件說明:
引數定義 alias null 此次呼叫不設定此值。(注:不是指的字串"null") "" (空字串)表示取消之前的設定。 每次呼叫設定有效的別名,覆蓋之前的設定。 有效的別名組成:字母(區分大小寫)、數字、下劃線、漢字、特殊字元(v2.1.6支援)@!#$&*+=.|。 限制:alias 命名長度限制為 40 位元組。(判斷長度需採用UTF-8編碼)
其他極光推送踩過的坑
1.之前專案裡遇到過Android 5.0的通知欄的圖示不顯示的Bug。
解決方案:若沒有res/drawable-xxxx/jpush_notification_icon這個資源預設使用應用圖示作為通知icon,在5.0以上系統將應用圖示作為statusbar icon可能顯示不正常,使用者可定義沒有陰影和漸變色的icon替換這個檔案,檔名不要變。
2.廣播接受者不走清單檔案中<category>中包名是否修改
<receiver android:name=".module.MyJPushReceiver" android:enabled="true" android:exported="false"> <intent-filter> <action android:name="cn.jpush.android.intent.REGISTRATION"/> <!-- Required 使用者註冊SDK的intent --> <action android:name="cn.jpush.android.intent.MESSAGE_RECEIVED"/> <!-- Required 使用者接收SDK訊息的intent --> <action android:name="cn.jpush.android.intent.NOTIFICATION_RECEIVED"/> <!-- Required 使用者接收SDK通知欄資訊的intent --> <action android:name="cn.jpush.android.intent.NOTIFICATION_OPENED"/> <!-- Required 使用者開啟自定義通知欄的intent --> <action android:name="cn.jpush.android.intent.NOTIFICATION_CLICK_ACTION"/> <action android:name="cn.jpush.android.intent.CONNECTION"/> <!-- 接收網路變化 連線/斷開 since 1.6.3 --> <category android:name="com.******"/> </intent-filter> </receiver>
3.sdk文件各種手機收不到通知的
由於第三方 ROM 的管理軟體需要使用者手動操作
小米【MIUI】
- 自啟動管理:需要把應用加到【自啟動管理】列表,否則殺程序或重新開機後進程無法開啟
- 通知欄設定:應用預設都是顯示通知欄通知,如果關閉,則收到通知也不會提示
- 網路助手:可以手動禁止已安裝的第三方程式訪問2G/3G和WIFI的網路和設定以後新安裝程式是否允許訪問2G/3G和WIFI的網路
- MIUI 7 神隱模式: 允許應用進行自定義配置模式,應用在後臺保持聯網可用,否則應用進入後臺時,應用無法正常接收訊息。【設定】下電量和效能中【神隱模式】
華為【Emotion】
- 自啟動管理:需要把應用加到【自啟動管理】列表,否則殺程序或重新開機後進程不會開啟,只能手動開啟應用
- 後臺應用保護:需要手動把應用加到此列表,否則裝置進入睡眠後會自動殺掉應用程序,只有手動開啟應用才能恢復執行
- 通知管理:應用狀態有三種:提示、允許、禁止。禁止應用則通知欄不會有任何提醒
魅族【Flyme】
- 自啟動管理:需要把應用加到【自啟動管理】列表,否則殺程序或重新開機後進程無法開啟
- 通知欄推送:關閉應用通知則收到訊息不會有任何展示
- 省電管理: 安全中心裡設定省電模式,在【待機耗電管理】中允許應用待機時,保持允許,否則手機休眠或者應用閒置一段時間,無法正常接收訊息。
VIVO【Funtouch OS】
- 記憶體一鍵清理:需要將應用加入【白名單】列表,否則系統自帶的“一鍵加速”,會殺掉程序
- 自啟動管理:需要將應用加入“i管家”中的【自啟動管理】列表,否則重啟手機後進程不會自啟。但強制手動殺程序,即使加了這個列表中,後續程序也無法自啟動。
OPPO【ColorOS】
- 凍結應用管理:需要將應用加入純淨後臺,否則鎖屏狀態下無法及時收到訊息
- 自啟動管理:將應用加入【自啟動管理】列表的同時,還需要到設定-應用程式-正在執行裡鎖定應用程序,否則殺程序或者開機後進程不會開啟,只能手動開啟應用
- 三星
- 記憶體一鍵優化:需要將應用加入【白名單】列表,否則系統記憶體優化後,會殺掉應用程序