Android阿里云推送

一:推送消息和推送通知的区别:

通知:

发送后会在系统通知栏收到展现,同时响铃或振动提醒用户。(用户收到消息,系统处理为通知)

消息:

以透传的形式传递给客户端,无显示,发送后不会在系统通知栏展现,第三方应用后需要开发者写代码才能看到。(用户收到消息,自己处理成弹框还是通知等)

参考: 推送中的消息和通知的区别

二:透传?

参考:安卓推送技术手册——使用透传消息的正确姿势

目前的消息推送方式主要有两种:通知和透传。

透传即是透明传送,即传送网络无论传输业务如何,只负责将需要传送的业务传送到目的节点,同时保证传输的质量即可,而不对传输的业务进行处理。

透传消息,就是消息体格式及内容,对于传递的通道来说是不去过问的,通道只负责消息的传递,对消息不做任何处理,当客户端接收到透传消息后,由客户端自己来决定如何处理消息。正是因为透传消息可以自定义消息体,也可以自定义消息的展示方式及后续动作处理,所以弥补了通知栏消息的一些不足之处(通知栏消息是直接展示出来,相关的动作客户端无法捕获到)。

透传消息主要有如下几个方面的特点:

  1. 后台处理,用户无感知。
  2. 前台展示,提醒用户。
  3. 展示的多样化。

整个透传消息的流程如下:

根据个推提供的API接口或在个推开发者平台上推送透传消息,个推服务端接收到推送的消息后,不做任何处理,直接发送给目标用户。
当客户端SDK接收到透传消息后,以广播方式发送给客户端,客户端在配置的第三方BroadReceiver里接收到透传消息后进行处理。

透传消息的消息体,可以根据不同的需求传递不同的参数或格式。如传递一个简单的字符串,或传递一个Json字符串,里面根据需求传递需要的字段。

用户无感知的透传,如:更新相关信息,在主界面中相关栏位用红点标识进行弱提醒,推送一条命令用来检测用户是否有登录等。通知栏消息虽然方便的提醒用户,但也在一定程度上给用户带来了打扰,用户无感知的消息推送有时效果会更好。
用户有感知的透传:把透传消息处理成通知栏展示出来,提醒用户方便点击查看相关信息(如个人帐单信息),直接打开应用或跳转到指定的应用界面中(根据透传消息的相关参数来判断跳转到哪一个指定的界面,相关参数传递要打开的界面的类名或Intent即可)等。对于开发者,处理成通知栏的相关事件也是可以捕获的,如通知栏的展示、点击等事件都可以进行捕获,以方便进行后续的操作。

因透传消息可以自己处理成通知栏内容展示,所以通知栏的样式也可以根据需求来做对应的改变。在Android 4.4及以上的系统,通知栏可以是样式丰富的通知栏,放入图片和视频等;可以展示普通的通知,也可以展示多样化的通知。

三:阿里云推送的集成

注册阿里云账号–>注册APP–>配置APP的包名,获取Appkey & Secret

登录阿里云控制台,找到产品与服务–>全部–>云计算基础服务–>移动推送下的移动推送点击即可找到应用列表。

参考:

Android集成阿里云消息推送的方法步骤

Android SDK配置(V2.3.7及以下版本)

Android SDK 3.0配置

Ram界面:
@前面是账号,下一步输入密码。

这里我们采用了3.0.12的版本

下载sdk:

AndroidManifest配置

APPKey和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>  

权限

    
    <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"/>

