flutter消息推送客户端集成方案详解
半点橘色 人气:0一、背景
公司一个CRM APP项目是用Flutter写的,根据业务要求,需要集成消息推送功能。所谓的消息推送就是系统会根据某些行为自动推送信息,手机的通知栏会接收到信息,点击可以打开app的某个指定页面。
二、第三方消息推送——个推
为了追求效率,我们不打算从底层开始写,而是挑选了第三方消息推送平台——个推。所以这只是一个基于个推平台的消息推送集成方案,仅供参考。
1、简介
个推是一个数据智能服务商,不仅有消息推送服务,还有用户画像、数据统计等服务。目前我们只使用了消息推送服务.
2、注册开通
要使用服务,首先需要去个推官网进行账号注册。
注册完后可以新增应用/服务,选择个推-消息推送。
新建应用,填写android和iOS包名
然后找到应用管理,在操作菜单栏中选择去集成。这里可以下载演示的DEMO进行安装。也可以直接根据提供的App Key 直接在项目中集成。
3、自定义消息推送——透传
个推的消息推送分为“通知消息”和“消息透传”。
通知消息:指定通知标题和内容后,由个推 SDK 自动处理在系统通知栏中展示通知栏消息。
消息透传:即自定义消息,消息体格式客户可以自己定义,如纯文本、json 串等。透传消息个推只传递数据,不做任何处理,客户端接收到透传消息后需要自己去做后续动作处理,如通知栏展示、弹框等。
我们选择了消息透传的方式进行开发。
三、项目集成
创建好个推消息推送服务后,就可以开始在项目中集成了
1、个推客户端flutter插件
在flutter项目的pubspec.yaml文件中添加个推sdk依赖
getuiflut: ^0.2.13 #个推SDK
2、Android和IOS配置
1)Android
打开android/app/build.gradle 文件修改如下内容
android { // ... defaultConfig { manifestPlaceholders = [ //填写你的个推应用app id GETUI_APPID: "H58mSiMN6L9zpMxmawsoP9", ] } } dependencies: { //个推SDK implementation 'com.getui:gtsdk:3.2.11.0' //个推核心组件 implementation 'com.getui:gtc:3.1.10.0' }
2) iOS
启用notification:xcode主工程配置 > Signing & Capabilities > +Push Noticifations
3、通知栏插件flutter_local_notifications
因为使用的是消息透传,通知栏的消息需要我们自己处理。这里推荐使用flutter_local_notifications
,如果flutter 3x以上的版本,它同时支持macOS、linux的系统通知。 在flutter项目的pubspec.yaml文件中添加依赖
flutter_local_notifications: ^9.7.0 #本地推送
android需要在AndroidManifest.xml 添加 INTERNET 权限
<uses-permission android:name="android.permission.INTERNET" />
4、个推消息与通知栏整合
在flutter的main.dart加载个推的主入口
void main() { // 个推管理初始化 GetuiflutManage(); // ... }
创建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'; /// 个推管理 class GetuiflutManage { static final GetuiflutManage _internal = GetuiflutManage._(); factory GetuiflutManage() => _internal; GetuiflutManage._() { _initPlatform(); } /// 客户端id String? get clientId => _clientId; String? _clientId; /// 初始化个推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(); /// 监听本地推送通知内容点击 ln.selectNotification.listen((value) { GetuiflutHandle.handleNavigate(value); }); /// 个推事件处理 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"); /// 离线则不再次发送 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()); } } }
创建getuiflut_handle.dart个推处理工具函数。
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(); /// 个推处理工具 class GetuiflutHandle { /// 获取实例 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); /// 进行本地消息推送 ln.send( title: payload.aps?.alert?.title ?? '', body: payload.aps?.alert?.body ?? '', payload: value, ); } // ... }
创建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._() { /// 安卓应用通知显示的图标,注意android/app/src/main/res/drawable目录 /// 添加对应的app_icon.png图标文件 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, ); } }
最后
加载全部内容