0 前言

0.1 痛点:安卓推送通知无统一标准

安卓是开源的手机操作系统,各大手机硬件厂商都会在它的基础上定制自己的操作系统。

在中国,用户因为各种原因无法使用 Google 官方服务框架,所以,在中国使用的手机的安卓操作系统并没有统一的推送通知标准,不同品牌的手机都会使用自己定制的推送服务。这给安卓开发的机型适配带来了很大麻烦。

在一次安卓的项目开发过程中,我们的项目组使用了阿里云 emas 服务框架,它能比较好的解决安卓推送通知机型适配的问题,非常适合小项目的开发。

这篇文章我会简单介绍如何集成阿里云推送服务到安卓项目中。

0.2 开发环境概述

本文使用的环境:

  • Android Studio 2022.2.1
  • Android Gradle Plugin 版本 8.0.2
  • Gradle 版本 8.0 (8.0 版本与之前的版本语法有些不同,本文使用 8.0 语法)
  • 编译 sdk 版本:API 33, Android 13.0
  • 阿里云推送通知版本:3.8.2
  • Java 版本:Java 8(本文使用 Java 语言)

注意:阿里云的官方文档有部分内容是过时的,其中过时的内容我在和阿里云相关开发人员确认后在本文中做了更新,如有与阿里云官方文档有不同的地方我会在文中标注。
本文写于 2023-05-30

0.3 知识准备

本文将会假设你已经了解:

  • 掌握基本的 Android 开发流程,以及如何使用 Android Studio
  • 了解基本的 Gradle 配置
  • 了解安卓的 Activity,Service 等基本概念
  • 基本的 Android 调试方法,例如断点和输出日志等
  • 了解发起 http 请求的基本方法

1 第一步:准备

1.1 阿里云 emas 和推送服务

本文略过如何开通阿里云并创建服务,你可以查看文档:

  • 如何开通 EMAS 服务:EMAS快速入门
  • 如何使用推送通知服务:推送通知服务快速入门

注意:推送通知是 EMAS 的一个子功能,你要先开通 EMAS 服务,然后再开通推送通知。服务开通后,再创建一个应用,然后获取 appkey 和 appsecret 。

1.2 注册厂商辅助通道

如果想实现当应用退出时,依然可以正常接受推送通知,你要注册厂商辅助通道。

为了简便,文章将以 Vivo 为例配置辅助通道,如果需要配置其他厂商,请查看文档,配置过程大同小异:辅助通道集成

注册 vivo 开发者平台,你可以查看这篇文档:vivo辅助通道集成

注意:如果要适配更多的手机型,则要注册所有的手机厂商。注册过程有点麻烦,注意预留足够时间。

2 第二步:集成 Android SDK

2.1 配置项目级 settings.gradle

...dependencyResolutionManagement {repositories {// 以下两个为阿里云 emas 项目仓库maven {url 'http://maven.aliyun.com/nexus/content/repositories/releases/'allowInsecureProtocol = true}maven {url "http://maven.aliyun.com/nexus/content/groups/public/"allowInsecureProtocol = true}...}
}
...

dependencyResolutionManagement 下的 repositories 中加入阿里云的源。

注意,Gradle 8.0 以前版本应使用项目级 build.gradle,在此本文不讨论。

2.2 配置模块级 build.gradle

dependencies {...// 推送通知依赖//主通道依赖implementation 'com.aliyun.ams:alicloud-android-push:3.8.2'//辅助通道基础依赖implementation 'com.aliyun.ams:alicloud-android-third-push:3.8.2'//vivo 辅助通道依赖implementation 'com.aliyun.ams:alicloud-android-third-push-vivo:3.8.2'
}

以上包括了阿里云原生通道和辅助通道。

配置完成后点击 sync ,看看是否可以同步成功。

3 第三步:实现推送通知接收类

3.1 MessageIntentService:接受应用内推送和后台推送

注意:阿里云官方配置文档中为 Receiver 类,但是官方更推荐 MessageIntentService,本文将按照推荐方法配置。

阿里云自有通道的消息接收类,当应用处于前台和后台时,类中方法会被调用。

创建一个 MessageIntentSerivce 类:

public class MessageIntentService extends AliyunMessageIntentService {private static final String TAG = "MessageIntentService";// 当应用在后台时,的推送通知方法@Overrideprotected void onNotification(Context context, String title, String summary, Map<String, String> extraMap) {Log.i(TAG,"收到一条推送通知 : " + title + ", summary:" + summary);}// 当应用在后台时:推送消息的回调方法@Overrideprotected void onMessage(Context context, CPushMessage cPushMessage) {Log.i(TAG,"收到一条推送消息 : " + cPushMessage.getTitle() + ", content:" + cPushMessage.getContent());}// 应用处于前台时,通知到达回调。注意:该方法仅对自定义样式通知有效@Overrideprotected void onNotificationReceivedInApp(Context context, String title, String summary, Map<String, String> extraMap, int openType, String openActivity, String openUrl) {}
}

3.2 PopupActivity:实现辅助通道推送接收类

如果应用已经关闭或者被系统杀死,自有通道无法接受消息,就要使用厂商辅助通道接收消息推送。

厂商辅助通道通知弹窗属于系统进程,并不属于某个 app。当用户点击通知时系统会根据通知内配置好的 Activity 跳转到某个 app 的 Activity。

根据文档,我们要在应用内定义一个 PopupActivity 用来接收辅助通道通知点击时的跳转事件。

public class PopupActivity extends AndroidPopupActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);}// 当系统通知被点击时调用的方法@Overrideprotected void onSysNoticeOpened(String title, String summary, Map<String, String> map) {}
}