AndroidManifest.xml配置

 
        
        <service
            android:name="com.alibaba.sdk.android.push.MsgService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.alibaba.sdk.android.push.NOTIFY_ACTION" />
            intent-filter>
        service>
        <service android:name="com.alibaba.sdk.android.push.channel.CheckService"
            android:process=":channel">
            <intent-filter>
                <action android:name="com.alibaba.sdk.android.push.CHECK_SERVICE" />
            intent-filter>
        service>
        <service android:name="com.taobao.accs.ChannelService"
            android:exported="true" android:process=":channel">
            <intent-filter>
                <action android:name="com.taobao.accs.intent.action.SERVICE"/>
            intent-filter>
        service>
        <service
            android:name="com.taobao.accs.ChannelService$KernelService"
            android:exported="false"
            android:process=":channel" >
        service>
        <service android:name="com.taobao.accs.data.MsgDistributeService"
            android:exported="true">
            <intent-filter>
                <action android:name="com.taobao.accs.intent.action.RECEIVE" />
            intent-filter>
        service>
        <receiver android:name="com.taobao.accs.EventReceiver"
            android:process=":channel">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            intent-filter>
            <intent-filter>
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
            intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_REMOVED"/>
                <data android:scheme="package"/>
            intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.USER_PRESENT"/>
            intent-filter>
        receiver>
        <receiver android:name="com.taobao.accs.ServiceReceiver"
            android:process=":channel">
            <intent-filter>
                <action android:name="com.taobao.accs.intent.action.COMMAND"/>
            intent-filter>
            <intent-filter>
                <action android:name="com.taobao.accs.intent.action.START_FROM_AGOO"/>
            intent-filter>
        receiver>
        <service android:name="org.android.agoo.accs.AgooService"
            android:exported="true" >
            <intent-filter>
                <action android:name="com.taobao.accs.intent.action.RECEIVE" />
            intent-filter>
        service>
        <service android:name="com.alibaba.sdk.android.push.AliyunPushIntentService"
            android:exported="true"
            >
            <intent-filter>
                <action android:name="org.agoo.android.intent.action.RECEIVE" />
            intent-filter>
        service>
        <receiver
            android:name="com.taobao.agoo.AgooCommondReceiver"
            android:process=":channel"
            android:exported="true" >
            <intent-filter>
                <action android:name="${applicationId}.intent.action.COMMAND" />
            intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_REMOVED" />
                <data android:scheme="package" />
            intent-filter>
        receiver>
        <service
            android:name="com.alibaba.sdk.android.push.channel.TaobaoRecvService"
            android:exported="true"
            android:process=":channel">
            <intent-filter>
                <action android:name="org.android.agoo.client.MessageReceiverService" />
            intent-filter>
        service>
        
        <service
            android:name="com.taobao.accs.internal.AccsJobService"
            android:permission="android.permission.BIND_JOB_SERVICE"
            android:process=":channel"/>
        
        <service android:name="com.alibaba.sdk.android.push.channel.KeepChannelService"
            android:permission="android.permission.BIND_JOB_SERVICE"
            android:process=":channel" />
        <receiver android:name="com.alibaba.sdk.android.push.SystemEventReceiver"
            android:process=":channel">
            <intent-filter>
                <action android:name="android.intent.action.MEDIA_MOUNTED"/>
                <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
                <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
            intent-filter>
        receiver>
        
        <activity
            android:name="com.alibaba.sdk.android.push.keeplive.PushExtActivity"
            android:configChanges="keyboardHidden|orientation|screenSize|navigation|keyboard"
            android:excludeFromRecents="true"
            android:exported="false"
            android:finishOnTaskLaunch="false"
            android:launchMode="singleInstance"
            android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
            android:process=":channel"
            >
        activity>

自定义接收器并配置接收器

       
        <receiver
            android:name=".receiver.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>

如果是从V2.3.7及以下版本升级到V3.0.0及以上版本的用户,需将改为,否则会接收不到推送。

自定义接收器:MyMessageReceiver

自定义receiver,通知可以不自定义通知框

必须有此类,不然收不到通知.

推送消息(透传)可以自定义通知栏,通过RemoteViews


/**
 * 用于阿里云接收推送的通知和消息
 */
public class MyMessageReceiver extends MessageReceiver {
    // 消息接收部分的LOG_TAG
    public static final String REC_TAG = "receiver";
    private int clickNotificationCode=100;

