发送后会在系统通知栏收到展现,同时响铃或振动提醒用户。(用户收到消息,系统处理为通知)
以透传的形式传递给客户端,无显示,发送后不会在系统通知栏展现,第三方应用后需要开发者写代码才能看到。(用户收到消息,自己处理成弹框还是通知等)
参考: 推送中的消息和通知的区别
参考:安卓推送技术手册——使用透传消息的正确姿势
目前的消息推送方式主要有两种:通知和透传。
透传即是透明传送,即传送网络无论传输业务如何,只负责将需要传送的业务传送到目的节点,同时保证传输的质量即可,而不对传输的业务进行处理。
透传消息,就是消息体格式及内容,对于传递的通道来说是不去过问的,通道只负责消息的传递,对消息不做任何处理,当客户端接收到透传消息后,由客户端自己来决定如何处理消息。正是因为透传消息可以自定义消息体,也可以自定义消息的展示方式及后续动作处理,所以弥补了通知栏消息的一些不足之处(通知栏消息是直接展示出来,相关的动作客户端无法捕获到)。
根据个推提供的API接口或在个推开发者平台上推送透传消息,个推服务端接收到推送的消息后,不做任何处理,直接发送给目标用户。
当客户端SDK接收到透传消息后,以广播方式发送给客户端,客户端在配置的第三方BroadReceiver里接收到透传消息后进行处理。
透传消息的消息体,可以根据不同的需求传递不同的参数或格式。如传递一个简单的字符串,或传递一个Json字符串,里面根据需求传递需要的字段。
用户无感知的透传,如:更新相关信息,在主界面中相关栏位用红点标识进行弱提醒,推送一条命令用来检测用户是否有登录等。通知栏消息虽然方便的提醒用户,但也在一定程度上给用户带来了打扰,用户无感知的消息推送有时效果会更好。
用户有感知的透传:把透传消息处理成通知栏展示出来,提醒用户方便点击查看相关信息(如个人帐单信息),直接打开应用或跳转到指定的应用界面中(根据透传消息的相关参数来判断跳转到哪一个指定的界面,相关参数传递要打开的界面的类名或Intent即可)等。对于开发者,处理成通知栏的相关事件也是可以捕获的,如通知栏的展示、点击等事件都可以进行捕获,以方便进行后续的操作。
因透传消息可以自己处理成通知栏内容展示,所以通知栏的样式也可以根据需求来做对应的改变。在Android 4.4及以上的系统,通知栏可以是样式丰富的通知栏,放入图片和视频等;可以展示普通的通知,也可以展示多样化的通知。
登录阿里云控制台,找到产品与服务–>全部–>云计算基础服务–>移动推送下的移动推送点击即可找到应用列表。
参考:
Android集成阿里云消息推送的方法步骤
Android SDK配置(V2.3.7及以下版本)
Android SDK 3.0配置
Ram界面:
@前面是账号,下一步输入密码。
这里我们采用了3.0.12的版本
<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"/>
<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及以上版本的用户,需将改为,否则会接收不到推送。
自定义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>
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初始化推送
}
-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推送即:可以不通过网页控制台发送,由后台来发送通知,比如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下绑定的设备没有限制。