4 第四步:调整应用清单,注册推送通知服务

我们选用在清单文件中管理配置,方便一些。

AndroidManifest.xml 中添加:

  • 阿里云推送通知服务 appid appkey
  • 各厂商辅助通道凭证
  • 注册 MessageIntentService
  • 注册 PopupActivity
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><application....tools:targetApi="31"></application>...<!--配置 appkey 和 appsecret--><meta-data android:name="com.alibaba.app.appkey" android:value="*****" /><meta-data android:name="com.alibaba.app.appsecret" android:value="*****" /><!--推送通知权限--><uses-permission android:name="android.permission.POST_NOTIFICATIONS" /><!--vivo 辅助通道配置--><meta-dataandroid:name="com.vivo.push.api_key"android:value="***" /><meta-dataandroid:name="com.vivo.push.app_id"android:value="***" /><!--MessageIntentService 服务注册,注意修改包名的路径--><serviceandroid:name="<你的包名>.MessageIntentService"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></service><!--注册辅助弹窗 Activity,注意修改路径--><activityandroid:name="<你的包名>.PopupActivity"android:exported="true"android:launchMode="singleInstance"><intent-filter><action android:name="android.intent.action.VIEW" /><category android:name="android.intent.category.DEFAULT" /><category android:name="android.intent.category.BROWSABLE" /><dataandroid:host="${applicationId}"android:path="/thirdpush"android:scheme="agoo" /></intent-filter></activity></manifest>

5 第五步:在 Application 类中启动 PushService

在 Application 的 onCreate() 函数中做几件事:

  • 启动 PushService 推送通知服务
  • 将推送通知注册到全局
  • 启动厂商辅助通道
  • 创建一个推送通知通道
  • 设置一个“自定义样式通知”

关于“推送通知通道”:自 Andorid API LEVEL 26 开始,安卓在显示通知时需要先定义推送通道,否则无法显示推送。文档:创建和管理通知渠道 | Android 开发者 | Android Developers

关于“自定义样式通知”:此项可选,如果想实现应用在前台时不弹出通知的话则需要配置。(详见本文 3.1)。

对自定义样式通知的说明: MessageReceiver/AliyunMessageIntentService相关接口:

通知在应用内到达回调

  • 当用户创建自定义通知样式,并且设置推送应用内到达不创建通知弹窗时调用该回调,且此时不调用onNotification回调(v2.3.3及以上版本支持)参数。

配置自定义通知样式文档:自定义通知样式

总结一下,当配置与不配置自定义样式通知时的效果:

  • 当配置时,如果通知到达时应用在前台,会回调 MessageIntentService.onNotificationReceivedInApp() ,不会调用 MessageIntentService.onNotification()
  • 未配置时,不论通知到达时是否在前台,都只会调用 MessageIntentService.onNotification()

回到正题,Application 源码:

