Android 集成阿里移动推送

1.android的推送一直饱受诟病,最近项目中需要用到推送。本来用的是极光推送,但是应用一旦被杀死推送便收不到。我跟boss说这是android的问题,不能做到ios那样百分百推送,但是boss说你看人家谁谁的应用我清理掉后台推送怎么还可以收到。最后经过网上的一通搜,查到了辅助通道推送。

2.什么是辅助通道推送,即集成品牌机的官方推送(华为、小米、OPPO)这样如果你的应用在这些手机上即使杀死APP照样可以收到通知,但是如果没有集成辅助通道推送那收到通知只能随缘了。

3.我集成了阿里的移动推送这里记录一下。毕竟不是专业做推送的就在我集成的当天,阿里的移动推送居然出问题了,IOS的通知延时高达3小时上新闻了。不管了android没受影响,关键是boss的手机是华为手机必须保证boss是手机能收到推送哈哈。

4.贴上阿里移动推送的官方链接:https://help.aliyun.com/document_detail/51056.html?spm=a2c4g.11174283.3.4.52eb6d16SpqQmM

5.建议使用maven快速集成简单方便。

(1).在Project根目录下build.gradle文件中配置maven库URL:

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

(2).在对应的module下的build.gradle文件中添加对应依赖。

android {
......
defaultConfig {
applicationId "com.xxx.xxx" //包名
......
ndk {
//选择要添加的对应cpu类型的.so库。
abiFilters 'armeabi', 'x86'
}
......
}
......
}
dependencies {
......
implementation 'com.aliyun.ams:alicloud-android-push:3.1.4'
......
}

注 : 如果在添加以上 abiFilter 配置之后android Studio出现以下提示(我是没有遇到):

NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin.
则在 Project 根目录的gradle.properties文件中添加:

android.useDeprecatedNdk=true

(3).在AndroidManifest文件中设置appKey,appSecret(注:这里有个坑在粘贴appsecret的时候多个空格注意要删掉!!!!):

<application android:name="*****">
<meta-data android:name="com.alibaba.app.appkey" android:value="*****"/>
<meta-data android:name="com.alibaba.app.appsecret" android:value="****"/>
</application>

(4).创建消息接收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">
<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>

(4).混淆配置

-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.**

(5).初始化阿里推送

首先通过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将会打印以下日志:
  1. 11-24 12:55:51.096 15235-15535/com.alibaba.xxxx D/YourApp﹕ init cloudchannel success
  • 确认cloudchannel初始化正常,在logcat日志中:输入awcn关键字:
  1. 11-24 12:53:51.036 15235-15556/com.alibaba.xxxx E/awcn﹕ |[seq:AWCN1_1] AUTH httpStatusCode: 200
  2. 11-24 12:53:51.036 15235-15556/com.alibaba.xxxx E/awcn﹕ |[seq:AWCN1_1] status:AUTH_SUCC
  • 确认DeviceId获取正常:在初始化成功后使用 cloudPushService.getDeviceId() 获取deviceId,应该能够成功获取。

  • 如果集成移动推送的过程中遇到了utdid冲突,可参考:阿里云-移动云产品SDK UTDID冲突解决方案
    (6).Android8.0及以上NotificationChannel机制
    在客户端创建自己的NotificationChannel,可参考下面代码

具体调用位置为:Application的onCreate,云推初始化前后都可以,可参考 Demo

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);
}

(7).集成辅助通道推送。

(1).目前阿里只有华为、小米、OPPO、谷歌上各自的开放平台开通推送服务配置到阿里的控制台。

辅助通道1.png

(2).添加辅助通道依赖。

dependencies {
compile 'com.aliyun.ams:alicloud-android-third-push:3.0.6@aar'
}
(3).如果集成了谷歌商店的推送的话需要额外的配置一下
dependencies {
......
compile ('com.google.firebase:firebase-messaging:9.6.1')
}
同时在AndroidManifest文件中添加如下配置:

<receiver
android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.taobao.taobao" />
</intent-filter>
</receiver>
<receiver
android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver"
android:exported="false" />
<service
android:name="com.alibaba.sdk.android.push.AgooFirebaseInstanceIDService"
android:exported="true" >
<intent-filter android:priority="-500" >
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service
android:name="com.alibaba.sdk.android.push.AgooFirebaseMessagingService"
android:exported="true" >
<intent-filter android:priority="-500" >
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>