    /**
     * 推送通知的回调方法
     *
     * @param context
     * @param title
     * @param summary
     * @param extraMap
     */
    @Override
    public void onNotification(Context context, String title, String summary, Map extraMap) {
        // TODO 处理推送通知
        Log.e("MyMessageReceiver", "Receive notification, title: " + title + ", summary: " + summary + ", extraMap: " + extraMap);
    }

    /**
     * 推送消息(透传)的回调方法
     *
     * @param context
     * @param cPushMessage
     */
    @Override
    public void onMessage(Context context, CPushMessage cPushMessage) {
        Log.e("MyMessageReceiver", "onMessage, messageId: " + cPushMessage.getMessageId() + ", title: " + cPushMessage.getTitle() + ", content:" + cPushMessage.getContent());

        buildNotification(context, cPushMessage);
    }

    /**
     * 接受到对应消息后,消息的弹出处理
     */
    public void buildNotification(Context context, CPushMessage message) {
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
        RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.push_layout);
        remoteViews.setImageViewResource(R.id.custom_icon, R.drawable.ic_launcher);
        remoteViews.setTextViewText(R.id.tv_custom_title, message.getTitle());
        remoteViews.setTextViewText(R.id.tv_custom_content, message.getContent());
        remoteViews.setTextViewText(R.id.tv_custom_time, new SimpleDateFormat("HH:mm").format(new Date()));
        remoteViews.setTextColor(R.id.tv_custom_title, Color.parseColor("#000000"));
        remoteViews.setTextColor(R.id.tv_custom_content, Color.parseColor("#000000"));
        remoteViews.setTextColor(R.id.tv_custom_time, Color.parseColor("#000000"));
        Notification notification = new NotificationCompat.Builder(context)
                .setContent(remoteViews)
                .setContentTitle(message.getTitle())
                .setContentText(message.getContent())
                .setSmallIcon(R.drawable.ic_launcher)
                .setDefaults(Notification.DEFAULT_VIBRATE)
                .setPriority(Notification.PRIORITY_DEFAULT)
                .build();
        notification.flags = FLAG_AUTO_CANCEL;
        notification.contentIntent = buildClickContent(context, message);
        notification.deleteIntent = buildDeleteContent(context, message);
        notificationManager.notify(message.hashCode(), notification);
    }
    public PendingIntent buildClickContent(Context context, CPushMessage message) {
        Intent clickIntent = new Intent();
        clickIntent.setAction("your.notification.click.action");
        //添加其他数据
        clickIntent.putExtra("message key",  message);//将message放入intent中,方便通知自建通知的点击事件
        return PendingIntent.getService(context, clickNotificationCode, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    }
    public PendingIntent buildDeleteContent(Context context, CPushMessage message) {
        Intent deleteIntent = new Intent();
        deleteIntent.setAction("your.notification.delete.action");
        //添加其他数据
        deleteIntent.putExtra("message key",  message);//将message放入intent中,方便通知自建通知的点击事件
        return PendingIntent.getService(context, clickNotificationCode, deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    }

    /**
     * 从通知栏打开通知的扩展处理
     *
     * @param context
     * @param title
     * @param summary
     * @param extraMap
     */
    @Override
    public void onNotificationOpened(Context context, String title, String summary, String extraMap) {
        Log.e("MyMessageReceiver", "onNotificationOpened, title: " + title + ", summary: " + summary + ", extraMap:" + extraMap);
    }

    /**
     * 无动作通知点击回调。当在后台或阿里云控制台指定的通知动作为无逻辑跳转时,通知点击回调为onNotificationClickedWithNoAction而不是onNotificationOpened
     *
     * @param context
     * @param title
     * @param summary
     * @param extraMap
     */
    @Override
    protected void onNotificationClickedWithNoAction(Context context, String title, String summary, String extraMap) {
        Log.e("MyMessageReceiver", "onNotificationClickedWithNoAction, title: " + title + ", summary: " + summary + ", extraMap:" + extraMap);

        Log.e("111", "onNotificationReceivedInApp, title: " + title +
                ", summary: " + summary +
                ", extraMap:" + extraMap );
        //title: 000,
        // summary: sdsdsdddd发送方,
        // extraMap: {_ALIYUN_NOTIFICATION_ID_=745373}
    }

    /**
     * 应用处于前台时通知到达回调。注意:该方法仅对自定义样式通知有效,
     * 相关详情请参考https://help.aliyun.com/document_detail/30066.html?spm=5176.product30047.6.620.wjcC87#h3-3-4-basiccustompushnotification-api
     *
     * @param context
     * @param title
     * @param summary
     * @param extraMap
     * @param openType
     * @param openActivity
     * @param openUrl
     */
    @Override
    protected void onNotificationReceivedInApp(Context context, String title, String summary, Map extraMap, int openType, String openActivity, String openUrl) {
        Log.e("MyMessageReceiver", "onNotificationReceivedInApp, title: " + title + ", summary: " + summary + ", extraMap:" + extraMap + ", openType:" + openType + ", openActivity:" + openActivity + ", openUrl:" + openUrl);
        Log.e("666", "onNotificationReceivedInApp, title: " + title +
                ", summary: " + summary +
                ", extraMap:" + extraMap +
                ", openType:" + openType +
                ", openActivity:" + openActivity +
                ", openUrl:" + openUrl);


    }

    /**
     * 通知删除回调
     *
     * @param context
     * @param messageId
     */
    @Override
    protected void onNotificationRemoved(Context context, String messageId) {
        Log.e("MyMessageReceiver", "onNotificationRemoved");
    }
}

通知的自定义布局:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:paddingBottom="10dp"
    android:paddingLeft="15dp"
    android:paddingRight="15dp"
    android:paddingTop="10dp">

    <ImageView
        android:id="@+id/custom_icon"
        android:layout_width="45dp"
        android:layout_height="45dp"
        android:layout_gravity="center"
        android:src="@drawable/ic_launcher" />

    <LinearLayout
        android:id="@+id/custom_content"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginLeft="5dp"
        android:layout_weight="1"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tv_custom_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ellipsize="end"
            android:maxLines="1"
            android:text="标题1111111111111111"
            android:textSize="15sp" />

        <TextView
            android:id="@+id/tv_custom_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:ellipsize="end"
            android:maxLines="1"
            android:text="内容222222222222222222"
            android:textSize="14sp" />
    LinearLayout>

    <TextView
        android:id="@+id/tv_custom_time"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="12:59" />
LinearLayout>

MyApplication初始化:

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        initCloudChannel(this);
    }

    /**
     * 初始化云推送通道
     */
    private void initCloudChannel(Context applicationContext) {
        PushServiceFactory.init(applicationContext);
        CloudPushService pushService = PushServiceFactory.getCloudPushService();
        pushService.register(applicationContext, new CommonCallback() {
            @Override
            public void onSuccess(String response) {
                Log.e("111111", "onSuccess=======" + response);
            }

            @Override
            public void onFailed(String errorCode, String errorMessage) {
                Log.e("111111", "onFailed=======errorCode=" + errorCode);
                Log.e("111111", "onFailed=======errorMessage=" + errorMessage);

            }
        });

        String deviceId = pushService.getDeviceId();
        Log.e("111111", "devicedId=======" + deviceId);//2b10feffb40a45e082cbf182718652c3

//        MiPushRegister.register(applicationContext, "XIAOMI_ID", "XIAOMI_KEY"); // 初始化小米辅助推送
//        HuaWeiRegister.register(applicationContext); // 接入华为辅助推送
//        GcmRegister.register(applicationContext, "send_id", "application_id"); // 接入FCM/GCM初始化推送
    }

