手记 | Android MobPush 接入总结
Posted HLQ_Struggle
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手记 | Android MobPush 接入总结相关的知识,希望对你有一定的参考价值。
序
PS:这不仅仅是一篇简单 MobPush 接入总结,同时也会掺杂个人理解以及不成熟的想法。接入的本身很 easy,总要透过现象看本质,去深入了解其他的内容。
手记开始,记录项目点滴,一起加油~
上来还是简单叨叨几句,不吐不快。
推送的目的是什么?在地铁上我想了很多:
- 拉活,通过产品各种特性(活动)吸引用户点击使用,进一步验证产品思路、方向;
- 促进用户粘性,好比今天收到通知,鸡老大直播 ing,马不停蹄的点击进去开始膜拜;
- 重大事件通知与防范,科技的力量,在某些方面,总会统一战线,无时无刻提示风险以及加强警惕;
- 。。。
其实推送最终的目的,个人更大的感觉还是将用户进一步留存,无论采取任何方式方法。
而相比 ios 的推送,则 android 要痛苦的很多。Android 的开放性使其自身逐步发展壮大,同时开放性也衍生了国内各种厂商的定制化。各种 “系统” 层出不穷,百花齐放的场景也给 Android 开发小伙伴带来了很多兼容性的问题。iOS 只需要发送苹果服务器,然后进行后续处理 (个人理解),而 Android?这里特意搜索了下国内几大厂商的历史图:
瞧瞧,目前五大厂商赫然在目!!!我们再看看截止 2021 年国内手机出货量:
除了魅族暂时未上榜单,其余依旧坚挺。这里排除华为鸿蒙,这个不在这篇文章考虑范围内。
那么对于我们原生 Android 开发而言,如何处理,能达到最好的推送效果?我想那可能是依次对主流厂商进行兼容适配,但是同时也带来了成倍的接入工作。
较好的一点是,有困难,便有专业解决困难提供商。对于小公司而言,一键接入成型并且经过市场检验的三方推送服务便是上上策。而国内众多推送服务商,我们又该选择哪儿个?接着往下看~
Push 厂商对比
我一直都是小公司,小公司里面对于方案的选择,大部分是 直系领导 直接拍板决定,少部分是看 主程 更倾向于哪儿家就用哪儿家。
下面从我个人关注的几个维度进行极光、友盟、Mob、个推这四个厂商简单的对比吧。 (❌ 代表不支持,✅ 代表支持。特殊情况单独注明) (截止到 2021 年 8 月 10 日):
极光 | 友盟 | Mob | 个推 | |
---|---|---|---|---|
支持消息格式 | 通知栏通知、自定义消息(透传)、富媒体、本地通知 | 通知栏通知、自定义消息(透传)、本地通知 | 通知栏通知、自定义消息(透传)、本地通知 | 通知消息、自定义消息(透传)、分组对比 |
离线厂商通道支持 | 华为、小米、OPPO、vivo、魅族、华硕、FCM | 华为、小米、OPPO、vivo、魅族 | 华为、小米、魅族、OPPO、vivo | 小米、华为、OPPO、vivo、魅族、坚果、海信、索尼等 |
别名、标签支持 | ✅ | ✅ | ✅ | ✅ |
移除关联启动 | 需要开通 VIP | ❌ | ❌ | ❌ |
消息撤回 | ✅ | ✅ | ✅ | ✅ |
卸载统计 | 高级版支持 | ✅ | ✅ | ✅ |
支持平台 | Android、iOS、Windows Phone、QuickApp | Android、iOS、Flutter | Android、iOS、Flutter、Unity、javascript、Cocos2d-X | Android、iOS |
分析对比,找瞎眼,如果不对,欢迎拍砖~
上图中只是个人简单对比,部分详细内容未考虑,当然也包括默认支持服务端 Web 调用,例如每个厂商对某个功能特性支持是否完整,这里就不一一诉说了。
方案很多,各位按照自身需求进行对应接入即可,下面开始个人习惯的 MobPush 集成啦~
MobPush 集成
从下面官网进入,准备开始接入:
登录成功后选择工作台:
Mob 后台创建 App 信息
创建应用:
- 上传 Icon
- 填写 App 名称
随后选择「立即接入」:
这里选择 MobPush:
添加应用包名以及选择接入厂商通道:
接入指南:
1、合规处理
由于目前针对用户个人信息/数据进一步管控加强,首要保证 App 符合合规。这里根据 Mob 官方进行部分整理:
- 确保App有《隐私政策》,并且在用户首次启动App时就弹出《隐私政策》取得用户同意;
- 务必告知用户选择 MobSDK 服务,并在《隐私政策》中增加参考条款;
- 务必确保用户同意《隐私政策》之后,调用 MobSDK 提交隐私协议接口。
2、项目根目录 build 中添加 MobPush 依赖:
buildscript
repositories
// 配置Mob Maven库
maven
url "https://mvn.mob.com/android"
dependencies
// 集成MobPush
classpath "com.mob.sdk:MobSDK:2018.0319.1724"
3、app 下 build 中新增 Mob 插件和扩展:
这里建议单独提出一个 Mob gradle,避免后续维护混乱。
// 调用MobTech SDK
apply plugin: 'com.mob.sdk'
// 在 MobSDK 的扩展中注册 MobPush 的相关信息
MobSDK
appKey "appKey"
appSecret "appSecret"
MobPush
// 集成其他推送通道(可选)
devInfo
// 华为推送配置信息
HUAWEI
appId "华为的appid"
// 魅族推送配置信息
MEIZU
appId "魅族的appid"
appKey "魅族的appkey"
// 小米推送配置信息
XIAOMI
appId "小米的appid"
appKey "小米的appkey"
// FCM 推送通道配置
FCM
// 设置默认推送通知显示图标
iconRes "@mipmap/ic_launcher"
// OPPO 推送配置信息
OPPO
appKey "OPPO的appKey"
appSecret "OPPO的appSecret"
// VIVO 推送配置信息
VIVO
appId "应用对应的vivo appID"
appKey "应用对应的vivo appKey"
随后在主 app 下 build 文件中进行引用:
// 引入 Mob 配置
apply from: 'MobSettings.gradle'
4、gradle.properties 中配置隐私协议适配版本
# 设定 MobSDK 为隐私协议适配版本
MobSDK.spEdition=FP
5、添加混淆代码
这块可以按照实际需求进行对应 CV 即可~
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview
# public *;
#
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
# Mob 混淆代码
-keep class com.mob.***;
-dontwarn com.mob.**
#厂商的混淆规则
-keep class android.os.SystemProperties
-dontwarn android.os.SystemProperties
-keep class com.huawei.***;
-keep class com.meizu.***;
-keep class com.xiaomi.***;
-dontwarn com.huawei.**
-dontwarn com.meizu.**
-dontwarn com.xiaomi.**
-keepclasseswithmembernames class *
native <methods>;
-keepclasseswithmembers class *
public <init>(android.content.Context, android.util.AttributeSet);
-keepclasseswithmembers class *
public <init>(android.content.Context, android.util.AttributeSet, int);
-keepclassmembers class * extends android.app.Activity
public void *(android.view.View);
-keepclassmembers enum *
public static **[] values();
public static ** valueOf(java.lang.String);
-keep class * implements android.os.Parcelable
public static final android.os.Parcelable$Creator *;
-keep class com.huawei.hms.***;
-keep class com.meizu.cloud.***;
-keep class com.xiaomi.mipush.sdk.***;
-keep class org.apache.thrift.***;
-keep class com.google.** *;
-keep class com.coloros.** *;
-keep class com.mob.tools.* *;
-keep class com.mob.wrappers.* *;
-dontwarn com.mob.commons.**
-dontwarn com.mob.wrappers.**
-dontwarn com.huawei.hms.**
-dontwarn com.meizu.cloud.**
-dontwarn com.xiaomi.mipush.sdk.**
-dontwarn org.apache.thrift.**
-dontwarn com.google.**
-dontwarn com.coloros.**
-dontwarn com.vivo.push.**
-keep class com.vivo.push.***;
-keep class com.vivo.vms.***;
-keep class com.mob.pushsdk.plugins.vivo.PushVivoReceiver*;
-keep class com.meizu.cloud.pushsdk.MzPushMessageReceiver
public *;
-keep class com.mob.pushsdk.plugins.xiaomi.PushXiaoMiRevicer *;
-dontwarn com.xiaomi.push.**
#这是oppo的混淆规则
-keep public class * extends android.app.Service
-keep class com.heytap.msp.** *;
-keep class com.mob.pushsdk.plugins.oppo.** *;
6、番外
当然,也可以选择在 AndroidManifest 中选择开启 Debug 功能:
<!-- 开启日志调试功能 -->
<meta-data
android:name="com.mob.mobpush.debugLevel"
android:value="4" />
7、Test 一波,发个通知
在 Mob 后台选择发送一条通知测试下~
结果如下:
再 Test 一波,这次我们将应用回到后台,再来测试下。
那如果我们现在应用被杀了呢?再来测试下?
在这里明显可以观察到,当应用被杀(模拟用户非在线时刻),Mob 后台推送并没有及时下发客户端。而当用户再次打开 App 时,才能收到之前的推送。那么,如果我时隔几天后打开呢?消息的及时性又如何保证呢?当然,什么事情也不是绝对的。
那我们现在配置下华为厂商推送再试试?
8、华为厂商推送
这块较为简单,MobPush 写的也狠明确,按照要求进行操作就可以了。简单重复性的东西这里就不一一贴图了。
MobSettings 中填写对应的 appId:
// 调用MobTech SDK
apply plugin: 'com.mob.sdk'
// 在 MobSDK 的扩展中注册 MobPush 的相关信息
MobSDK
appKey "appKey"
appSecret "appSecret"
MobPush
// 集成其他推送通道(可选)
devInfo
// 华为推送配置信息
HUAWEI
appId "appId"
随后我们在 Mob 后台进行测试离线推送测试:
经过如上几个测试小 case,我想大家对于接入离线厂商的必要性不言而喻了吧。
其实对于这块,个人理解是:当 Mob 自有通道开启状态,也就是 App 在线时,Mob 后台通过 Mob 自有通道进行消息通知下发。而如果 Mob 通道被关闭,也就是 App 被杀死,这块我猜测可能是心跳包检测?说实话还真没去了解过。关闭时通过设备对应不同厂商通道进行消息下发。从而保证了消息下发并不依赖 App 是否存活,比较厂商(系统)通道,肯定不会被干死,从而进一步的保证了 App 的消息接受性。
其它厂商这里就不一一进行对接测试了,大家前提记得注册好相关厂商帐号,随后按照 MobPush 进行配置即可。
9、再来个指定用户推送并传递对应 key
首先在 App 获取注册 ID:
MobPush.getRegistrationId
Log.e("HLQ", "------> getRegistrationId $it")
随后获取到注册 ID 并设置 Mob 后台,接着选择自定义消息,并设置如下几个内容:
- content:This is content.
- hlqType:1
- hlqCode:666
对应的消息监听如下:
MobPush.addPushReceiver(object : MobPushReceiver
/**
* 接收到自定义消息(透传消息)
*/
override fun onCustomMessageReceive(
p0: Context?,
p1: MobPushCustomMessage?
)
Log.e(TAG, "----> onCustomMessageReceive $p1")
/**
* 接收到通知消息
*/
override fun onNotifyMessageReceive(
p0: Context?,
p1: MobPushNotifyMessage?
)
Log.e(TAG, "----> onNotifyMessageReceive $p1")
/**
* 通知被点击事件
*/
override fun onNotifyMessageOpenedReceive(
p0: Context?,
p1: MobPushNotifyMessage?
)
Log.e(TAG, "----> onNotifyMessageOpenedReceive $p1")
/**
* 标签操作回调
*/
override fun onTagsCallback(
p0: Context?,
p1: Array<out String>?,
p2: Int,
p3: Int
)
Log.e(TAG, "----> onTagsCallback $p1")
/**
* 别名操作回调
*/
override fun onAliasCallback(
p0: Context?,
p1: String?,
p2: Int,
p3: Int
)
Log.e(TAG, "----> onAliasCallback $p1")
)
当在 Mob 后台点击发送时,App 是没有显式通知的,而在回调接口中,则输出我们刚刚设置的内容:
onCustomMessageReceive
messageId=4bp6i0t0m5xnyia9ds,
content=This is content.,
offlineFlag=0,
extrasMap=hlqCode=666, hlqType=1,
pushData="hlqCode":"666","hlqType":"1",
channel=mobpush,
id=4bp6i0t0m5xnyia9ds,
timestamp=1629216359101
好咧,针对 MobPush 推送呢,代码部分到此结束了。大部分官方都有,就不充斥太多的重复性的代码段了。
MobPush 小结
从个人角度而言,每一次都需要有些收获,或者来说,把自己遇到的问题暴露出来,万一官方不好意思调整了呢?
O(∩_∩)O哈哈~
那就从以下几点,简单说说吧。
1、技术保障
周末的时候,出现 MobSDK 拉取不下来的情况,梯子、切换网络、热点,均无效。大周末本来不好意思打扰,结果直接拉群解决,虽然最后还是按照自己降低 gradle 版本处理,但是态度上让人觉得很不错。
周三的时候,中午特意给我反馈,说他们的技术测试正常,并提供了对应的测试 Demo。虽然因为工作原因没能认真看看,但是这个认真负责的态度,赞一波~
一句话,免费的东西,这就不错了。莫抬杠~
2、文档友好度
从 MobPush 的集成来看,如果前期准备工作都已完成(这里指的账号,我从来没遇到过账号准备齐全的,都是自己折腾去),在线推送集成很 Easy,似乎就是分分钟,Mob 后台创建应用,拷贝依赖到根 build,然后跟着官方继续拷贝,剩下就是根据产品进行必要的授权。
而后期厂商集成,相对折腾的点,个人感觉更多的是各个厂商折腾相关信息,开通相关服务。比如华为乱七八糟一大堆,还要下载文件。这块其实对于 Mob 后台配置较为简单,那个 key 之类的就好了,本地项目同理。
这里简单小总结下个人感观:
“文档简洁”.apply
便于接入
不便于获取详细日志情况,例如华为集成是否成功?
针对某些失败情况,未能提供更多的解决示例
官方文档更新较慢
关于第二点,这里我拿接入华为离线厂商推送举个例子:
以上两个链接是 MobPush 官方提供,但是我怎么能再接入的同时就了解到我华为渠道接入成功了呢?相关的说明请原谅我没找到。这里我随便找个正面示例:
其实针对文档友好度,个人觉得,最简单的方式就是让开发者能否最快速的接入所需要的功能?并且能对于接入内容,官方给出详细说明文档,好比怎么算成功失败了?我怎么能第一时间了解到这些?而不是需要个人实际发送通知测试,才能得出结论。(Mob 小哥哥别打我~ -_-)
关于这个文档更新这块,其实还是会导致人产生误区,简单举几个例子:
- 官方针对 MobSDK 依赖地址,集成文档是 https 打头,下载 SDK 却写着 http。虽然后续咨询官方,官方说都支持,但是还是上来给人产生误区的感觉。
- 目前个人测试看是根据配置的厂商渠道自动配置对应的厂商,有个疑问是,假设某天 MobPush 未能主动更新厂商或者开发者想自己替换呢?挺好奇这块的。
人呐,总想得到更多,O(∩_∩)O哈哈~
深入 SDK 稍微看看
整套集成下来,不知道大家注意到我们从始至终都没有调用过 init 方法,那么它在哪儿完成的初始化呢?
会不会是 ContentProvider?印象中此物调用时机介于 Application 的 attachBaseContext 和 onCreate 之间。
盲猜还是不如直接进入 SDK 瞅瞅~
深入 SDK,发现目前 Mob 提供了两种方式:
- MobApplication:onCreate() init
- ContentProvider:onCreate() init
反编译生成的 Apk,发生 Mob 将 application name 替换为 MobApplication,如下所示:
<application
android:name="com.mob.MobApplication" >
这里我不仅微笑一下,那如果我要是 application 继承 MobApplication 呢?还会给我替换么?
class BaseApplication : MobApplication()
override fun onCreate()
super.onCreate()
再次反编译 apk 查看下:
<application
android:name="com.hlq.mob.BaseApplication" >
也是,都继承了 MobApplication 还替换个锤锤?
还别说,这块动态替换还是蛮有意思的,比如说,我集成的过程并没有添加权限,那这些权限什么时候被注入的呢?
奇怪的是在 AndroidManifest 中也看到了上文说到的 ContentProvider:
<provider
android:name="com.mob.MobProvider"
android:exported="false"
android:multiprocess="true"
android:authorities="com.pwccn.klcore.com.mob.MobProvider" />
神奇…
期间还发现个比较 6 的操作:
- 当我配置文件中未配置渠道时,SDK 自动拉取 Mob 相关依赖;
- 而当我配置文件中只有华为时,SDK 自动拉取华为相关依赖。
这个操作很神奇啊,有没有老哥指导的点拨一下下那~
各种混淆,看的茫然,下次有机会再说吧~
Error
-
如果当前 AS 版本最新,并且 gradle 版本为 7.0 时,出现 MobSDK 拉取失败的情况,直接降低 gradle 版本即可。当然官方最后提供了同样 gradle 7.0 的 Demo,因为个人懒得原因就没有细细研究了。
-
针对厂商推送失败的情况,认真检查相关包名等是否按照官方要求配置。我这就坑了自己一把。再不行给官方丢个 Demo,让官方帮忙处理下。O(∩_∩)O哈哈~
THK
以上是关于手记 | Android MobPush 接入总结的主要内容,如果未能解决你的问题,请参考以下文章
Gradle 手记|记录我使用过的 build 基本配置(不断更新中。。。
Gradle 手记|记录我使用过的 build 基本配置(不断更新中。。。