public class MyApplication extends Application {@Overridepublic void onCreate(){...initCloudChannel(this);createNotificationChannel(this);}// 初始化阿里云推送通知服务private void initCloudChannel(Context applicationContext) {PushServiceFactory.init(applicationContext);CloudPushService pushService = PushServiceFactory.getCloudPushService();pushService.setLogLevel(CloudPushService.LOG_DEBUG);   //仅适用于Debug包,正式包不需要此行// 注册推送通知服务pushService.register(applicationContext, new CommonCallback() {@Overridepublic void onSuccess(String response) {Log.d(TAG, "推送通知初始化成功");}@Overridepublic void onFailed(String errorCode, String errorMessage) {Log.d(TAG, "推送通知初始化失败 -- errorcode:" + errorCode + " -- errorMessage:" + errorMessage);}});// 设置自定义通知样式(可选)BasicCustomPushNotification notification = new BasicCustomPushNotification();notification.setBuildWhenAppInForeground(false);CustomNotificationBuilder.getInstance().setCustomNotification(1, notification);// 设置 MessageIntentServicepushService.setPushIntentService(MessageIntentService.class);// 厂商辅助通道初始化VivoRegister.register(applicationContext);}// 创建一个推送通知通道 private void createNotificationChannel(Application app) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {NotificationManager mNotificationManager = (NotificationManager) app.getSystemService(Context.NOTIFICATION_SERVICE);// 通知通道的idString id = "1";// 用户可以看到的通知通道的名字.CharSequence name = "推送通知通道";// 用户可以看到的通知通道的描述String 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);}}
}

6 第六步:处理业务逻辑

到目前为止,我们有三种推送通知场景:

  • 通知到达时应用在前台:如果配置了自定义通知样式,则会回调 MessageIntentService.onNotificationReceivedInApp() 且不会弹出通知,如果未配置则会弹出通知并调用 MessageIntentService.onNotification()
  • 通知到达时应用在后台:通知会默认弹出,并调用 MessageIntentService.onNotification()
  • 通知到达时应用已关闭:用户点击通知后,会调用 PopupActivity.onSysNoticeOpened()

你可以根据不同的场景实现不同的回调函数,完成业务逻辑开发。

一种比较推荐的实现方式是在回调函数中发布广播(Broadcast)然后在 Activity 或者 Service 中侦听广播消息(使用 BroadcastReceiver)。

7 第七步:测试

现在,app 中的消息接收功能已经开发完毕,开始测试。

7.1 获取设备 id

每一个安卓设备会分配一个推送通知设备 id,可以在应用初始化后,用以下方法获取设备 id

PushServiceFactory.getCloudPushService().getDeviceId();

如果你想在应用初始化时将设备 id 输出到日志,你可以在 MyApplication 类的 onCreate() 方法中加入:

Log.i("Application", "DeviceId: " + PushServiceFactory.getCloudPushService().getDeviceId())

然后在应用启动后,就可以在日志中看到设备 id 了

7.2 发送测试推送通知

对照接口文档:批量推送接口

你可以使用阿里云自带的 API 调试工具(需要登录):MassPush_移动推送_API调试-阿里云OpenAPI开发者门户

根据我们实现的代码,在调试时使用的参数配置如下,注意以下所有参数都需要正确配置才能保证正常推送

基本配置:

  • androidOpenType: “ACTIVITY”(表示推送通知的打开方式为 ACTIVITY)
  • pushType: “NOTICE”(表示推送为通知)
  • deviceType: “ANDROID” (表示推送给安卓设备)
  • target: “DEVICE” (表示使用 设备id 向设备推送消息)
  • title: “自有通道标题” (推送通知的标题)
  • body: “自有通道内容” (推送通知的内容)
  • targetValue: “<你的 deviceId>” (表示给特定 deviceId 发送推送通知)

安卓设备配置参数:

  • androidNotificationChannel: “1” (使用的推送通道,我们已经在 Application 中定义)
  • androidActivity: “com.xxx.xxxxx.MainActivity” (指定一个当自有通道点击时跳转的 Activity)
  • androidVivoPushMode: “1” (vivo 推送模式,1 表示测试消息推送,vivo 要指定测试设备才可正常推送,可参考:vivo开放平台)
  • androidNotificationBarType: 1 (自定义通知样式编号,在代码里面我们定义为 1,见本文“第五步”)
  • androidExtParamters: “<自定义字典参数>” (这里可以携带自定义参数,在回调函数中可以获取到这些参数)

辅助通道配置参数:

  • androidPopupActivity: “com.xxx.xxxxx.PopupActivity” (指定我们之前写的 PopupActivity 类)
  • androidPopupTitle: “辅助通道标题” (辅助通道的标题,可以与 title 不同)
  • androidPopupBody: “辅助通道内容” (辅助通道内容,可以与 body 不同)

7.3 测试可能遇到的问题

如果发现 app 有日志输出,但是通知无法弹出,则请查看手机的设置中是否允许当前应用弹出通知。如果未授权,则开启相关的权限。

后记

安卓的推送通知功能异常复杂,在开发时建议大家预留足够的时间来配置、开发和测试。

希望本文能够帮助哪些正在为推送通知头疼的朋友们。

如果帮到你了,请为我点个赞谢谢!

