阿里雲移動推送的接入和踩坑

近期由於業務需求,要換掉以前的推送,首先選擇了阿里雲推送,官方介紹阿里移動推送(Alibaba Cloud Mobile Push)是基於大數據的移動智能推送服務,幫助App快速集成移動推送的功能,在實現高效、精確、實時的移動推送的同時,極大地降低了開發成本。讓開發者最有效地與用戶保持連接,從而提高用戶活躍度、提高應用的留存率。那麼接下來我們就一起看看是如何接入的。

一. 在阿里雲後臺創建自己的App

具體的步驟請詳看阿里雲移動推送的技術文檔:阿里雲移動推送快速入門

打開阿里雲移動研發平臺EMAS控制檯,進行後面的操作

一、創建產品和應用

移動服務當前創建應用,需要兩步

  • (1)添加產品(產品是一個集合的概念,產品下包含iOS應用、Android應用);
  • (2)在產品處,點擊管理後,右上角點擊“創建應用”完成應用創建。

1、點擊頁面中的“添加產品”按鈕,即可創建一個新的產品

1

2、輸入產品的基本信息創建App時需要輸入產品的名稱,上傳產品圖標,選擇產品分類。

2

3、產品創建成功

App創建成功後,產品列表會多出一個產品,強烈建議您去配置app。

3

4、創建產品對應的應用

在產品列表頁面,點擊已經創建的產品按鈕,進入產品管理頁面。

4

5、在產品管理頁面,點擊添加應用圖標,創建應用(目前需要分端創建)。

5

  • (1)創建Android應用,並填寫APP名稱和PackageName

6

創建完成後,應用會出現在應用列表中:

7

 二. Android SDK 3.0配置

安卓sdk的配置,個人強烈建議採用Maven庫快速集成(遠程同步),本博客也將採用遠程快速集成。

1. 在Project根目錄下build.gradle文件中配置maven庫URL

    allprojects {
        repositories {
            jcenter()
            maven {
                url 'http://maven.aliyun.com/nexus/content/repositories/releases/'
            }
        }
    }

2. 在對應的app下的build.gradle文件中添加對應依賴

    android {
        ......
        defaultConfig {
            applicationId "com.xxx.xxx" //包名
            ......
            ndk {
                //選擇要添加的對應cpu類型的.so庫。
                abiFilters 'armeabi', 'x86'
            }
            ......
        }
        ......
    }
    dependencies {
        ......
        compile 'com.aliyun.ams:alicloud-android-push:3.1.4@aar'
        // 或(二選一)
        compile 'com.aliyun.ams:alicloud-android-push:3.1.4'


        compile 'com.aliyun.ams:alicloud-android-utils:1.1.3'
        compile 'com.aliyun.ams:alicloud-android-beacon:1.0.1'
        compile 'com.aliyun.ams:alicloud-android-ut:5.4.0'
      
        ......
    }

特別注意 : 如果在添加以上 abiFilter 配置之後android Studio出現以下提示:

    NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin.

則在 Project 根目錄的gradle.properties文件中添加:

android.useDeprecatedNdk=true

3. appKey, appSecret配置

在AndroidManifest文件中設置appKey,appSecret:

    <application android:name="*****">
        <meta-data android:name="com.alibaba.app.appkey" android:value="*****"/> <!-- 請填寫你自己的- appKey -->
        <meta-data android:name="com.alibaba.app.appsecret" android:value="****"/> <!-- 請填寫你自己的appSecret -->
    </application>

特別提示:com.alibaba.app.appkeycom.alibaba.app.appsecret爲您App的對應信息,在推送控制檯APP列表頁的應用證書中獲取。appkeyappsecret請務必寫在application標籤下,否則sdk會報找不到appkey錯誤。如果您是百川雲推送用戶,不能直接使用百川平臺的appKey和appSecret,需要登錄阿里雲移動推送控制檯,登錄賬號爲您的百川平臺賬號,並使用阿里雲平臺的appKeyappSecret