(4).混淆配置。

小米通道

-keep class com.xiaomi.** {;}
-dontwarn com.xiaomi.
*

华为通道

-keep class com.huawei.** {;}
-dontwarn com.huawei.
*

GCM/FCM通道

-keep class com.google.firebase.{;}
-dontwarn com.google.firebase.
*

OPPO通道

-keep public class * extends android.app.Service

(5).初始化辅助通道。

将以下代码加入你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通道开发者平台获
(6).用指定的机型查看log是否集成成功。
华为通道初始化成功,可以看到以下日志:

11-11 22:21:33.671 30248-30324/com.xxx E/MPS:HuaWeiRegister: HuaWeiRegister checkDevice flag=true //确认是华为的手机
11-11 22:21:33.674 30248-30324/com.xxx E/MPS:HuaWeiRegister﹕ Register huawei push............ //开始注册华为手机
11-11 22:21:33.714 29643-30328/com.xxx E/MPS:HuaWeiRegister﹕ huawei register success,token = 08657430243125472000000411000001
小米通道初始化成功,可以看到以下日志:

12-09 22:20:39.710 19566-19566/com.xxx E/MPS:MiPushRegister: MiPushRegister checkDevice flag=true //确认是小米的手机
12-09 22:20:39.712 19566-19566/com.xxx E/MPS:MiPushRegister: Register mipush. //开始注册小米
12-09 22:20:40.596 19566-19733/com.xxx E/MPS:MiPushRegister: XiaoMi register success. //小米注册成功 regid=d//igwEhgBGCI2TG6lWqlCesc0I6xE1wUhNCBXQ8uNOi/dDZioYXVysbrVrvRmyEVPn9nWz92D28IzYbA1RzoGDyTzYZwXKfBHEQkrey4G8=
GCM/FCM通道初始化成功,可以看到以下日志:

05-19 19:18:44.530 19153-19177/com.xxx D/MPS:GcmRegister: token from register: eWIXLYCNP0Q:APA91bFUAgxj6XYf5okyoCBnRPw1UwITndzXrvPDgbdI2N44PYm17hFEBiNXNQJrJ8bOG_xjw3c3UPDAhzNMTLNjlAKcjUanKyLA6E3k4wEmgZuhgUT02UMmMvH2LVA1L2Z4-l-cT_Ug
收到小米通道下行的消息:(需要将sdk日志等级设置到DEBUG)

12-09 22:24:34.065 19566-25042/com.xxx D/MPS:MiPushReceiver: onReceiveMessage,msg=[{"f":262,"b":"{"content"\ ... ... ,"i":"f__-rnje3_OH74gE|VG0g3kwMnGADAGrXZku1FFW5"}]
收到GCM/FCM通道下发的消息:

05-19 19:20:04.900 19153-20391/com.alibaba.push2 D/MPS:GcmRegister: onReceiveMessage payload msg:[.

(7).该功能的使用需要接入推送辅助通道,确保使用最新的辅助通道扩展包,具体参考上文;

辅助弹窗送达的通知展示效果,和普通通知相同;
服务端指定辅助弹窗通道推送时,一定要指定通知点击后要打开的Activity,该Activity需继承自抽象类AndroidPopupActivity(MiPushSystemNotificationActivity已废弃,小米弹窗、华为弹窗、OPPO弹窗统一继承AndroidPopupActivity),否则无法获取到通知的相关信息,并且会影响通知到达率的统计;
AndroidPopupActivity中提供抽象方法onSysNoticeOpened(),实现该方法后可获取到辅助弹窗通知的标题、内容和额外参数,在通知点击时触发,原本的通知回调onNotification()和onNotificationOpened()不适用于辅助弹窗;
指定打开的托管弹窗Activity在AndroidManifest.xml中注册时需要声明属性:android:exported=true
注:AndroidPopupActivity 适合作为中间件,因为它继承自Activity扩展性差。点击弹窗回调onSysNoticeOpened()方法!!!
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);
}
}

另外对通知的标题长度限制是16个字符,但是我试了超过10个就不行了,不知道是不是服务端哪里设置的有问题暂时没解决。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容