Proguard配置

-keepclasseswithmembernames class ** {
    native ;
}
-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.**

初始化错误:

errorcode:1105 -- errorMessage:网络连接不稳定或连接异常

errorcode:10207 -- errorMessage:无网络连接,请查看tag为awcn的error级别日志

在gradle中:

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.3"

    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
}

报错:

参考:移动推送Android SDK:出现“1105,网络不稳定或连接异常错误”或者“10207,无网络连接,请查看tag为awcn的error级别日志”怎么解决?

移动推送 OpenApi:Specified parameter AndroidOpenType is not valid.

Android推送通知打开类型的有四种:

点击通知后动作:APPLICATION
打开应用:ACTIVITY
打开URL:URL
无打开动作:NONE利用OpenApi设置通知打开动作时只能为APPLICATION ACTIVITY URL NONE中的一个,否则就会报Specified parameter AndroidOpenType is not valid

注意字母全是大写

阿里云推送基本概念

ak:Access Key
https://ak-console.aliyun.com/?spm=5176.doc55451.2.3.6Gi7Ab#/accesskey

短信服务:
https://dysms.console.aliyun.com/dysms.htm?spm=5176.2020520107.0.0.719a8383uQWpmQ#/account

PHP文档
https://help.aliyun.com/document_detail/48049.html

