经过漫长的无所事事,终于来了一个活,要搞推送,不能socket,要后台关闭了也能推。
第三方推送,厂商自带,各种看了一下,但最终产品敲定,用百度云推送
研究的过程都是千篇一律,下demo,看文档,测试。
主要记录下各厂商的配置过程,以免后续重新配置的时候有遗漏
(厂商通道目前只配置了华为,因为莫得手机)
百度云基础推送
(是百度云推送不是智能云):
- 百度云创建应用的包名问题
比较坑一点的是它创建了不能修改包名和删除这个项目。后续要加上厂商,包名要独特一点,因为所有申请的包名需要一致,且各个平台内部都不允许重复,我一开始测试的时候搞了一个随意的包名,百度云是通过了,但华为那边就表示包名已存在不允许申请了,然后这一个就只能搁浅了。这里会获取到apikey
- jar包导入
demo里的jar包导入,只实现百度云推送的话,只需要 pushservice-x.x.x.jar包并添加依赖
- so库
demo里的jniLibs复制到项目根module的main下
- AndroidManifest.xml配置
根据文档配置来,先去掉关于厂商的部分,没有什么问题
http://push.baidu.com/
1、权限配置
<!-- Push service 运行需要的权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<!-- Push service 运行的可选权限 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- 适配Android N系统必需的ContentProvider写权限声明,写权限包含应用包名-->
<uses-permission android:name="baidu.push.permission.WRITE_PUSHINFOPROVIDER.你的包名" />
<permission
android:name="baidu.push.permission.WRITE_PUSHINFOPROVIDER.你的包名"
android:protectionLevel="signature">
</permission>
<!-- Push service 运行需要的权限 END -->
组件注册
<!-- push必须的组件声明 -->
<!-- 用于接收系统消息以保证PushService正常运行 -->
<receiver android:name="com.baidu.android.pushservice.PushServiceReceiver"
android:process=":bdservice_v1" >
<intent-filter>
<action android:name="com.baidu.android.pushservice.action.notification.SHOW" />
<!-- 以下六项为可选的action声明,可大大提高service存活率和消息到达速度 -->
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="android.intent.action.MEDIA_MOUNTED" />
<action android:name="android.intent.action.USER_PRESENT" />
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
</intent-filter>
</receiver>
<!-- Push服务接收客户端发送的各种请求-->
<receiver android:name="com.baidu.android.pushservice.RegistrationReceiver"
android:process=":bdservice_v1" >
<intent-filter>
<action android:name="com.baidu.android.pushservice.action.METHOD" />
</intent-filter>
</receiver>
<service android:name="com.baidu.android.pushservice.PushService"
android:exported="true"
android:process=":bdservice_v1" >
<intent-filter >
<action android:name="com.baidu.android.pushservice.action.PUSH_SERVICE" />
</intent-filter>
</service>
<!-- 4.4版本新增的CommandService声明,提升小米和魅族手机上的实际推送到达率 -->
<service android:name="com.baidu.android.pushservice.CommandService"
android:exported="true" />
<!-- 适配Android N系统必需的ContentProvider声明,写权限包含应用包名-->
<provider
android:name="com.baidu.android.pushservice.PushInfoProvider"
android:authorities="你的包名.bdpush"
android:writePermission="baidu.push.permission.WRITE_PUSHINFOPROVIDER.你的包名"
android:protectionLevel = "signature"
android:exported="true"
android:process=":bdservice_v1" />
<!-- 可选声明, 提升push消息送达率 -->
<service
android:name="com.baidu.android.pushservice.job.PushJobService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:process=":bdservice_v1" />
<!-- push必须的组件声明 END -->
- 自定义类继承PushMessageReceiver
在没有配置厂商的时候,通知到达会通过PushMessageReceiver的OnNotificationArrived来,所以自定义一个MyPushMessageReceiver集成PushMessageReceiver,其他方法的说明参照文档或者demo
在AndroidManifest.xml配置该receiver,路径不一样的记得变换
<receiver android:name="你的路径.MyPushMessageReceiver">
<intent-filter>
<!-- 接收push消息 -->
<action android:name="com.baidu.android.pushservice.action.MESSAGE" />
<!-- 接收bind、setTags等method的返回结果-->
<action android:name="com.baidu.android.pushservice.action.RECEIVE" />
<!-- 接收通知点击事件,和通知自定义内容 -->
<action android:name="com.baidu.android.pushservice.action.notification.CLICK" />
</intent-filter>
</receiver>
- 初始化
主Activity的OnCreate初始化代码,至于apikey想要怎么储存怎么调用就是你的事了,这里的api_key记得改哈,千万要记得改呀
为了方便查看可以开个云推送调试,但debug的嘛,不用的时候记得关
PushManager.startWork(getApplicationContext(),PushConstants.LOGIN_TYPE_API_KEY,"你的百度云api_key");
PushSettings.enableDebugMode(true);//开启云推送调试
运行程序,MyPushMessageReceiver的onBind中,errorCode(即方法的第二个参数)为0,则可以用web发送推送信息了;如果errorCode为其他值,参照开发文档说明。顺便说一下,jar包的方法参数命明都非常的简略,var1,var2,s1,s2,i1,i2什么的,想看的明白还是要看文档或者demo(demo里使用到的方法参数都是非常正常的命名)
华为通道配置
:
(有的功能出现的问题不知道是不是因为加了厂商通道的缘故,因为有些功能我在加了华为通道之后才使用到的,在这遇到的就写这了)
- 华为平台申请项目和应用
按部就班,注册开发者,认证,选择push服务,创建项目并开通推送服务,记得开通推送服务,现在不开配置SHA256的时候也是要开的
- 创建应用获取agconnect-services.json
在项目中创建应用,包名和百度云中注册的一致,会获得一个agconnect-services.json文件,放在根module下。至此,重新进入项目可以看到华为的APP ID, API key 等等的数据。
- 配置SHA256
搞一个应用签名给这个应用,签名怎么搞我就不说了。通过控制台keytool -list -v -keystore xxx.jks(你的签名的路径),获取SHA256的值,复制到平台的SHA256证书指纹中,记得点输入框后面勾勾啊,不然不保存。
接下来就是代码中的华为配置
- AndroidManifest.xml配置,build.gradle配置
参考文档和demo,把华为部分的该加上的加上
1、AndroidManifest
上文自定义MyPushMessageReceiver的注册中加上
<!-- 使用华为代理功能必须声明,用于接收华为的透传 -->
<action android:name="com.huawei.android.push.intent.RECEIVE" />
组件注册(HmsPushPatchMessageService标红参考问题一)
<!-- 华为代理推送必需组件 -->
<activity
android:name="com.baidu.android.pushservice.hwproxy.HwNotifyActivity"
android:exported="true"
android:launchMode="singleTask"
android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="bdpush"
android:path="/hwnotify"
android:scheme="baidupush" />
</intent-filter>
</activity>
<!-- 华为HMS接入声明service -->
<service
android:name="com.baidu.android.pushservice.HmsPushPatchMessageService"
android:exported="false">
<intent-filter>
<action android:name="com.huawei.push.action.MESSAGING_EVENT" />
</intent-filter>
</service>
<!-- 华为代理推送必需组件 END -->
根module的build.gradle
apply plugin: 'com.huawei.agconnect'(这是Android Studio 4.0之前的写法,如果是4.0之后的,记得变换一下4.0后的写法)
项目的build.gradle配置华为HMS Core SDK的Maven仓地址,同时增加agcp配置
buildscript {
repositories {
google()
jcenter()
// 配置HMS Core SDK的Maven仓地址。有多个Maven仓记得把华为的放最后
maven {url 'https://developer.huawei.com/repo/'}
}
dependencies {
...
// 由于使用了agconnect-services.json,故增加agcp配置。
classpath 'com.huawei.agconnect:agcp:1.4.2.300'
}
}
allprojects {
repositories {
google()
jcenter()
// 配置HMS Core SDK的Maven仓地址。有多个Maven仓记得把华为的放最后
maven {url 'https://developer.huawei.com/repo/'}
}
}
- 百度云初始化部分加上华为代理的代码
// 开启华为代理,如需开启,请参考华为厂商接入文档
PushManager.enableHuaweiProxy(this, true);
// 初始化
PUSHPushManager.startWork(getApplicationContext(),PushConstants.LOGIN_TYPE_API_KEY,"你的百度云api_key");
- 到百度云应用配置中,配置上华为的appId,apiKey,apiSecret
按理说,至此可以运行并接收通知。然后我经历了问题一 和 问题二 ,才实现了通知的接收
问题一 已解决
AndroidManifest中,华为HMS接入声明service的HmsPushPatchMessageService无法正常引入标红,但是jar包里确实存在这个类
根据提示,我觉得可能是缺乏华为支持包,参考华为自己的步骤
https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/android-integrating-sdk-0000001050040084
我引入了最新的华为的依赖
implementation 'com.huawei.hms:push:5.1.1.301'
到这里实际上应该就可以接收了(这里说的接收包括离线推送和在线推送)
问题二 已解决
我遇到的第二问题是,获取通知推送失败,不管是在线的还是离线的,参考华为,我没有成功的获取华为token,token是否获取成功及查看在HmsPushPatchMessageService的onNewToken()中,可以继承下来打印出来看(继承的话记得把AndroidManifest中的HmsPushPatchMessageService也改下),故加上开启华为自动获取token,获取token成功,推送接收成功(但是我后来关闭自动获取token也可以,也不记得啥情况了,可能是当时测试的通知的延时过长让我以为没收到了吧)
// 开启华为代理,如需开启,请参考华为厂商接入文档
PushManager.enableHuaweiProxy(this, true);
//华为自动开启获取token,看情况要不要
//HmsMessaging.getInstance(getApplicationContext()).setAutoInitEnabled(true);
// 初始化
PUSHPushManager.startWork(getApplicationContext(),PushConstants.LOGIN_TYPE_API_KEY,"api_key");
问题三 未解决
通知推送存在时延,单独百度云的不会,纯华为厂商的也不会,就是百度云配置了华为厂商通道后,大部分时候推送都时延了,少则几秒,多则二十多秒,不知道为啥
问题四 未解决
存在多条通知未点击时会自动变成一个(百度云配置了华为厂商),变成 你有n条消息未读,没有办法实现不同通知不同跳转。原本只使用百度云的时候不会,华为自己推送也不会这样,猜测可能和百度云设置的华为接收有关,jar包里跳来跳去只发现一个
var6.notify(var3.mMsgId, 0, var11);
通知id固定为0,源码无法修改,无法测试,待后续有时间研究
问题五 已解决
华为推送,会识别内容,把认为不重要的通知自动分为静默通知,导致我,,,andorid 10的手机没打开通知栏看状态栏不显示,一直以为是哪里出了问题。。。
测试过程中推送内容请不要太随意,有失体验
问题六 未解决
为了避免APP被调用重复启动,我设置了主Activity android:alwaysRetainTaskState=”true”,确保在主Activity存活情况下直接打开应用,而不是一次次的从启动页开始。
为了指定点击通知打开指定页面可以通过高级设置的自定义行为设置。但由于我的应用不是开发应用,需要登录操作,就有一个很烦人了问题,自定义行为指定页面,会绕过我的登录操作直接打开指定页面,在应用未启动的时候我只希望它启动应用到登录就好了;不指定,应用原本在哪个页面就是哪个页面,也不符合产品需求,还没有看过服务端的代码,不知道有没有好的解决方案。
问题七 待研究
百度云推送时,正常点击通知栏,会调用我们最初自定义的MyPushMessageReceiver的onNotificationClicked方法,并打开应用
但是,我尝试它的高级设置后发现,如果我附加了字段发送,onNotificationClicked是调用了并获取到是附加字段数据,但在app未启动情况下,没有打开应用的操作。这里如果有需求则需要代码设置唤醒。目前问题六我在考虑能否通过判断应用是否启动来区分打开登录页和指定页,还没有找到有效的应用状态判断
同理,我附加字段,并自定义行为指定打开的页面,也不会调用onNotificationClicked了(自定义行为可以带传递参数),至于这种时候附加字段去哪里了,我还没测
————- 4.7更新 ————-
问题八 已解决
问题:报错com.huawei.hms.push.BaseException: arguments invalid
我一般为了检测华为是否获取token会log它的HmsPushPatchMessageService各种状态,今天新配置一个应用的时候发现onTokenError了,内容如上,但它的提示不够明确,我感觉步骤好像没漏什么,又不想一步步核对,发现华为它的HmsPushPatchMessageService的基类HmsMessageService其实是有自己输出日志的
那想要看错误具体是什么方面的,就可以直接去log “HmsMessageService”查看错误码,然后去对照文档就很明确了,
检查配置信息,是我漏了配置 apply plugin: ‘com.huawei.agconnect’