flutter消息推送客戶端集成方案詳解
一、背景
公司一個(gè)CRM APP項(xiàng)目是用Flutter寫的,根據(jù)業(yè)務(wù)要求,需要集成消息推送功能。所謂的消息推送就是系統(tǒng)會(huì)根據(jù)某些行為自動(dòng)推送信息,手機(jī)的通知欄會(huì)接收到信息,點(diǎn)擊可以打開app的某個(gè)指定頁面。

二、第三方消息推送——個(gè)推
為了追求效率,我們不打算從底層開始寫,而是挑選了第三方消息推送平臺(tái)——個(gè)推。所以這只是一個(gè)基于個(gè)推平臺(tái)的消息推送集成方案,僅供參考。
1、簡介
個(gè)推是一個(gè)數(shù)據(jù)智能服務(wù)商,不僅有消息推送服務(wù),還有用戶畫像、數(shù)據(jù)統(tǒng)計(jì)等服務(wù)。目前我們只使用了消息推送服務(wù).
2、注冊(cè)開通
要使用服務(wù),首先需要去個(gè)推官網(wǎng)進(jìn)行賬號(hào)注冊(cè)。
注冊(cè)完后可以新增應(yīng)用/服務(wù),選擇個(gè)推-消息推送。

新建應(yīng)用,填寫android和iOS包名

然后找到應(yīng)用管理,在操作菜單欄中選擇去集成。這里可以下載演示的DEMO進(jìn)行安裝。也可以直接根據(jù)提供的App Key 直接在項(xiàng)目中集成。


3、自定義消息推送——透?jìng)?/h3>
個(gè)推的消息推送分為“通知消息”和“消息透?jìng)?rdquo;。
通知消息:指定通知標(biāo)題和內(nèi)容后,由個(gè)推 SDK 自動(dòng)處理在系統(tǒng)通知欄中展示通知欄消息。
消息透?jìng)鳎杭醋远x消息,消息體格式客戶可以自己定義,如純文本、json 串等。透?jìng)飨€(gè)推只傳遞數(shù)據(jù),不做任何處理,客戶端接收到透?jìng)飨⒑笮枰约喝プ龊罄m(xù)動(dòng)作處理,如通知欄展示、彈框等。
我們選擇了消息透?jìng)鞯姆绞竭M(jìn)行開發(fā)。
三、項(xiàng)目集成
創(chuàng)建好個(gè)推消息推送服務(wù)后,就可以開始在項(xiàng)目中集成了
1、個(gè)推客戶端flutter插件
在flutter項(xiàng)目的pubspec.yaml文件中添加個(gè)推sdk依賴
getuiflut: ^0.2.13 #個(gè)推SDK
2、Android和IOS配置
1)Android
打開android/app/build.gradle 文件修改如下內(nèi)容
android {
// ...
defaultConfig {
manifestPlaceholders = [
//填寫你的個(gè)推應(yīng)用app id
GETUI_APPID: "H58mSiMN6L9zpMxmawsoP9",
]
}
}
dependencies: {
//個(gè)推SDK
implementation 'com.getui:gtsdk:3.2.11.0'
//個(gè)推核心組件
implementation 'com.getui:gtc:3.1.10.0'
}
2) iOS
啟用notification:xcode主工程配置 > Signing & Capabilities > +Push Noticifations

