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

javascript

97
java

次推文
android


LZ-Saysweb



咱們都曾羨慕別人,卻忘了,咱們也曾是別人羨慕的咱們。json


推薦直接拉到底閱讀原文~緩存


前言微信


最近的任務吶,真是讓人蛋碎一地,各類被錘。
app


不過比較 nice 的是,推送湊齊了,能夠整理一篇咯~maven


點滴積累吧。ide


跟着老大~


前期調研


移動端發展到如今,各類推送 SDK 真的琳琅滿目,讓人看花了眼。


這裏就挑我用過的幾個來作一個簡單對比,畢竟雞老大說了,連基本的論證對比都沒,你還玩個錘子(我瞎編的)。


下面從我我的關注的幾個維度進行簡單的對比 (❌:表明不支持,✅:表明支持。特殊狀況單獨註明):



對於小司而言,價格是一個重點,真的賊羨慕動不動就開通 VIP 或者 Pro 的小夥伴,酸了。


針對以上三種,我的以爲:


  • 若是當前應用僅僅在線推送,極光、Mob、友盟均可以;

  • 若是當前應用僅僅支持國內並且還要支持離線推送,那麼友盟以及 Mob 不二人選;

  • 若是土豪級別應用,又支持國外,那麼直接極光 VIP/Pro 走起,一鍵式支持國內廠商以及 FCM 海外推送;

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


有點茫然,明明看着 Mob 支持 FCM,可是官網上卻沒看到寫。


對了,今天偶然看到小夥伴對極光推送的一些討論:



好壞很少說,純技術分享,不涉及其餘東西,自行選擇吧。


沒轍,一分錢,難倒英雄漢!還好,哈哈哈。


因爲項目私密性,這裏就不放置對應的效果圖了。PS:其實我仍是蠻喜歡放個效果圖的,至少一上來就能看到效果,But 涉密,阿哦~


1、友盟廠商申請對應 key


因爲我司帳號問題,沒法集入全部廠商,尷尬啊。


畢竟雞老大也說過,不對未接觸的事物發表任何意見。


因此這裏按照友盟所須要對應廠商資料進行依次註冊填入便可:



推薦幾個不錯的廠商推送指南:


  • 友盟 - 廠商通道集成文檔

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


圖忒多了,並且沒啥難點,按照集成對應平臺提供資料進行對應廠商註冊吧。


2、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 集成推送已完成~


3、Android 原生集成 - FCM


Google 爸爸 GCM 集成的真的是賊貼心,業界楷模啊。


我不吹,你本身瞧~


附上 FCM 地址:


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


須要注意的幾點:


  • 記得測試的時候,ke xue 上網,我以前就遇到這麼一個狀況,顯示發送了,結果 App 收不到,最後才反應過來,沒有 ke xue 上網。

  • 國內的手機通常沒有 Google 全家桶,或者說 Google 服務,須要去豌豆莢中下載。


3.1 FCM 前期配置


首先不可避免的,建立項目:



這裏須要注意建立項目的一個規則:


  • 項目名稱必須至少包含 4 個字符只能包含字母、數字、空格和如下字符:-!'"


按照要求輸入項目名稱,勾選接收條款:



添加 Google Analytics 分析:



第三步勾選對應的條款,完成項目建立:



建立期間還有個小進度,賊好看:



建立的速度很快:



3.2 FCM 集成


進入首頁後,點擊 Android 圖標,開始 Android 接入/集成相關工做:



一共有以下四步:


第一步填寫對應包名以及 SHA-1,反之我是都填了。



第二步下載配置文件並拷貝到 app 目錄下:



第三步添加對應的 SDK



第四步運行驗證,可忽略



固然 Google 也爲咱們提供了一鍵式的配置,可是尷尬的是,我嘗試失敗了,不過也算是一種方式,具體文章內容以下:


  • 將 Firebase 添加到您的 Android 項目


這裏爲了偷個懶,直接一張圖展現了:



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 完畢~


4、Flutter Android 集成 - Mob


此模塊在廠商相關信息完善時,集成僅僅幾分鐘~


相對於 Flutter 接入推送,不得不說 Mob 作的賊優秀,直接 Flutter 插件搞起,大大的方便了 Flutter 開發者,先比個當心心~ ❤️


附上 Mob 插件地址:


  • 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


本文內容較多,主要是整理前段時間遇到的問題,其實也不算啥問題吧,主要各類帳號前期準備不足,後期產品調整頻繁致使。


基本都附上了源碼。


菜雞一枚,歡迎各位大佬指正~



Thanks


  • 極光推送

  • 友盟推送

  • Mob 推送 






歡迎各位關注

不按期發佈

見證成長路






以爲不錯,右下角點個好看唄~

本文分享自微信公衆號 - 賀利權(hlq_struggle)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索