1. 程式人生 > >Android整合極光推送和踩過的坑(一)

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就不是靜態的了!但是同樣會導致記憶體洩露。但是恰恰下面這種是單例導致記憶體洩露最典型的例子。由於單例的靜態特性使得其生命週期跟應用的生命週期一樣長,所以如果使用不恰當的話,很容易造成記憶體洩漏。

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;
    }
當建立這個單例的時候,由於需要傳入一個Context,所以這個Context的生命週期的長短至關重要: 

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中加極光推送自定義的廣播接受者

<!--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-->
注意:記得修改包名,我直接複製的之前專案的,導致忘記修改包名,推送訊息就是不走MyJPushReceiver。敲打

八. 設定別名

在登入成功的回撥中設定別名,這裡用的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】

    • 凍結應用管理:需要將應用加入純淨後臺,否則鎖屏狀態下無法及時收到訊息
    • 自啟動管理:將應用加入【自啟動管理】列表的同時,還需要到設定-應用程式-正在執行裡鎖定應用程序,否則殺程序或者開機後進程不會開啟,只能手動開啟應用
  • 三星
    • 記憶體一鍵優化:需要將應用加入【白名單】列表,否則系統記憶體優化後,會殺掉應用程序