手把手教你开发安卓推送通知服务(使用阿里云 emas)相关推荐

  1. wns服务器没有响应,如何使用 Windows 推送通知服务 (WNS) 进行验证(Windows 运行时应用)...

    如何使用 Windows 推送通知服务 (WNS) 进行验证(Windows 运行时应用) 12/11/2015 本文内容 [ 本文适用于编写 Windows 运行时应用的 Windows 8.x 和 ...

  2. iOS开发 - ANPs推送通知 标签: 推送通知ANPs远程推送、本地推送

    iOS开发 - ANPs推送通知 标签: 推送通知ANPs远程推送本地推送 2015-05-03 14:12 3510人阅读 评论(0) 收藏 举报 本文章已收录于:  iOS知识库  分类: [IO ...

  3. android自定义push通知_20个海外Web和App推送通知服务工具

    在App和网站中使用推送通知有不同的原因,并且在提高流量和与客户互动方面有很多好处.推送通知是一种交互式可点击消息,可将访问者直接引导至你的网站.它们可以帮助你以指数方式增加流量和参与率.因此,营销人 ...

  4. 苹果推送通知服务(APNs)编程(转)详细步骤

    iPhone 对于应用程序在后台运行有诸多限制(除非你越狱).因此,当用户切换到其他程序后,原先的程序无法保持运行状态.对于那些需要保持持续连接状态的应用程序(比如社区网络应用),将不能收到实时的信息 ...

  5. go gorilla_使用gorilla websocket构建浏览器推送通知服务的低级设计

    go gorilla Singhania AdityaSinghania Aditya Follow跟随 Aug 31 8月31 gopher leaving everyone awestruck w ...

  6. Windows Phone 7 不温不火学习之《推送通知服务》

    Windows Phone 中的 Microsoft Push Notification Service 向第三方开发人员提供了一个弹性,专注,而且持续的渠道,使得开发人员可以从Web Service ...

  7. Apple推送通知服务教程

    Apple推送通知服务教程 生成APP ID和SSL证书 登录iOS Provisioning Portal页面 首先,我们将要新建一个App ID. 每一个推送APP都需要一个唯一的对应的App I ...

  8. APPLE推送通知服务教程 PART-2

    原文地址:http://www.ityran.com/archives/281 本文由泰然翻译组出品,转载请注明出处! 翻译人员:jesse,TXX_糖炒小虾,无敌葫芦娃 校对:Iven 生成APP ...

  9. 推送通知服务【WP7学习札记之十三】

    为什么使用推送通知服务 Windows Phone执行模型决定只有一个第三方的应用程序可以在前台运行,应用程序不能再后台运行,不断的往Cloud拉数据.微软提供推送通知服务(Push Notifica ...

最新文章

  1. 架构师之路 — API 经济 — RESTful API
  2. 云端TensorFlow读取数据IO的高效方式
  3. Java 两线程交替打印奇偶数(一)
  4. 看动画学算法之:排序-插入排序
  5. jzoj3501-消息传递【换根法,树形dp】
  6. matlab figure 嵌套,操作Matlab的Figure窗口(一)
  7. Python gevent高并发(限制最大并发数、协程池)
  8. Linux进程共享通信 -- mmap实现
  9. lombok依赖_公司来了个新同事不会用 Lombok,还说我代码有问题
  10. c oracle 存储图片,用c语言如何读取和保存jpg图片文件?
  11. 王建宙称乔布斯故意展开TD-LTE版iPhone
  12. HashMap源码详解与对比
  13. 阿里P8架构师谈:如何搭建亿级并发系统的性能指标体系
  14. 数字图像处理(dip)
  15. c语言程序设计电子科技大学,C语言程序设计
  16. python get rect 函数_Pygame:如何正确使用get_rect()
  17. java opts tomcat,jvm初学篇-tomcat JAVA_OPTS配置
  18. unity3d Space Game太空射击游戏资源包
  19. 链表:递归中删除结点不发生断链
  20. [books] - SICP 2nd edition

热门文章

  1. 玉米秸秆粉碎还田机的设计
  2. Vue+SpringBoot进销存管理系统源码【源码免费分享】
  3. matlab三维点电荷电势图,Matlab模拟三维空间中点电荷的电势分布
  4. Ribbon源码3-负载均衡算法源码分析
  5. aix linux系统管理员,AIX Web-based System Manager(WSM) 图形化管理工具
  6. 为什么不建议直接使用 @Async 注解
  7. seo友情链接如何交换以及作弊方式
  8. 全网最全系统学习爬虫教程,用爬虫进行数据分析(bs4,xpath,正则表达式)
  9. Java每日练习3——给出一个月的总天数
  10. 【安全知识分享】安全文化与安全.ppt(附下载)