vlambda博客
学习文章列表

集成推送那点事-友盟/Mob-Flutter/FCM

97

次推文


LZ-Says



我们都曾羡慕别人,却忘了,我们也曾是别人羡慕的我们。


推荐直接拉到底阅读原文~


前言


最近的任务呐,真是让人蛋碎一地,各种被锤。


不过比较 nice 的是,推送凑齐了,可以整理一篇咯~


点滴积累吧。


跟着老大~


前期调研


移动端发展到现在,各种推送 SDK 真的琳琅满目,让人看花了眼。


这里就挑我用过的几个来做一个简单对比,毕竟鸡老大说了,连基本的论证对比都没,你还玩个锤子(我瞎编的)。


下面从我个人关注的几个维度进行简单的对比 (❌:代表不支持,✅:代表支持。特殊情况单独注明):


集成推送那点事-友盟/Mob-Flutter/FCM


对于小司而言,价格是一个重点,真的贼羡慕动不动就开通 VIP 或者 Pro 的小伙伴,酸了。


针对以上三种,个人觉得:


  • 如果当前应用仅仅在线推送,极光、Mob、友盟都可以;

  • 如果当前应用仅仅支持国内而且还要支持离线推送,那么友盟以及 Mob 不二人选;

  • 如果土豪级别应用,又支持国外,那么直接极光 VIP/Pro 走起,一键式支持国内厂商以及 FCM 海外推送;

  • 反之,想支持海外,老老实实接入 FCM 吧。


有点茫然,明明看着 Mob 支持 FCM,但是官网上却没看到写。


对了,今天偶然看到小伙伴对极光推送的一些讨论:


集成推送那点事-友盟/Mob-Flutter/FCM


好坏不多说,纯技术分享,不涉及其他东西,自行选择吧。


没辙,一分钱,难倒英雄汉!还好,哈哈哈。


由于项目私密性,这里就不放置对应的效果图了。PS:其实我还是蛮喜欢放个效果图的,至少一上来就能看到效果,But 涉密,阿哦~


一、友盟厂商申请对应 key


由于我司账号问题,无法集入所有厂商,尴尬啊。


毕竟鸡老大也说过,不对未接触的事物发表任何意见。


所以这里按照友盟所需要对应厂商资料进行依次注册填入即可:


集成推送那点事-友盟/Mob-Flutter/FCM


推荐几个不错的厂商推送指南:


  • 友盟 - 厂商通道集成文档

  • Mob - 第三方厂商推送指南


图忒多了,而且没啥难点,按照集成对应平台提供资料进行对应厂商注册吧。


二、Android 原生集成 - 友盟 v6.0.5


当初采用友盟原因如下:


  • 支持厂商推送

  • 方便运营小伙伴直接友盟查看所有数据


1.1 添加友盟依赖


前期在友盟平台创建当前应用之类的就不谈了,注意推送 Android 版需要绑定包名。


关于友盟推送需要离线厂商推送,所以涉及到大部分的配置项,这里我直接提取一个 gradle,避免主 gradle 各种杂乱不堪。


首先我们在项目根目录下添加友盟的远程库:


