咱們都曾羨慕別人,卻忘了,咱們也曾是別人羨慕的咱們。java
最近的任務吶,真是讓人蛋碎一地,各類被錘。android
不過比較 nice 的是,推送湊齊了,能夠整理一篇咯~json
點滴積累吧。緩存
跟着老大~bash
移動端發展到如今,各類推送 SDK 真的琳琅滿目,讓人看花了眼。app
這裏就挑我用過的幾個來作一個簡單對比,畢竟雞老大說了,連基本的論證對比都沒,你還玩個錘子(我瞎編的)。maven
下面從我我的關注的幾個維度進行簡單的對比 (❌:表明不支持,✅:表明支持。特殊狀況單獨註明):ide
類別 | 極光 | 友盟 | Mob |
---|---|---|---|
離線(廠商通道) | 免費服務不支持,高級版以及私有云支持(華爲、小米、vivo、OPPO、魅族、FCM) | 支持小米、華爲、魅族、OPPO、vivo系統級下發通道 | 支持華爲、小米、魅族、OPPO、vivo廠商級通道以及 FCM |
是否支持設置別名 | ✅ | ✅ | ✅ |
Flutter 支持 | ❌ | ❌ | ✅ |
對於小司而言,價格是一個重點,真的賊羨慕動不動就開通 VIP 或者 Pro 的小夥伴,酸了。測試
針對以上三種,我的以爲:gradle
有點茫然,明明看着 Mob 支持 FCM,可是官網上卻沒看到寫。
對了,今天偶然看到小夥伴對極光推送的一些討論:
好壞很少說,純技術分享,不涉及其餘東西,自行選擇吧。
沒轍,一分錢,難倒英雄漢!還好,哈哈哈。
因爲項目私密性,這裏就不放置對應的效果圖了。PS:其實我仍是蠻喜歡放個效果圖的,至少一上來就能看到效果,But 涉密,阿哦~
因爲我司帳號問題,沒法集入全部廠商,尷尬啊。
畢竟雞老大也說過,不對未接觸的事物發表任何意見。
因此這裏按照友盟所須要對應廠商資料進行依次註冊填入便可:
推薦幾個不錯的廠商推送指南:
圖忒多了,並且沒啥難點,按照集成對應平臺提供資料進行對應廠商註冊吧。
當初採用友盟緣由以下:
前期在友盟平臺建立當前應用之類的就不談了,注意推送 Android 版須要綁定包名。
關於友盟推送須要離線廠商推送,因此涉及到大部分的配置項,這裏我直接提取一個 gradle,避免主 gradle 各類雜亂不堪。
首先咱們在項目根目錄下添加友盟的遠程庫:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
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' }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
複製代碼
隨後在 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'
複製代碼
在 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
}
複製代碼
在 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.UmengNotifyClickActivity
import 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 集成推送已完成~
Google 爸爸 GCM 集成的真的是賊貼心,業界楷模啊。
我不吹,你本身瞧~
附上 FCM 地址:
須要注意的幾點:
首先不可避免的,建立項目:
這裏須要注意建立項目的一個規則:
按照要求輸入項目名稱,勾選接收條款:
添加 Google Analytics 分析:
第三步勾選對應的條款,完成項目建立:
建立期間還有個小進度,賊好看:
建立的速度很快:
進入首頁後,點擊 Android 圖標,開始 Android 接入/集成相關工做:
一共有以下四步:
固然 Google 也爲咱們提供了一鍵式的配置,可是尷尬的是,我嘗試失敗了,不過也算是一種方式,具體文章內容以下:
這裏爲了偷個懶,直接一張圖展現了:
在 app build 中完善下依賴:
// FCM
implementation '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>
複製代碼
固然還有一些可修改的內容,例如:
我是直接採用默認的了。這裏官網找到的,貼出來,避免小夥伴有需求還的找。
<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 接入推送,不得不說 Mob 作的賊優秀,直接 Flutter 插件搞起,大大的方便了 Flutter 開發者,先比個當心心~ ❤️
附上 Mob 插件地址:
以及對應 Flutter 的集成指南:
Mob 的文檔,真的是良心,集成賊簡單,入手超級方便,一塊兒來看。
首先,根目錄下的 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 推送的相關配置:
代碼以下:
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.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity : FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine)
}
}
複製代碼
最後就是對於初始化 Mob 以及接受到 Mob 消息推送如何處理了,蠻簡單的,這裏說下幾個點吧:
如下是部分代碼,僅供參考:
/// 目前僅支持 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) {}
複製代碼
本文內容較多,主要是整理前段時間遇到的問題,其實也不算啥問題吧,主要各類帳號前期準備不足,後期產品調整頻繁致使。
基本都附上了源碼。
菜雞一枚,歡迎各位大佬指正~