Permission權限配置:

    <!-- 阿里雲推送相關權限 -->
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.RESTART_PACKAGES" />
    <uses-permission android:name="android.permission.GET_TASKS" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.REORDER_TASKS" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

 4. 消息接收Receiver配置

創建消息接收Receiver,繼承自com.alibaba.sdk.android.push.MessageReceiver,並在對應回調中添加業務處理邏輯,可參考以下代碼:

    public class MyMessageReceiver extends MessageReceiver {
        // 消息接收部分的LOG_TAG
        public static final String REC_TAG = "receiver";
        @Override
        public void onNotification(Context context, String title, String summary, Map<String, String> extraMap) {
            // TODO 處理推送通知
            Log.e("MyMessageReceiver", "Receive notification, title: " + title + ", summary: " + summary + ", extraMap: " + extraMap);
        }
        @Override
        public void onMessage(Context context, CPushMessage cPushMessage) {
                Log.e("MyMessageReceiver", "onMessage, messageId: " + cPushMessage.getMessageId() + ", title: " + cPushMessage.getTitle() + ", content:" + cPushMessage.getContent());
        }
        @Override
        public void onNotificationOpened(Context context, String title, String summary, String extraMap) {
            Log.e("MyMessageReceiver", "onNotificationOpened, title: " + title + ", summary: " + summary + ", extraMap:" + extraMap);
        }
        @Override
        protected void onNotificationClickedWithNoAction(Context context, String title, String summary, String extraMap) {
            Log.e("MyMessageReceiver", "onNotificationClickedWithNoAction, title: " + title + ", summary: " + summary + ", extraMap:" + extraMap);
        }
        @Override
        protected void onNotificationReceivedInApp(Context context, String title, String summary, Map<String, String> extraMap, int openType, String openActivity, String openUrl) {
            Log.e("MyMessageReceiver", "onNotificationReceivedInApp, title: " + title + ", summary: " + summary + ", extraMap:" + extraMap + ", openType:" + openType + ", openActivity:" + openActivity + ", openUrl:" + openUrl);
        }
        @Override
        protected void onNotificationRemoved(Context context, String messageId) {
            Log.e("MyMessageReceiver", "onNotificationRemoved");
        }
    }

將該receiver添加到AndroidManifest.xml中(切不要忘記了)

    <!-- 消息接收監聽器 (用戶可自主擴展) -->
    <receiver
        android:name=".MyMessageReceiver"
        android:exported="false"> <!-- 爲保證receiver安全,建議設置不可導出,如需對其他應用開放可通過android:permission進行限制 -->
        <intent-filter>
            <action android:name="com.alibaba.push2.action.NOTIFICATION_OPENED" />
        </intent-filter>
        <intent-filter>
            <action android:name="com.alibaba.push2.action.NOTIFICATION_REMOVED" />
        </intent-filter>
        <intent-filter>
            <action android:name="com.alibaba.sdk.android.push.RECEIVE" />
        </intent-filter>
    </receiver>

如果是從V2.3.7及以下版本升級到V3.0.0及以上版本的用戶,需將<action android:name="org.agoo.android.intent.action.RECEIVE" />改爲<action android:name="com.alibaba.sdk.android.push.RECEIVE" />,否則會接收不到推送。

5. Proguard配置

    -keepclasseswithmembernames class ** {
        native <methods>;
    }
    -keepattributes Signature
    -keep class sun.misc.Unsafe { *; }
    -keep class com.taobao.** {*;}
    -keep class com.alibaba.** {*;}
    -keep class com.alipay.** {*;}
    -keep class com.ut.** {*;}
    -keep class com.ta.** {*;}
    -keep class anet.**{*;}
    -keep class anetwork.**{*;}
    -keep class org.android.spdy.**{*;}
    -keep class org.android.agoo.**{*;}
    -keep class android.os.**{*;}
    -dontwarn com.taobao.**
    -dontwarn com.alibaba.**
    -dontwarn com.alipay.**
    -dontwarn anet.**
    -dontwarn org.android.spdy.**
    -dontwarn org.android.agoo.**
    -dontwarn anetwork.**
    -dontwarn com.ut.**
    -dontwarn com.ta.**