移动推送

提供从云端到移动终端的优质推送服务,支持Android和iOS平台的通知/消息的推送功能。
推送内容及模式

通知:
会自动在手机端弹出通知栏,用户可以打开或者清除通知栏。iOS的通知走APNs(苹果官方推送通知服务),android 走移动推送自己的通道。

注:iOS需app在后台运行下才会在通知栏弹出。

消息:
不会自动在通知栏弹出,会在app中提示消息的接收。iOS和android的消息都走移动推送自己的通道。

注:透传消息,即自定义消息。只负责消息的推送,不做任何处理。客户端在接收到消息后,需要自己去处理消息的展示方式或后续动作。 Android继承MessageReciever类的onMessage方法,iOS继承onMessageReceived方法。iOS的消息通道只有在app处于前台状态的情况下才处于激活状态。

推送方式

按设备号推送

在客户端调用getDeviceld获得设备号,再通过控制台/openapi接口推送。
按账号推送

在客户端调用bindAccount操作,传参账号为您自己业务的账号(如您的app用手机号登陆,可以用手机号来bindAccount),再通过控制台/openapi接口推送。
名词解释

推送

AppKey:
app在移动推送中的唯一标示。推送SDK初始化和调用openapi推送时需要,从推送控制台APP列表页的应用证书中获取。

AppSecret:
app的秘钥。推送SDK初始化时需要,从推送控制台APP列表页的应用证书中获取。

openapi推送

openapi推送即:可以不通过网页控制台发送,由后台来发送通知,比如PHP

accessKeyld和accessKeySecret:
阿里云用户使用云产品的openapi接口验权时需要,从阿里云官网控制台获取https://ak-console.aliyun.com/#/accesskey

responseld:
openapi推送请求返回ID(如需排查问题可告诉客户人员该ID)。

messageld:
某一次推送的消息ID。从控制台通知记录/消息记录中可以找到消息ID。

deviceld:
设备在推送的唯一标示。 32位,数字和小写字母组合,通过代码获取:Android:CloudPushService的getDeviceld方法,iOS:CloudPushSDK的getDeviceld方法。

deviceToken:
iOS设备在苹果中心注册时返回的64位设备标识符(iOS设备同时会有deviceld和deviceToken,请不要混淆)。

account:
给设备添加的账号,可以是任意您的业务需要的,一个设备只能添加一个account,account可以添加多个设备。

alias:
给设备添加的别名,可以是任意您的业务需要的,一个设备可以最多添加128个alias,一个alias可以最多添加128个设备。

tag:
给设备添加的标签,可以是任意您的业务需要的,一个appkey最多能绑定1万个tag,一个tag下绑定的设备没有限制。

你可能感兴趣的:(推送)