first commit
This commit is contained in:
735
basic_utils/basic_push.md
Normal file
735
basic_utils/basic_push.md
Normal file
@@ -0,0 +1,735 @@
|
||||
# Basic Push - 推送通知模块文档
|
||||
|
||||
## 模块概述
|
||||
|
||||
`basic_push` 是 OneApp 基础工具模块群中的推送通知核心模块,提供统一的推送消息接收、处理和分发功能。该模块集成了极光推送SDK、本地通知、事件总线、心跳管理等功能,支持iOS和Android平台的推送服务。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: basic_push
|
||||
- **模块路径**: oneapp_basic_utils/basic_push
|
||||
- **类型**: Flutter Package Module
|
||||
- **主要功能**: 推送消息接收、事件总线、本地通知、心跳管理
|
||||
|
||||
### 核心特性
|
||||
- **推送服务集成**: 集成极光推送SDK,支持远程推送消息
|
||||
- **事件总线系统**: 基于RxDart的事件发布订阅机制
|
||||
- **本地通知**: 支持本地通知的发送和管理
|
||||
- **心跳管理**: 前后台切换时的心跳上报机制
|
||||
- **用户绑定**: 用户登录后的推送设备绑定和解绑
|
||||
- **权限管理**: 推送权限检查和设置跳转
|
||||
- **多平台支持**: iOS和Android平台适配
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
basic_push/
|
||||
├── lib/
|
||||
│ ├── basic_push.dart # 模块入口文件
|
||||
│ └── src/
|
||||
│ ├── push_facade.dart # 推送门面服务
|
||||
│ ├── push_topic.dart # 主题定义
|
||||
│ ├── push_config.dart # 配置管理
|
||||
│ ├── constant.dart # 常量定义
|
||||
│ ├── connector.dart # 连接器
|
||||
│ ├── channel/ # 通道实现
|
||||
│ │ ├── core/
|
||||
│ │ │ └── i_push_channel.dart
|
||||
│ │ ├── push_channel.dart
|
||||
│ │ └── local_channel.dart
|
||||
│ ├── domain/ # 领域对象
|
||||
│ │ ├── do/
|
||||
│ │ │ ├── push/
|
||||
│ │ │ │ ├── push_init_params.dart
|
||||
│ │ │ │ └── query/
|
||||
│ │ │ │ └── setting_push_query_do.dart
|
||||
│ │ │ └── setting_has_success_do.dart
|
||||
│ │ ├── errors/
|
||||
│ │ │ └── setting_errors.dart
|
||||
│ │ └── push_device_info.dart
|
||||
│ ├── eventbus/ # 事件总线
|
||||
│ │ ├── event_bus.dart
|
||||
│ │ ├── event_bus.freezed.dart
|
||||
│ │ └── event_bus.g.dart
|
||||
│ ├── heart_beat/ # 心跳管理
|
||||
│ │ └── heart_beat_mgmt.dart
|
||||
│ ├── infrastructure/ # 基础设施层
|
||||
│ │ ├── push_repository.dart
|
||||
│ │ ├── remote_api.dart
|
||||
│ │ └── remoteapi/
|
||||
│ │ └── push_repository_remote.dart
|
||||
│ └── push_parser/ # 消息解析
|
||||
│ └── push_message_parser.dart
|
||||
├── basic_push_uml.puml # UML图定义
|
||||
├── basic_push_uml.svg # UML图
|
||||
└── pubspec.yaml # 依赖配置
|
||||
```
|
||||
|
||||
## 核心架构组件
|
||||
|
||||
### 1. 推送初始化参数 (PushInitParams)
|
||||
|
||||
定义推送服务初始化所需的参数:
|
||||
|
||||
```dart
|
||||
/// 初始化需要的参数
|
||||
class PushInitParams {
|
||||
const PushInitParams({
|
||||
this.privateCloud = true,
|
||||
this.isProduction = false,
|
||||
this.isDebug = false,
|
||||
this.appKey = '',
|
||||
this.channel = '',
|
||||
this.connIp = '',
|
||||
this.connHost,
|
||||
this.connPort = 0,
|
||||
this.reportUrl = '',
|
||||
this.badgeUrl = '',
|
||||
this.heartbeatInterval,
|
||||
});
|
||||
|
||||
/// iOS环境:生产环境设置
|
||||
/// TestFlight/In-house/Ad-hoc/AppStore为生产环境(true)
|
||||
/// Xcode直接编译为开发环境(false)
|
||||
final bool isProduction;
|
||||
|
||||
/// 是否是私有云
|
||||
final bool privateCloud;
|
||||
|
||||
/// debug开关
|
||||
final bool isDebug;
|
||||
|
||||
/// 应用Key
|
||||
final String appKey;
|
||||
|
||||
/// 渠道标识
|
||||
final String channel;
|
||||
|
||||
/// 连接IP地址
|
||||
final String connIp;
|
||||
|
||||
/// 连接主机
|
||||
final String? connHost;
|
||||
|
||||
/// 连接端口
|
||||
final int connPort;
|
||||
|
||||
/// 上报URL
|
||||
final String reportUrl;
|
||||
|
||||
/// 角标URL
|
||||
final String badgeUrl;
|
||||
|
||||
/// 推送心跳间隔(毫秒),默认4分50秒
|
||||
final int? heartbeatInterval;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 事件总线系统 (EventBus)
|
||||
|
||||
基于RxDart实现的事件发布订阅系统:
|
||||
|
||||
```dart
|
||||
/// 事件总线接口
|
||||
abstract class IEventBus {
|
||||
/// 监听多个主题的事件
|
||||
Stream<Event> on(List<Topic> topics);
|
||||
|
||||
/// 发布新事件
|
||||
void fire(Event event);
|
||||
|
||||
/// 销毁事件总线
|
||||
void destroy();
|
||||
|
||||
/// 获取发送端口用于连接器连接
|
||||
SendPort get sendPort;
|
||||
}
|
||||
|
||||
/// 事件总线实现
|
||||
class EventBus implements IEventBus {
|
||||
factory EventBus({bool sync = false}) => EventBus._(
|
||||
PublishSubject<Event>(
|
||||
onListen: () => Logger.d('Event Bus has a listener', tag),
|
||||
onCancel: () => Logger.d('Event Bus has no listener', tag),
|
||||
sync: sync,
|
||||
),
|
||||
);
|
||||
|
||||
@override
|
||||
void fire(Event event) {
|
||||
Logger.d('Fire a event, $event');
|
||||
if (_checkEvent(event)) {
|
||||
streamController.add(event);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<Event> on(List<Topic> topics) =>
|
||||
streamController.stream.where((event) {
|
||||
final firstWhere = topics.firstWhere(
|
||||
(element) => (element & event.topic).isHit,
|
||||
orElse: Topic.zero,
|
||||
);
|
||||
return firstWhere != Topic.zero();
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 事件和主题定义 (Event & Topic)
|
||||
|
||||
使用Freezed定义的不可变数据类:
|
||||
|
||||
```dart
|
||||
/// 事件对象
|
||||
@freezed
|
||||
class Event with _$Event {
|
||||
const factory Event({
|
||||
required Topic topic,
|
||||
required DateTime timestamp,
|
||||
dynamic payload,
|
||||
@Default('') String description,
|
||||
@Default(EventSource.local) EventSource sources,
|
||||
@Default(false) bool notificationInApp,
|
||||
}) = _Event;
|
||||
|
||||
factory Event.fromJson(Map<String, dynamic> json) => _$EventFromJson(json);
|
||||
}
|
||||
|
||||
/// 主题对象
|
||||
@freezed
|
||||
class Topic with _$Topic {
|
||||
const factory Topic({
|
||||
@Default(maxInt) int scope,
|
||||
@Default(maxInt) int product,
|
||||
@Default(maxInt) int index,
|
||||
@Default(maxInt) int subIndex,
|
||||
}) = _Topic;
|
||||
|
||||
const Topic._();
|
||||
|
||||
factory Topic.zero() => const Topic(scope: 0, product: 0, index: 0, subIndex: 0);
|
||||
|
||||
/// 主题合并操作
|
||||
Topic operator |(Topic other) => Topic(
|
||||
scope: scope | other.scope,
|
||||
product: product | other.product,
|
||||
index: index | other.index,
|
||||
subIndex: subIndex | other.subIndex,
|
||||
);
|
||||
|
||||
/// 主题匹配操作
|
||||
Topic operator &(Topic other) => Topic(
|
||||
scope: scope & other.scope,
|
||||
product: product & other.product,
|
||||
index: index & other.index,
|
||||
subIndex: subIndex & other.subIndex,
|
||||
);
|
||||
|
||||
/// 是否命中
|
||||
bool get isHit => scope > 0 && product > 0 && index > 0 && subIndex > 0;
|
||||
}
|
||||
|
||||
/// 事件来源
|
||||
enum EventSource {
|
||||
/// 远程推送
|
||||
push,
|
||||
/// 本地
|
||||
local,
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 推送门面服务 (IPushFacade)
|
||||
|
||||
推送模块的核心接口定义:
|
||||
|
||||
```dart
|
||||
/// push模块的接口
|
||||
abstract class IPushFacade {
|
||||
/// 初始化模块
|
||||
/// 开启心跳上报
|
||||
void initPush({
|
||||
ILoginDeps loginDeps = const DefaultLoginDeps(),
|
||||
PushInitParams pushInitParams = const PushInitParams(),
|
||||
});
|
||||
|
||||
/// 系统通知权限是否授予
|
||||
bool get isNotificationEnabled;
|
||||
|
||||
/// 返回推送SDK里的regId
|
||||
Future<String?> get pushRegId;
|
||||
|
||||
/// 调用此API跳转至系统设置中应用设置界面
|
||||
void openSettingsForNotification();
|
||||
|
||||
/// 将bizId与推送regId传至服务端绑定
|
||||
Future<bool> bindPush();
|
||||
|
||||
/// 将bizId与推送RegId传至服务端解绑
|
||||
Future<bool> unbindPush();
|
||||
|
||||
/// 发布一个事件
|
||||
void postEvent({
|
||||
required Topic topic,
|
||||
dynamic payload,
|
||||
String description = '',
|
||||
});
|
||||
|
||||
/// 订阅对应topic的事件消息
|
||||
Stream<Event> subscribeOn({required List<Topic> topics});
|
||||
|
||||
/// 取消订阅topic的事件消息
|
||||
void unsubscribe(StreamSubscription<dynamic> stream);
|
||||
|
||||
/// 获取服务器通知开关列表
|
||||
Future<Either<SettingError, SettingPushQueryModel>> fetchPushQuery();
|
||||
|
||||
/// 设置服务器通知开关列表
|
||||
Future<Either<SettingError, SettingHasSuccessModel>> fetchPushSet({
|
||||
List<SettingDetailSwitchModel> detailSwitchList,
|
||||
});
|
||||
|
||||
/// 告知当前在前台
|
||||
void enableHearBeatForeground();
|
||||
|
||||
/// 告知当前在后台
|
||||
void enableHearBeatBackground();
|
||||
|
||||
/// 发送本地通知
|
||||
Future<String> sendLocalNotification(LocalNotification notification);
|
||||
|
||||
/// 设置应用角标
|
||||
Future<dynamic> setBadgeNumber(int badgeNumber);
|
||||
|
||||
/// 清除缓存
|
||||
Future<bool> clearCache();
|
||||
}
|
||||
|
||||
/// 全局推送门面实例
|
||||
IPushFacade get pushFacade => _pushFacade ??= biuldPushFacade();
|
||||
```
|
||||
|
||||
### 5. 预定义主题 (Push Topics)
|
||||
|
||||
```dart
|
||||
/// 通知点击主题
|
||||
const Topic notificationOnClickTopic =
|
||||
Topic(scope: shift2, product: shift0, index: shift0);
|
||||
|
||||
/// 点击事件里payload里的跳转协议
|
||||
const keyLaunchScheme = 'launchScheme';
|
||||
|
||||
/// 全部主题
|
||||
const Topic allTopic = Topic();
|
||||
|
||||
/// 零主题
|
||||
const Topic zeroTopic = Topic(scope: 0, product: 0, index: 0, subIndex: 0);
|
||||
```
|
||||
|
||||
## 使用指南
|
||||
|
||||
### 1. 推送服务初始化
|
||||
|
||||
```dart
|
||||
import 'package:basic_push/basic_push.dart';
|
||||
|
||||
// 配置推送初始化参数
|
||||
final pushInitParams = PushInitParams(
|
||||
isProduction: true, // iOS生产环境
|
||||
privateCloud: true, // 使用私有云
|
||||
isDebug: false, // 关闭调试模式
|
||||
appKey: 'your_app_key', // 应用密钥
|
||||
channel: 'official', // 渠道标识
|
||||
connHost: 'push.example.com', // 推送服务器
|
||||
connPort: 8080, // 连接端口
|
||||
heartbeatInterval: 290000, // 心跳间隔(4分50秒)
|
||||
);
|
||||
|
||||
// 初始化推送服务
|
||||
pushFacade.initPush(
|
||||
loginDeps: MyLoginDeps(),
|
||||
pushInitParams: pushInitParams,
|
||||
);
|
||||
```
|
||||
|
||||
### 2. 用户绑定和解绑
|
||||
|
||||
```dart
|
||||
// 用户登录后绑定推送
|
||||
try {
|
||||
final success = await pushFacade.bindPush();
|
||||
if (success) {
|
||||
print('推送绑定成功');
|
||||
} else {
|
||||
print('推送绑定失败');
|
||||
}
|
||||
} catch (e) {
|
||||
print('推送绑定异常: $e');
|
||||
}
|
||||
|
||||
// 用户登出时解绑推送
|
||||
try {
|
||||
final success = await pushFacade.unbindPush();
|
||||
if (success) {
|
||||
print('推送解绑成功');
|
||||
} else {
|
||||
print('推送解绑失败');
|
||||
}
|
||||
} catch (e) {
|
||||
print('推送解绑异常: $e');
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 权限管理
|
||||
|
||||
```dart
|
||||
// 检查通知权限
|
||||
if (pushFacade.isNotificationEnabled) {
|
||||
print('通知权限已授予');
|
||||
} else {
|
||||
print('通知权限未授予,请手动开启');
|
||||
|
||||
// 跳转到系统设置页面
|
||||
pushFacade.openSettingsForNotification();
|
||||
}
|
||||
|
||||
// 获取推送注册ID
|
||||
final regId = await pushFacade.pushRegId;
|
||||
print('推送注册ID: $regId');
|
||||
```
|
||||
|
||||
### 4. 事件发布和订阅
|
||||
|
||||
```dart
|
||||
// 发布事件
|
||||
pushFacade.postEvent(
|
||||
topic: notificationOnClickTopic,
|
||||
payload: {
|
||||
keyLaunchScheme: 'oneapp://car/control',
|
||||
'userId': '12345',
|
||||
'action': 'open_door',
|
||||
},
|
||||
description: '用户点击推送通知',
|
||||
);
|
||||
|
||||
// 订阅事件
|
||||
final subscription = pushFacade.subscribeOn(
|
||||
topics: [notificationOnClickTopic],
|
||||
).listen((event) {
|
||||
print('接收到事件: ${event.description}');
|
||||
|
||||
// 处理跳转协议
|
||||
final scheme = event.payload[keyLaunchScheme] as String?;
|
||||
if (scheme != null) {
|
||||
handleDeepLink(scheme);
|
||||
}
|
||||
});
|
||||
|
||||
// 取消订阅
|
||||
pushFacade.unsubscribe(subscription);
|
||||
```
|
||||
|
||||
### 5. 本地通知
|
||||
|
||||
```dart
|
||||
// 发送本地通知
|
||||
final notification = LocalNotification(
|
||||
title: '车辆提醒',
|
||||
body: '您的车辆充电已完成',
|
||||
payload: jsonEncode({
|
||||
'type': 'charging_complete',
|
||||
'vehicleId': 'VIN123456',
|
||||
}),
|
||||
);
|
||||
|
||||
final notificationId = await pushFacade.sendLocalNotification(notification);
|
||||
print('本地通知已发送,ID: $notificationId');
|
||||
|
||||
// 设置应用角标
|
||||
await pushFacade.setBadgeNumber(5);
|
||||
```
|
||||
|
||||
### 6. 应用生命周期管理
|
||||
|
||||
```dart
|
||||
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
switch (state) {
|
||||
case AppLifecycleState.resumed:
|
||||
// 应用进入前台
|
||||
pushFacade.enableHearBeatForeground();
|
||||
break;
|
||||
case AppLifecycleState.paused:
|
||||
// 应用进入后台
|
||||
pushFacade.enableHearBeatBackground();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7. 推送设置管理
|
||||
|
||||
```dart
|
||||
// 获取推送设置
|
||||
final result = await pushFacade.fetchPushQuery();
|
||||
result.fold(
|
||||
(error) => print('获取推送设置失败: ${error.message}'),
|
||||
(settings) => {
|
||||
print('当前推送设置: ${settings.detailSwitchList}'),
|
||||
// 显示推送设置界面
|
||||
},
|
||||
);
|
||||
|
||||
// 更新推送设置
|
||||
final updateResult = await pushFacade.fetchPushSet(
|
||||
detailSwitchList: [
|
||||
SettingDetailSwitchModel(
|
||||
key: 'vehicle_notification',
|
||||
enabled: true,
|
||||
name: '车辆通知',
|
||||
),
|
||||
SettingDetailSwitchModel(
|
||||
key: 'charging_notification',
|
||||
enabled: false,
|
||||
name: '充电通知',
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
updateResult.fold(
|
||||
(error) => print('更新推送设置失败: ${error.message}'),
|
||||
(success) => print('推送设置更新成功'),
|
||||
);
|
||||
```
|
||||
|
||||
## 依赖配置
|
||||
|
||||
### pubspec.yaml 关键依赖
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
# 函数式编程
|
||||
dartz: ^0.10.1
|
||||
|
||||
# 响应式编程
|
||||
rxdart: ^0.27.0
|
||||
|
||||
# 不可变数据类
|
||||
freezed_annotation: ^2.0.0
|
||||
|
||||
# JSON序列化
|
||||
json_annotation: ^4.0.0
|
||||
|
||||
# 基础日志
|
||||
basic_logger:
|
||||
path: ../basic_logger
|
||||
|
||||
# 基础平台
|
||||
basic_platform:
|
||||
path: ../basic_platform
|
||||
|
||||
dev_dependencies:
|
||||
# 代码生成
|
||||
freezed: ^2.0.0
|
||||
json_serializable: ^6.0.0
|
||||
build_runner: ^2.0.0
|
||||
```
|
||||
|
||||
## 高级功能
|
||||
|
||||
### 1. 自定义登录依赖
|
||||
|
||||
```dart
|
||||
class MyLoginDeps with ILoginDeps {
|
||||
@override
|
||||
bool get isLogin {
|
||||
// 实现自定义的登录状态检查逻辑
|
||||
return UserManager.instance.isLoggedIn;
|
||||
}
|
||||
}
|
||||
|
||||
// 使用自定义登录依赖
|
||||
pushFacade.initPush(
|
||||
loginDeps: MyLoginDeps(),
|
||||
pushInitParams: pushInitParams,
|
||||
);
|
||||
```
|
||||
|
||||
### 2. 复杂主题组合
|
||||
|
||||
```dart
|
||||
// 定义自定义主题
|
||||
const Topic carNotificationTopic = Topic(
|
||||
scope: shift1,
|
||||
product: shift2,
|
||||
index: shift1,
|
||||
subIndex: shift1,
|
||||
);
|
||||
|
||||
const Topic chargingNotificationTopic = Topic(
|
||||
scope: shift1,
|
||||
product: shift2,
|
||||
index: shift2,
|
||||
subIndex: shift1,
|
||||
);
|
||||
|
||||
// 组合多个主题
|
||||
final combinedTopic = carNotificationTopic | chargingNotificationTopic;
|
||||
|
||||
// 订阅组合主题
|
||||
final subscription = pushFacade.subscribeOn(
|
||||
topics: [combinedTopic],
|
||||
).listen((event) {
|
||||
// 处理车辆或充电相关的通知
|
||||
});
|
||||
```
|
||||
|
||||
### 3. 推送消息解析
|
||||
|
||||
```dart
|
||||
// 自定义推送消息解析器
|
||||
class MyPushMessageParser {
|
||||
static Map<String, dynamic> parse(Map<String, dynamic> rawMessage) {
|
||||
// 解析推送消息的自定义格式
|
||||
return {
|
||||
'type': rawMessage['msg_type'],
|
||||
'data': jsonDecode(rawMessage['data']),
|
||||
'timestamp': DateTime.parse(rawMessage['timestamp']),
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 性能优化建议
|
||||
|
||||
### 1. 事件订阅管理
|
||||
- 及时取消不需要的事件订阅,避免内存泄漏
|
||||
- 使用合适的主题过滤,减少不必要的事件处理
|
||||
- 在Widget销毁时记得取消订阅
|
||||
|
||||
### 2. 心跳优化
|
||||
- 根据应用特性调整心跳间隔
|
||||
- 在后台时降低心跳频率
|
||||
- 监听网络状态变化,暂停心跳服务
|
||||
|
||||
### 3. 本地通知限制
|
||||
- 避免频繁发送本地通知
|
||||
- 合理设置通知的声音和震动
|
||||
- 控制通知的数量和频率
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 推送权限处理
|
||||
```dart
|
||||
// 推荐:友好的权限请求
|
||||
void requestNotificationPermission() {
|
||||
if (!pushFacade.isNotificationEnabled) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text('开启通知权限'),
|
||||
content: Text('为了及时收到重要消息,请开启通知权限'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text('稍后设置'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
pushFacade.openSettingsForNotification();
|
||||
},
|
||||
child: Text('去设置'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 错误处理
|
||||
```dart
|
||||
// 推荐:完整的错误处理
|
||||
Future<void> handlePushBinding() async {
|
||||
try {
|
||||
final success = await pushFacade.bindPush();
|
||||
if (!success) {
|
||||
// 绑定失败的用户友好提示
|
||||
showSnackBar('推送服务暂时不可用,请稍后重试');
|
||||
}
|
||||
} catch (e) {
|
||||
// 记录错误日志
|
||||
Logger.e('推送绑定异常: $e', tagPush);
|
||||
// 用户友好的错误提示
|
||||
showSnackBar('网络连接异常,请检查网络后重试');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 事件处理优化
|
||||
```dart
|
||||
// 推荐:使用StreamBuilder处理事件
|
||||
class NotificationHandler extends StatefulWidget {
|
||||
@override
|
||||
_NotificationHandlerState createState() => _NotificationHandlerState();
|
||||
}
|
||||
|
||||
class _NotificationHandlerState extends State<NotificationHandler> {
|
||||
late StreamSubscription _subscription;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_subscription = pushFacade.subscribeOn(
|
||||
topics: [notificationOnClickTopic],
|
||||
).listen(_handleNotificationClick);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_subscription.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _handleNotificationClick(Event event) {
|
||||
// 安全的事件处理
|
||||
if (mounted && event.payload != null) {
|
||||
final scheme = event.payload[keyLaunchScheme] as String?;
|
||||
if (scheme != null) {
|
||||
NavigationService.handleDeepLink(scheme);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 问题排查
|
||||
|
||||
### 常见问题
|
||||
1. **推送收不到**: 检查应用权限、网络连接和推送配置
|
||||
2. **事件订阅失效**: 确认订阅没有被意外取消,检查主题匹配逻辑
|
||||
3. **心跳断开**: 检查网络稳定性和服务器配置
|
||||
|
||||
### 调试技巧
|
||||
- 启用debug模式查看详细日志
|
||||
- 使用推送测试工具验证配置
|
||||
- 监控应用生命周期事件
|
||||
|
||||
Reference in New Issue
Block a user