6. 在應用中註冊和啓動移動推送

  • 首先通過PushServiceFactory獲取到CloudPushService,然後調用register()初始化並註冊雲推送通道,並確保Application上下文中進行初始化工作。
  • 請參照以下代碼段進行初始化:
    import android.app.Application;
    import android.content.Context;
    import android.util.Log;
    import com.alibaba.sdk.android.push.CloudPushService;
    import com.alibaba.sdk.android.push.CommonCallback;
    import com.alibaba.sdk.android.push.noonesdk.PushServiceFactory;
    public class MainApplication extends Application {
        private static final String TAG = "Init";
        @Override
        public void onCreate() {
            super.onCreate();
            initCloudChannel(this);
        }
        /**
         * 初始化雲推送通道
         * @param applicationContext
         */
        private void initCloudChannel(Context applicationContext) {
            PushServiceFactory.init(applicationContext);
            CloudPushService pushService = PushServiceFactory.getCloudPushService();
            pushService.register(applicationContext, new CommonCallback() {
                @Override
                public void onSuccess(String response) {
                    Log.d(TAG, "init cloudchannel success");
                }
                @Override
                public void onFailed(String errorCode, String errorMessage) {
                    Log.d(TAG, "init cloudchannel failed -- errorcode:" + errorCode + " -- errorMessage:" + errorMessage);
                }
            });
        }
    }

【注意】:

  • 移動推送的初始化必須在Application中,不能放到Activity中執行。移動推送在初始化過程中將啓動後臺進程channel,必須保證應用進程和channel進程都執行到推送初始化代碼。
  • 如果設備成功註冊,將回調callback.onSuccess()方法。
  • 但如果註冊服務器連接失敗,則調用callback.onFailed方法,並且自動進行重新註冊,直到onSuccess爲止。(重試規則會由網絡切換等時間自動觸發。)
  • 請在網絡通暢的情況下進行相關的初始化調試,如果網絡不通,或者App信息配置錯誤,在onFailed方法中,會有相應的錯誤碼返回,可參考錯誤處理

啓動正常確認方法:

  • 回調方法callback.onSuccess()被調用。以上文接入代碼爲例,logcat將會打印以下日誌:
11-24 12:55:51.096 15235-15535/com.alibaba.xxxx D/YourApp﹕ init cloudchannel success
  • 確認cloudchannel初始化正常,在logcat日誌中:輸入awcn關鍵字:
11-24 12:53:51.036 15235-15556/com.alibaba.xxxx E/awcn﹕ |[seq:AWCN1_1] AUTH httpStatusCode: 200
11-24 12:53:51.036 15235-15556/com.alibaba.xxxx E/awcn﹕ |[seq:AWCN1_1] status:AUTH_SUCC

以上就是阿里雲推送的創建、接入和sdk初始化的過程,做到這裏我們就可以阿里雲移動推送後臺發送測試推送了,但是在安卓8.0以上發現收不到推送,自8.0(API Level 26)起,Android 推出了NotificationChannel機制,旨在對通知進行分類管理。如果用戶App的targetSdkVersion大於等於26,且並未設置NotificaitonChannel,創建的通知是不會彈出的,所以我們要對8.0及其以上的設配設置NotificaitonChannel。

具體調用位置爲:Application的onCreate,雲推初始化前後都可以,具體代碼如下:

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
                // 通知渠道的id
                String id = "1";
                // 用戶可以看到的通知渠道的名字.
                CharSequence name = "notification channel";
                // 用戶可以看到的通知渠道的描述
                String description = "notification description";
                int importance = NotificationManager.IMPORTANCE_HIGH;
                NotificationChannel mChannel = new NotificationChannel(id, name, importance);
                // 配置通知渠道的屬性
                mChannel.setDescription(description);
                // 設置通知出現時的閃燈(如果 android 設備支持的話)
                mChannel.enableLights(true);
                mChannel.setLightColor(Color.RED);
                // 設置通知出現時的震動(如果 android 設備支持的話)
                mChannel.enableVibration(true);
                mChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
                //最後在notificationmanager中創建該通知渠道
                mNotificationManager.createNotificationChannel(mChannel);
            }