3、通知欄插件flutter_local_notifications
因?yàn)槭褂玫氖窍⑼競(jìng)?,通知欄的消息需要我們自己處理。這里推薦使用flutter_local_notifications,如果flutter 3x以上的版本,它同時(shí)支持macOS、linux的系統(tǒng)通知。 在flutter項(xiàng)目的pubspec.yaml文件中添加依賴
flutter_local_notifications: ^9.7.0 #本地推送
android需要在AndroidManifest.xml 添加 INTERNET 權(quán)限
<uses-permission android:name="android.permission.INTERNET" />
4、個(gè)推消息與通知欄整合
在flutter的main.dart加載個(gè)推的主入口
void main() {
// 個(gè)推管理初始化
GetuiflutManage();
// ...
}
創(chuàng)建getuiflut_manage.dart文件
import 'dart:io';
import 'package:crm_flutter/common/logger.dart';
import 'package:crm_flutter/common/notifications/getuiflut_handle.dart';
import 'package:getuiflut/getuiflut.dart';
/// 密鑰
const appId = 'aaaaaabbbbbccccccdddddd';
const appKey = 'aaaaaabbbbbccccccdddddd';
const appSecret = 'aaaaaabbbbbccccccdddddd';
/// 個(gè)推管理
class GetuiflutManage {
static final GetuiflutManage _internal = GetuiflutManage._();
factory GetuiflutManage() => _internal;
GetuiflutManage._() {
_initPlatform();
}
/// 客戶端id
String? get clientId => _clientId;
String? _clientId;
/// 初始化個(gè)推sdk
Future<void> _initGetuiSdk() async {
if (Platform.isIOS) {
Getuiflut().startSdk(
appId: appId,
appKey: appKey,
appSecret: appSecret,
);
}
if (Platform.isAndroid) {
try {
Getuiflut.initGetuiSdk;
} catch (e) {
e.toString();
}
}
getClientId();
}
/// 初始化
Future<void> _initPlatform() async {
_initGetuiSdk();
/// 監(jiān)聽本地推送通知內(nèi)容點(diǎn)擊
ln.selectNotification.listen((value) {
GetuiflutHandle.handleNavigate(value);
});
/// 個(gè)推事件處理
Getuiflut().addEventHandler(
onReceiveClientId: (String cid) async {
logger.debugPrint('cid: ${cid}');
_clientId = cid;
},
onReceiveMessageData: (Map<String, dynamic> msg) async {
logger.debugPrint("fonReceiveMessageData: $msg");
GetuiflutHandle.push(msg['payload']);
},
onReceivePayload: (Map<String, dynamic> message) async {
logger.debugPrint("flutter onReceivePayload: $message");
/// 離線則不再次發(fā)送
if (message['offLine']) return;
GetuiflutHandle.push(message['payloadMsg']);
},
onReceiveNotificationResponse: (Map<String, dynamic> message) async {
GetuiflutHandle.handleNavigate(message['payload']);
},
);
}
Future<void> getClientId() async {
try {
_clientId = await Getuiflut.getClientId;
logger.debugPrint('cid: ${_clientId}');
} catch (e) {
logger.debugPrint(e.toString());
}
}
}
創(chuàng)建getuiflut_handle.dart個(gè)推處理工具函數(shù)。
import 'dart:convert';
import 'package:crm_flutter/common/global.dart';
import 'package:crm_flutter/common/logger.dart';
import 'package:crm_flutter/common/notifications/clientid_bind.dart';
import 'package:crm_flutter/common/notifications/local_notifications.dart';
import 'package:crm_flutter/common/notifications/router_map.dart';
import 'package:crm_flutter/common/login/user_data_helper.dart';
import 'package:crm_flutter/psmb/model/push_payload_model.dart';
import 'package:crm_flutter/routes/routes.dart';
import 'package:flutter/material.dart';
/// 本地通知
final LocalNotifications ln = LocalNotifications();
/// 個(gè)推處理工具
class GetuiflutHandle {
/// 獲取實(shí)例
static PushPayloadModel payloadInstance(String value) {
Map<String, dynamic> payloadMap = json.decode(value);
return PushPayloadModel.fromJson(payloadMap);
}
/// 通知欄推送
static void push(String value) {
PushPayloadModel payload = GetuiflutHandle.payloadInstance(value);
/// 進(jìn)行本地消息推送
ln.send(
title: payload.aps?.alert?.title ?? '',
body: payload.aps?.alert?.body ?? '',
payload: value,
);
}
// ...
}
創(chuàng)建local_notifications.dart 文件
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:rxdart/subjects.dart';
/// 本地通知
class LocalNotifications {
static final FlutterLocalNotificationsPlugin np =
FlutterLocalNotificationsPlugin();
static final LocalNotifications _internal = LocalNotifications._();
factory LocalNotifications() => _internal;
final BehaviorSubject<String?> selectNotification =
BehaviorSubject<String?>();
LocalNotifications._() {
/// 安卓應(yīng)用通知顯示的圖標(biāo),注意android/app/src/main/res/drawable目錄
/// 添加對(duì)應(yīng)的app_icon.png圖標(biāo)文件
var android = const AndroidInitializationSettings('app_icon');
var ios = const IOSInitializationSettings();
np.initialize(InitializationSettings(android: android, iOS: ios),
onSelectNotification: (String? payload) async {
selectNotification.add(payload);
});
}
/// push消息
void send({
required String title,
required String body,
String? payload,
String channelId = '1',
String channelName = 'crm_psmb',
}) {
var androidDetails = AndroidNotificationDetails(channelId, channelName,
importance: Importance.max, priority: Priority.high);
var iosDetails = const IOSNotificationDetails();
var details = NotificationDetails(android: androidDetails, iOS: iosDetails);
np.show(
DateTime.now().millisecondsSinceEpoch >> 10,
title,
body,
details,
payload: payload,
);
}
}
最后
以上就是flutter消息推送客戶端集成方案。只要過程順利你現(xiàn)在已經(jīng)可以利用個(gè)推平臺(tái)進(jìn)行透?jìng)飨⑼扑土?。但這只是開始,我們?nèi)杂泻芏鄦栴}并未解決:
1、通知欄收到消息,點(diǎn)擊跳轉(zhuǎn)到目標(biāo)app頁面要如何處理?
2、安卓機(jī)子app離線了收不到消息怎么辦?
3、服務(wù)端如何集成個(gè)推?服務(wù)端如何精準(zhǔn)推送到目標(biāo)用戶?
以上就是flutter消息推送客戶端集成方案詳解的詳細(xì)內(nèi)容,更多關(guān)于flutter消息推送客戶端集成的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Arduino 數(shù)據(jù)類型轉(zhuǎn)換(單機(jī)片)詳細(xì)介紹
這篇文章主要介紹了Arduino 數(shù)據(jù)類型轉(zhuǎn)換(單機(jī)片)詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下2016-11-11
淺析Android中常見三種彈框在項(xiàng)目中的應(yīng)用
這篇文章主要介紹了淺析Android中常見三種彈框在項(xiàng)目中的應(yīng)用,需要的朋友可以參考下2017-03-03
Android自定義Drawable實(shí)現(xiàn)圓角效果
這篇文章主要為大家詳細(xì)介紹了Android自定義Drawable實(shí)現(xiàn)圓角效果,實(shí)現(xiàn)一個(gè)圓形和圓角的背景圖片效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
Android手勢(shì)密碼view學(xué)習(xí)筆記(二)
這篇文章主要為大家詳細(xì)介紹了Android手勢(shì)密碼view的第二篇學(xué)習(xí)筆記,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03
Android開發(fā)之資源文件用法實(shí)例總結(jié)
這篇文章主要介紹了Android開發(fā)之資源文件用法,結(jié)合實(shí)例形式總結(jié)分析了Android開發(fā)過程中針對(duì)資源文件的常見操作技巧,需要的朋友可以參考下2016-02-02
Android自定義控件實(shí)現(xiàn)下拉刷新效果
這篇文章主要為大家詳細(xì)介紹了Android自定義控件實(shí)現(xiàn)下拉刷新效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
Android自定義Chronometer實(shí)現(xiàn)短信驗(yàn)證碼秒表倒計(jì)時(shí)功能
這篇文章主要介紹了Android自定義ChronometerView實(shí)現(xiàn)類似秒表倒計(jì)時(shí),短信驗(yàn)證碼倒計(jì)時(shí)功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11