buildscript { repositories { google() jcenter() // 这里 maven { url 'https://dl.bintray.com/umsdk/release' } } dependencies { // 。。。 }}

allprojects { repositories { flatDir { dirs 'libs' } google() jcenter() maven { url 'https://jitpack.io' } // 这里 maven { url 'https://dl.bintray.com/umsdk/release' } }


随后在 app 下创建友盟依赖的 gradle,这里注意由于我司开发者账号原因,并没能集成所有厂商:


dependencies {    // 友盟推送 // 基础组件库依赖(必须) Push 605 版本必须升级新版本 Common SDK implementation 'com.umeng.umsdk:common:2.2.2'    implementation 'com.umeng.umsdk:utdid:1.5.2' // 友盟 push 相关依赖(必须)    implementation 'com.umeng.umsdk:push:6.0.5' implementation 'com.umeng.umsdk:alicloud-httpdns:1.2.5' implementation 'com.umeng.umsdk:alicloud-utils:1.1.5'    implementation 'com.umeng.umsdk:alicloud_beacon:1.0.1' implementation 'com.umeng.umsdk:agoo-accs:3.3.8.8-open-fix2' implementation 'com.umeng.umsdk:agoo_networksdk:3.5.5' implementation 'com.umeng.umsdk:agoo_tlog:3.0.0.17'    implementation 'com.umeng.umsdk:agoo_tnet4android:3.1.14.9' // ====== 厂商集成 Start // 小米 Push 通道 implementation 'com.umeng.umsdk:xiaomi-push:3.7.0' implementation 'com.umeng.umsdk:xiaomi-umengaccs:1.1.4' // 华为 Push 通道 implementation 'com.umeng.umsdk:huawei-basetb:2.6.3.306' implementation 'com.umeng.umsdk:huawei-pushtb:2.6.3.306' implementation 'com.umeng.umsdk:huawei-umengaccs:1.2.4' // Oppo Push 通道 implementation 'com.umeng.umsdk:oppo-push:2.0.2' implementation 'com.umeng.umsdk:oppo-umengaccs:1.0.6'  // vivo Push 通道 implementation 'com.umeng.umsdk:vivo-push:2.3.5' implementation 'com.umeng.umsdk:vivo-umengaccs:1.1.0'}


最后在主 gradle 也就是 app 下的 gradle 添加对此依赖:


// 友盟推送apply from: 'UMeng_Push.gradle'


1.2 初始化友盟推送并设置通知栏点击动作


在 Application 中进行友盟推送的初始化以及点击通知栏后操作:


 private fun initUMengSettings() { // 初始化 SDK mContext?.let { UMConfigure.init( mContext, K_RELEASE_UMENG, it.getString(R.string.code_umeng), UMConfigure.DEVICE_TYPE_PHONE, K_UMENG_SECRET ) initUMengPush(it) } } /** * 初始化友盟消息推送 */ private fun initUMengPush(context: Context) { // 获取消息推送代理示例 val pushAgent = PushAgent.getInstance(context) // 注册推送服务,每次调用 register 方法都会回调该接口 pushAgent.register(mIUmengRegisterCallback) // 设置点击通知栏打开操作 pushAgent.notificationClickHandler = mNotificationClickHandler
initUMengPushSettings(pushAgent) } /** * 注册推送服务 */ private val mIUmengRegisterCallback = object : IUmengRegisterCallback { override fun onSuccess(deviceToken: String?) { pwcLog("-------> 注册成功:deviceToken:--------> $deviceToken") }
override fun onFailure(s: String?, s1: String?) { pwcLog("-------> 注册失败:s ---> $s ||| s1 ---> $s1") }    }
/** * 点击通知栏 后续操作 */ private val mNotificationClickHandler = object : UmengNotificationClickHandler() { /** * 处理用户点击通知栏消息 */ override fun dealWithCustomAction(context: Context?, uMessage: UMessage?) { super.dealWithCustomAction(context, uMessage) context ?: return uMessage ?: return // 后台接口传递过来的参数都在 map 中 val extraMap = uMessage.extra // 这里演示下获取俩个值 val openType = extraMap["type"] val openID = extraMap["id"] // 。。。 }
} /** * 推送基础信息配置 */ private fun initUMengPushSettings(pushAgent: PushAgent) { // 设置最多显示通知条数 参数 number 可以设置为 0~10 之间任意整数。当参数为 0 时,表示不合并通知; pushAgent.displayNotificationNumber = 0 // 设置客户端允许声音提醒 pushAgent.notificationPlaySound = MsgConstant.NOTIFICATION_PLAY_SDK_ENABLE // 设置客户端允许呼吸灯点亮 pushAgent.notificationPlayLights = MsgConstant.NOTIFICATION_PLAY_SDK_ENABLE // 设置客户端允许震动 pushAgent.notificationPlayVibrate = MsgConstant.NOTIFICATION_PLAY_SDK_ENABLE // 通知免打扰 SDK默认在“23:00”到“7:00”之间收到通知消息时不响铃,不振动,不闪灯 pushAgent.setNoDisturbMode(23, 0, 7, 0) // 设置冷却时间 避免一分钟内出现多条通知而被替换 pushAgent.muteDurationSeconds = 600 }


1.3 离线推送支持


在 Application 中对应初始化厂商通道即可:

/** * @author:heliquan * @date:2020-05-07 * @desc:厂商推送 */class PushSDKBizImpl : AppInterface {
private var mContext: Context? = null
override fun onCreate(knowledgeCore: KnowledgeCore) { if (mContext == null) { mContext = knowledgeCore.applicationContext } registerPush(knowledgeCore) }
private fun registerPush(knowledgeCore: KnowledgeCore) { // 小米 Push register        MiPushRegistar.register(mContext, K_XIAOMI_ID, K_XIAOMI_KEY) // 华为 Push register        HuaWeiRegister.register(knowledgeCore) // OPPO Push register        OppoRegister.register(mContext, K_OPPO_KEY, K_OPPO_SECRET) // Vivo Push register VivoRegister.register(mContext) } // 。。。}


很多时候我们都希望,即使用户当前未使用 App,或者说当前的 App 处于被杀死的状态,后台推送消息依然想被前台接收。


那么如果想实现离线推送,我们还要完善下面的一步:


import com.umeng.message.UmengNotifyClickActivityimport org.android.agoo.common.AgooConstants/** * @author HLQ_Struggle * @date 2020/5/7 * @desc * 小米、华为等对后台进程做了诸多限制。若使用一键清理,应用的channel进程被清除,将接收不到推送。通过接入托管弹窗功能,可有效防止以上情况,增加推送消息的送达率。 */class PushActivity : UmengNotifyClickActivity() {
    private val mSelfActivity = PushActivity@ this
override fun onMessage(intent: Intent?) { super.onMessage(intent) // 拿到数据 AgooConstants.MESSAGE_BODY 进行对应后续操作 val offlinePushBean = intent?.getStringExtra(AgooConstants.MESSAGE_BODY)?.let { GsonUtil.fromJson( it, // 这里需要将获取到的json再次进行格式化 object : TypeToken<OfflinePushBean>() { }) } // 例如我这里直接跳转启动页,然后慢慢跳转目标页 offlinePushBean?.extra?.let { val intent = Intent(mSelfActivity, SplashActivity::class.java) intent.putExtra(K_OFFLINE_PUSH_ID, it.id) intent.putExtra(K_OFFLINE_PUSH_TYPE, it.type) intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK startActivity(intent) finish() } }
}


当然 AndroidManifest 此 Activity 内容附上:


<activity android:name=".ui.activity.push.PushActivity" android:exported="true" android:launchMode="singleTask" android:theme="@style/FullScreenTransparentTheme" />


到此,友盟 Android 集成推送已完成~


三、Android 原生集成 - FCM


Google 爸爸 GCM 集成的真的是贼贴心,业界楷模啊。


我不吹,你自己瞧~



  • firebase.google.com/?hl=zh-cn


需要注意的几点:


  • 记得测试的时候,ke xue 上网,我之前就遇到这么一个情况,显示发送了,结果 App 收不到,最后才反应过来,没有 ke xue 上网。

  • 国内的手机一般没有 Google 全家桶,或者说 Google 服务,需要去豌豆荚中下载。


3.1 FCM 前期配置


首先不可避免的,创建项目:


集成推送那点事-友盟/Mob-Flutter/FCM


这里需要注意创建项目的一个规则:


  • 项目名称必须至少包含 4 个字符只能包含字母、数字、空格和以下字符:-!'"


按照要求输入项目名称,勾选接收条款:


集成推送那点事-友盟/Mob-Flutter/FCM


添加 Google Analytics 分析:


集成推送那点事-友盟/Mob-Flutter/FCM


第三步勾选对应的条款,完成项目创建:


集成推送那点事-友盟/Mob-Flutter/FCM


创建期间还有个小进度,贼好看:


集成推送那点事-友盟/Mob-Flutter/FCM


创建的速度很快:


集成推送那点事-友盟/Mob-Flutter/FCM


3.2 FCM 集成


进入首页后,点击 Android 图标,开始 Android 接入/集成相关工作:


集成推送那点事-友盟/Mob-Flutter/FCM


一共有如下四步:


第一步填写对应包名以及 SHA-1,反之我是都填了。


集成推送那点事-友盟/Mob-Flutter/FCM


第二步下载配置文件并拷贝到 app 目录下:


集成推送那点事-友盟/Mob-Flutter/FCM


第三步添加对应的 SDK


集成推送那点事-友盟/Mob-Flutter/FCM

集成推送那点事-友盟/Mob-Flutter/FCM


第四步运行验证,可忽略


集成推送那点事-友盟/Mob-Flutter/FCM


当然 Google 也为我们提供了一键式的配置,但是尴尬的是,我尝试失败了,不过也算是一种方式,具体文章内容如下:


  • 将 Firebase 添加到您的 Android 项目


这里为了偷个懒,直接一张图展示了:


集成推送那点事-友盟/Mob-Flutter/FCM


3.3 FCM 消息处理


在 app build 中完善下依赖:

// FCMimplementation 'com.google.firebase:firebase-analytics:17.4.4'// FCM Message 处理implementation 'com.google.firebase:firebase-messaging:20.2.2'// FCM Message 后台处理implementation 'com.google.firebase:firebase-messaging-directboot:20.2.2'


随后创建一个 Service 用于处理 FCM 消息,这里我直接采用了接收到 Google FCM 消息后手动创建一个通知:


/** * @author HLQ_Struggle * @date 2020/7/8 * @desc */class MyFirebaseMessagingService : FirebaseMessagingService() { /** * 处理 FCM 消息 */ override fun onMessageReceived(remoteMessage: RemoteMessage) { Log.d(TAG, "From: ${remoteMessage.from}")        // Check if message contains a data payload. if (remoteMessage.data.isNotEmpty()) { Log.e(TAG, "Message data payload: ${remoteMessage.data}") // 这里包含后台传递自定义的值            val remoteMessageMap = remoteMessage.data sendNotification( remoteMessageMap["type"].toString(), remoteMessageMap["title"].toString(), remoteMessageMap["content"].toString() ) }
remoteMessage.notification?.let { Log.e(TAG, "Message Notification Body: ${it.body}")        }
} /** * 令牌更新回调 FCM 没有设置别名这么一说 所以需要我们通过令牌的方式去指定推送 */ override fun onNewToken(token: String) { Log.d(TAG, "Refreshed token: $token") sendRegistrationToServer(token) } /** * 保存令牌 */ private fun sendRegistrationToServer(token: String?) { Log.d(TAG, "sendRegistrationTokenToServer($token)") } /** * Create and show a simple notification containing the received FCM message. * * @param messageBody FCM message body received. */    private fun sendNotification(type: String, title: String, content: String) { val intent = Intent(this, SplashActivity::class.java) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) val pendingIntent = PendingIntent.getActivity( this, 0 /* Request code */, intent, PendingIntent.FLAG_ONE_SHOT        ) val channelId = getString(R.string.default_notification_channel_id) val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) val notificationBuilder = NotificationCompat.Builder(this, channelId) .setSmallIcon(R.mipmap.ic_launcher_round) .setContentTitle(title) .setContentText(content) .setAutoCancel(true) .setSound(defaultSoundUri)            .setContentIntent(pendingIntent) val notificationManager =            getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager // Since android Oreo notification channel is needed. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( channelId, "Channel human readable title", NotificationManager.IMPORTANCE_DEFAULT ) notificationManager.createNotificationChannel(channel)        } notificationManager.notify(0 /* ID of notification */, notificationBuilder.build()) }
    companion object { private const val TAG = "MyFirebaseMsgService" }}


复制代码在 AndroidManifest 中 Service:


<service android:name=".service.MyFirebaseMessagingService" android:directBootAware="true" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter></service>


3.4 FCM 其它配置


当然还有一些可修改的内容,例如:


  • icon

  • notification_color


我是直接采用默认的了。这里官网找到的,贴出来,避免小伙伴有需求还的找。

 

 <meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/appicon" /> <meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/styleTitleOrange" /> <meta-data android:name="firebase_messaging_auto_init_enabled" android:value="false" /> <meta-data android:name="firebase_analytics_collection_enabled"        android:value="false" />


到此,FCM 完毕~


四、Flutter Android 集成 - Mob


此模块在厂商相关信息完善时,集成仅仅几分钟~


相对于 Flutter 接入推送,不得不说 Mob 做的贼优秀,直接 Flutter 插件搞起,大大的方便了 Flutter 开发者,先比个小心心~ ❤️



  • pub.dev/packages/mo…


以及对应 Flutter 的集成指南:


  • mob.com/wiki/detail…


Mob 的文档,真的是良心,集成贼简单,入手超级方便,一起来看。


2.1 添加 Mob 插件依赖


  • mobpush_plugin: ^1.1.5


2.2 配置 Android 基本环境


首先,根目录下的 build 文件添加如下:


dependencies { // 。。。 classpath 'com.mob.sdk:MobSDK:+'}


其次,app 下 build 文件添加对应的配置项,这里关于 Mob 的配置可单独提取一个 gradle 文件,这里当初为了实现而实现,就不抽离了。


导入插件:


apply plugin: 'com.android.application' // 一般项目自带有这个,所以这块的这个可以忽略apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"apply plugin: 'com.mob.sdk'


Mob 推送的相关配置:


  • 基础的 appKey 以及 appSecret

  • 厂商对应的 key 以及其它信息


代码如下:


MobSDK { appKey "Mob 提供的 App Key" appSecret "Mob 提供的 App Secret" // 配置MobPush MobPush { // 配置厂商推送(可选配置,不需要厂商推送可不配置,需要哪些厂商推送只需配置哪些厂商配置即可) devInfo { // 配置小米厂商推送 XIAOMI { appId "您的小米平台appId" appKey "您的小米平台appKey"            } // 配置华为厂商推送 HUAWEI { appId "您的华为平台appId"            } // 配置魅族厂商推送 MEIZU { appId "您的魅族平台appId" appKey "您的魅族平台appKey"            } // 配置FCM厂商推送 FCM { // 设置默认推送通知显示图标 iconRes "@mipmap/default_ic_launcher"            } // 配置 OPPO 厂商推送 OPPO { appKey "您的OPPO平台appKey" appSecret "您的OPPO平台appSecret"            } // 配置VIVO厂商推送 VIVO { appId "您的VIVO平台appId" appKey "您的VIVO平台appKey" } } }}


接着去 MainActivity 中注册下,一般也无需操作,我这里是之前写过一个通道,附上部分代码:


import io.flutter.embedding.android.FlutterActivityimport io.flutter.embedding.engine.FlutterEngineimport io.flutter.plugin.common.MethodCallimport io.flutter.plugin.common.MethodChannelimport io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity : FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) { GeneratedPluginRegistrant.registerWith(flutterEngine) }
}


最后就是对于初始化 Mob 以及接受到 Mob 消息推送如何处理了,蛮简单的,这里说下几个点吧:


  • 由于项目需求设置以用户名为别名,所以也涉及到了添加别名这个操作,而在这里则是本地维护了一个状态,避免多次设置重复别名;

  • 其次需求是接收到消息推送执行刷新操作,所以我在这里直接接收到推送消息后通过 eventBus 发送状态去执行数据更新操作了。


以下是部分代码,仅供参考:


 /// 目前仅支持 Android 端推送 void initMobPush() { getCacheValue(memberInfo).then((userCache) { MemberInfoBean memberInfoBean = memberInfoBeanFromJson(userCache); if (Platform.isAndroid) { // 设置隐私协议授权状态 MobpushPlugin.updatePrivacyPermissionStatus(true);
getCacheValue(pushAliaState).then((result) { LogUtil.e(" ===> 获取 Mob 注册状态"); if (result == null) { LogUtil.e(" ===> Mob 未注册 需要注册"); MobpushPlugin.setAlias(memberInfoBean.memberInfo.id) .then((Map<String, dynamic> map) { LogUtil.e(" ===> 设置 Mob 推送别名:-> res: ${map['res']} "); if (map['errorCode'] == '0') { // 注册成功 本地缓存状态 setCacheValue(bool, pushAliaState, true); } }); } }); // 添加推送回调 MobpushPlugin.addPushReceiver(_onEvent, _onError); } }); }
void _onEvent(Object event) { LogUtil.e(' 接收到消息内容:$event'); eventBus.fire(PushEvent(true)); }
void _onError(Object event) {}

End


本文内容较多,主要是整理前段时间遇到的问题,其实也不算啥问题吧,主要各种账号前期准备不足,后期产品调整频繁导致。


基本都附上了源码。


菜鸡一枚,欢迎各位大佬指正~


集成推送那点事-友盟/Mob-Flutter/FCM


Thanks


  • 极光推送

  • 友盟推送

  • Mob 推送 






欢迎各位关注

不定期发布

见证成长路

集成推送那点事-友盟/Mob-Flutter/FCM
集成推送那点事-友盟/Mob-Flutter/FCM





觉得不错,右下角点个好看呗~