在服務端的話一定也要設置:

// 指定notificaitonchannel id
pushRequest.setAndroidNotificationChannel("1"); 

特別注意:利用阿里雲控制檯推送

使用阿里雲控制檯推送通知時,需要設置 “高級設置”,在最下面的 “Android8.0 特殊配置:” ,填寫 “通知通道:”,也就是上述客戶端註冊的 NotificationChannel 的 id,例如上述代碼中NotificationChannel 爲1,如下圖所示:image

 以上就是阿里雲的全部推送,那麼還有一個很致命的問題在這,目前谷歌的推送通道在大陸被牆了,一般的推送只能用service接收,並且app只能在啓動或者後臺的情況下收的到。當App進程被殺死後,推送是收不到的,那麼該如何解決這種問題呢?

目前市面上華爲、小米、oppo、vivo和魅族品牌佔據大陸手機市場前五,每個品牌的手機都有自己的推送渠道,以下我簡稱輔助渠道。也就是說當app的進程被殺死的情況下,我們可以通過廠商渠道來推送,這樣即使App不啓動也可以收到推送。

接下來我們一起來看一下輔助渠道的接入,不要走開,這個是關鍵點哦!!!!

一. 小米/華爲/OPPO系統推送支持

  • 輔助通道:移動推送針對小米、華爲設備管控較嚴的情況特意接入華爲,小米推送輔助通道以提高在華爲、小米設備上的到達率。移動推送優先選擇自有通道進行推送消息下發,只有在自有通道斷連時選擇輔助通道下發消息。當前輔助通道通過華爲、小米推送下發透傳消息,消息到達應用後經移動推送SDK處理後觸發onNotification,onMessage回調。小米、華爲推送在下發透傳消息時並不保證會拉起被殺死進程(相關機制可參考小米、華爲推送官網),所以輔助通道在進程被殺死情況下無法保證消息一定到達。
  • 輔助彈窗:輔助彈窗通過系統通道下發通知,可以在進程被殺死情況下推送成功。由於輔助彈窗通過在對應設備上推送通知實現,因而通過輔助彈窗下發的通知不會觸發onNotification回調。當前移動推送已接入小米、華爲、OPPO輔助彈窗。其中華爲彈窗到達率統計只覆蓋用戶點擊華爲彈窗推送通知的場景,未點擊部分暫未覆蓋;小米彈窗到達率統計覆蓋所有場景。

在對應的應用市場配置應用

  • 小米開放平臺 註冊你的App, 得到相應的小米AppID,小米AppKey,小米AppSecert。在控制檯應用配置設置你的小米AppSecert。(注意:最新的小米開放平臺是分開 push 功能的,需要在 push 功能區 開通/啓用 推送功能)。
  • 同理在 華爲開發者聯盟 註冊 App,應用審覈通過後,能夠得到華爲的AppID和AppSecert。在控制檯應用配置中設置你的華爲AppID和AppSecert。(注意:最新的華爲開放平臺是分開push功能的,需要在push功能區 開通/啓用 推送功能)

  • OPPO開放平臺 註冊OPPO企業開發者賬號,添加應用並開通oppo推送服務,目前應用需滿足:1.在oppo市場上架,2.評級爲A,才能使用推送服務,具體政策可諮詢oppo客服。同樣需要在控制檯應用配置設置你的OppoAppkey和OppoMasterSecret(AppServerSecret )。

  • 應用配置

     

 二. 依賴Maven集成

1. 項目頂層build.gradle中添加Maven倉庫地址:

    allprojects {
        repositories {
            maven {
                url 'http://maven.aliyun.com/nexus/content/repositories/releases/'
            }
        }
    }

2. gradle添加依賴:

    dependencies {
        compile 'com.aliyun.ams:alicloud-android-third-push:3.0.6@aar'
    }

需要特別注意的地方:oppo 通道 需使用 v3.0.6 版本,應用滿足:1、在 oppo 市場上架,2、評級爲 A.

3. Proguard配置

如果集成推送SDK的工程開啓代碼混淆,在Proguard配置的基礎上,需要添加以下輔助通道的Proguard配置。

    # 小米通道
    -keep class com.xiaomi.** {*;}
    -dontwarn com.xiaomi.**
    # 華爲通道
    -keep class com.huawei.** {*;}
    -dontwarn com.huawei.**
    # OPPO通道
    -keep public class * extends android.app.Service

4. 在應用中初始化輔助通道

將以下代碼加入你application.onCreate()方法中初始通道。注意:輔助通道註冊務必在Application中執行且放在推送SDK初始化代碼之後,否則可能導致輔助通道註冊失敗

    // 註冊方法會自動判斷是否支持小米系統推送,如不支持會跳過註冊。
    MiPushRegister.register(applicationContext, "小米AppID", "小米AppKey");
    // 註冊方法會自動判斷是否支持華爲系統推送,如不支持會跳過註冊。
    HuaWeiRegister.register(applicationContext);
    //GCM/FCM輔助通道註冊
    GcmRegister.register(this, sendId, applicationId); //sendId/applicationId爲步驟獲得的參數
    // OPPO通道註冊
    OppoRegister.register(applicationContext, appKey, appSecret); // appKey/appSecret在OPPO通道開發者平臺獲取

注意:1. 本方法會自動判斷是否支持小米系統推送,如不支持會跳過註冊。

          2. 如果控制檯配置了小米/華爲的信息,app需要加對應的jar包依賴,不然會有crash的風險。

          3. OPPO通道是否註冊成功, 可以通過過濾MPS:oppo關鍵字查看, 註冊成功會打印onRegister regid=****相關日誌, 否則檢 查參數是否正確填入;

          4. 客戶端接入完畢,服務端推送時如果設備無法收到推送,可先查看 移動推送Android SDK:Android輔助通道和彈窗排查步驟

接入輔助通道後,需要結合輔助彈窗來接收推送

1. 當前輔助彈窗已接入小米、華爲、OPPO(小米輔助彈窗:v2.3.0及以上支持;華爲輔助彈窗:v3.0.8及以上支持;OPPO輔助彈窗:v3.1.4及以上支持);

2. 當前華爲輔助彈窗僅支持Emotion UI(華爲定製ROM)4.1級以上版本的設備;

輔助彈窗在客戶端設置:

  • 輔助彈窗送達的通知展示效果,和普通通知相同;
  • 服務端指定輔助彈窗通道推送時,一定要指定通知點擊後要打開的Activity,該Activity需繼承自抽象類AndroidPopupActivityMiPushSystemNotificationActivity已廢棄,小米彈窗、華爲彈窗、OPPO彈窗統一繼承AndroidPopupActivity),否則無法獲取到通知的相關信息,並且會影響通知到達率的統計;
  • AndroidPopupActivity中提供抽象方法onSysNoticeOpened(),實現該方法後可獲取到輔助彈窗通知的標題內容額外參數,在通知點擊時觸發,原本的通知回調onNotification()onNotificationOpened()不適用於輔助彈窗;
  • 指定打開的託管彈窗Activity在AndroidManifest.xml中註冊時需要聲明屬性:android:exported=true

  • 接入如下所示:

    import com.alibaba.sdk.android.push.AndroidPopupActivity;
    public class PopupPushActivity extends AndroidPopupActivity {
        static final String TAG = "PopupPushActivity";
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
        }
        /**
         * 實現通知打開回調方法,獲取通知相關信息
         * @param title     標題
         * @param summary   內容
         * @param extMap    額外參數
         */
        @Override
        protected void onSysNoticeOpened(String title, String summary, Map<String, String> extMap) {
            Log.d("OnMiPushSysNoticeOpened, title: " + title + ", content: " + summary + ", extMap: " + extMap);
        }
    }

以上就是輔助通道和輔助彈窗的接入的全過程,需要特別的注意的是華爲的開發者聯盟裏push需要設置sha2和回調地址,這一條需要特別的注意。以上有不明白的小夥伴,可以評論留言諮詢。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章