diff --git a/flutter_monisuo/PUSH_NOTIFICATION_GUIDE.md b/flutter_monisuo/PUSH_NOTIFICATION_GUIDE.md
new file mode 100644
index 0000000..d04a80c
--- /dev/null
+++ b/flutter_monisuo/PUSH_NOTIFICATION_GUIDE.md
@@ -0,0 +1,328 @@
+# Flutter前端推送通知集成方案
+
+## 技术选型
+
+### 推送服务选择
+考虑到国内环境,推荐使用 **极光推送 (JPush)** 或 **个推 (Getui)**
+
+**优势**:
+- 国内推送到达率高
+- 支持iOS和Android
+- 提供完善的Flutter SDK
+- 免费版本足够使用
+
+## 集成步骤
+
+### 1. 添加依赖
+
+```yaml
+dependencies:
+ # 极光推送
+ jpush_flutter: ^2.5.0
+
+ # 本地通知
+ flutter_local_notifications: ^16.0.0
+
+ # 权限管理
+ permission_handler: ^11.0.0
+```
+
+### 2. Android配置
+
+**android/app/build.gradle**:
+```gradle
+android {
+ defaultConfig {
+ manifestPlaceholders = [
+ JPUSH_PKGNAME: applicationId,
+ JPUSH_APPKEY: "你的APPKEY",
+ JPUSH_CHANNEL: "developer-default"
+ ]
+ }
+}
+```
+
+**android/app/src/main/AndroidManifest.xml**:
+```xml
+
+
+
+
+
+
+
+
+
+```
+
+### 3. iOS配置
+
+**ios/Runner/Info.plist**:
+```xml
+UIBackgroundModes
+
+ remote-notification
+
+```
+
+### 4. 初始化推送
+
+**lib/services/push_service.dart**:
+```dart
+import 'package:jpush_flutter/jpush_flutter.dart';
+import 'package:flutter_local_notifications/flutter_local_notifications.dart';
+
+class PushService {
+ static final PushService _instance = PushService._internal();
+ factory PushService() => _instance;
+ PushService._internal();
+
+ final JPush jpush = JPush();
+ final FlutterLocalNotificationsPlugin localNotifications =
+ FlutterLocalNotificationsPlugin();
+
+ Future init() async {
+ // 初始化极光推送
+ jpush.addEventHandler(
+ onReceiveNotification: (Map message) async {
+ print('收到推送: $message');
+ _handleNotification(message);
+ },
+ onOpenNotification: (Map message) async {
+ print('点击推送: $message');
+ _handleNotificationTap(message);
+ },
+ );
+
+ jpush.setup(
+ appKey: '你的APPKEY',
+ channel: 'developer-default',
+ production: false,
+ debug: true,
+ );
+
+ // 初始化本地通知
+ await _initLocalNotifications();
+ }
+
+ Future _initLocalNotifications() async {
+ const AndroidInitializationSettings initializationSettingsAndroid =
+ AndroidInitializationSettings('@mipmap/ic_launcher');
+
+ final DarwinInitializationSettings initializationSettingsDarwin =
+ DarwinInitializationSettings();
+
+ final InitializationSettings initializationSettings =
+ InitializationSettings(
+ android: initializationSettingsAndroid,
+ iOS: initializationSettingsDarwin,
+ );
+
+ await localNotifications.initialize(
+ initializationSettings,
+ onDidReceiveNotificationResponse: (NotificationResponse response) {
+ _handleLocalNotificationTap(response.payload);
+ },
+ );
+ }
+
+ void _handleNotification(Map message) {
+ // 处理推送消息
+ final title = message['title'] ?? '新消息';
+ final body = message['alert'] ?? '';
+
+ _showLocalNotification(title, body, message);
+ }
+
+ void _handleNotificationTap(Map message) {
+ // 处理推送点击
+ final type = message['extras']['type'];
+
+ switch (type) {
+ case 'order':
+ // 跳转到订单详情
+ break;
+ case 'asset':
+ // 跳转到资产页面
+ break;
+ default:
+ // 跳转到首页
+ break;
+ }
+ }
+
+ Future _showLocalNotification(
+ String title,
+ String body,
+ Map data,
+ ) async {
+ const AndroidNotificationDetails androidPlatformChannelSpecifics =
+ AndroidNotificationDetails(
+ 'monisuo_channel',
+ '模拟所通知',
+ channelDescription: '模拟所应用通知',
+ importance: Importance.max,
+ priority: Priority.high,
+ );
+
+ const NotificationDetails platformChannelSpecifics =
+ NotificationDetails(android: androidPlatformChannelSpecifics);
+
+ await localNotifications.show(
+ DateTime.now().millisecondsSinceEpoch ~/ 1000,
+ title,
+ body,
+ platformChannelSpecifics,
+ payload: jsonEncode(data),
+ );
+ }
+
+ void _handleLocalNotificationTap(String? payload) {
+ if (payload != null) {
+ final data = jsonDecode(payload);
+ _handleNotificationTap(data);
+ }
+ }
+
+ // 设置别名(通常是用户ID)
+ Future setAlias(String userId) async {
+ jpush.setAlias(userId);
+ }
+
+ // 删除别名
+ Future deleteAlias() async {
+ jpush.deleteAlias();
+ }
+
+ // 设置标签
+ Future setTags(List tags) async {
+ jpush.setTags(tags);
+ }
+}
+```
+
+### 5. 在main.dart中初始化
+
+```dart
+void main() async {
+ WidgetsFlutterBinding.ensureInitialized();
+
+ // 初始化推送服务
+ await PushService().init();
+
+ runApp(const MyApp());
+}
+```
+
+### 6. 登录后设置别名
+
+```dart
+// 用户登录成功后
+await PushService().setAlias(userId);
+
+// 用户退出登录后
+await PushService().deleteAlias();
+```
+
+## 后端推送接口
+
+**后端需要提供推送接口**:
+
+```java
+@PostMapping("/api/push/send")
+public Result sendPush(
+ @RequestParam String userId,
+ @RequestParam String title,
+ @RequestParam String body,
+ @RequestParam(required = false) Map extras
+) {
+ // 调用极光推送API
+ JPushClient jpushClient = new JPushClient(appKey, masterSecret);
+
+ PushPayload payload = PushPayload.newBuilder()
+ .setPlatform(Platform.all())
+ .setAudience(Audience.alias(userId))
+ .setNotification(Notification.alert(body))
+ .setMessage(Message.content(body))
+ .setOptions(Options.newBuilder().setApnsProduction(false).build())
+ .build();
+
+ jpushClient.sendPush(payload);
+
+ return Result.success("推送成功");
+}
+```
+
+## 推送场景
+
+### 1. 充值审批通知
+```dart
+{
+ "title": "充值审批通过",
+ "body": "您的充值订单已审批通过,金额: 100 USDT",
+ "extras": {
+ "type": "order",
+ "orderNo": "F20260324001"
+ }
+}
+```
+
+### 2. 提现审批通知
+```dart
+{
+ "title": "提现审批完成",
+ "body": "您的提现申请已处理,金额: 100 USDT",
+ "extras": {
+ "type": "order",
+ "orderNo": "F20260324002"
+ }
+}
+```
+
+### 3. 资产变动通知
+```dart
+{
+ "title": "资产变动",
+ "body": "您的账户余额发生变动",
+ "extras": {
+ "type": "asset",
+ "userId": "123"
+ }
+}
+```
+
+## 测试
+
+### 1. 测试推送
+```dart
+// 在开发环境中测试
+await PushService()._showLocalNotification(
+ '测试标题',
+ '测试内容',
+ {'type': 'test'},
+);
+```
+
+### 2. 测试极光推送
+- 在极光推送控制台发送测试推送
+- 检查应用是否收到推送
+
+## 注意事项
+
+1. **权限申请**: Android需要申请通知权限
+2. **iOS证书**: 需要配置APNs证书
+3. **测试环境**: 开发时使用开发环境
+4. **生产环境**: 上线前切换到生产环境
+5. **用户隐私**: 首次启动时请求推送权限
+
+## 成本估算
+
+- 极光推送免费版:每月100万条推送
+- 对于中小规模应用完全够用
+- 如需更多,可以升级付费版本
+
+---
+
+**集成时间**: 预计2-3小时
+**难度**: 中等
+**维护成本**: 低
diff --git a/flutter_monisuo/lib/main.dart b/flutter_monisuo/lib/main.dart
index 03ff639..8c0bcbb 100644
--- a/flutter_monisuo/lib/main.dart
+++ b/flutter_monisuo/lib/main.dart
@@ -13,6 +13,7 @@ import 'data/services/market_service.dart';
import 'data/services/trade_service.dart';
import 'data/services/asset_service.dart';
import 'data/services/fund_service.dart';
+import 'services/push_service.dart';
import 'providers/auth_provider.dart';
import 'providers/market_provider.dart';
import 'providers/asset_provider.dart';
@@ -26,6 +27,10 @@ void main() async {
await SharedPreferences.getInstance();
await LocalStorage.init();
+
+ // 初始化推送服务
+ await PushService().init();
+ debugPrint('✅ 推送服务已初始化');
runApp(const MyApp());
}
diff --git a/flutter_monisuo/lib/services/push_service.dart b/flutter_monisuo/lib/services/push_service.dart
new file mode 100644
index 0000000..786afdd
--- /dev/null
+++ b/flutter_monisuo/lib/services/push_service.dart
@@ -0,0 +1,321 @@
+import 'dart:convert';
+import 'package:flutter/material.dart';
+import 'package:jpush_flutter/jpush_flutter.dart';
+import 'package:flutter_local_notifications/flutter_local_notifications.dart';
+
+/// 推送通知服务
+class PushService {
+ static final PushService _instance = PushService._internal();
+ factory PushService() => _instance;
+ PushService._internal();
+
+ final JPush jpush = JPush();
+ final FlutterLocalNotificationsPlugin localNotifications =
+ FlutterLocalNotificationsPlugin();
+
+ bool _initialized = false;
+
+ /// 初始化推送服务
+ Future init({String? appKey}) async {
+ if (_initialized) return;
+
+ try {
+ // 初始化极光推送
+ jpush.addEventHandler(
+ onReceiveNotification: (Map message) async {
+ debugPrint('📱 收到推送: $message');
+ _handleNotification(message);
+ },
+ onOpenNotification: (Map message) async {
+ debugPrint('📱 点击推送: $message');
+ _handleNotificationTap(message);
+ },
+ onReceiveMessage: (Map message) async {
+ debugPrint('📱 收到自定义消息: $message');
+ },
+ );
+
+ // 如果有appKey则设置,否则跳过(用于开发环境)
+ if (appKey != null && appKey.isNotEmpty) {
+ jpush.setup(
+ appKey: appKey,
+ channel: 'developer-default',
+ production: false,
+ debug: true,
+ );
+ }
+
+ // 初始化本地通知
+ await _initLocalNotifications();
+
+ _initialized = true;
+ debugPrint('✅ 推送服务初始化成功');
+ } catch (e) {
+ debugPrint('❌ 推送服务初始化失败: $e');
+ }
+ }
+
+ /// 初始化本地通知
+ Future _initLocalNotifications() async {
+ const AndroidInitializationSettings initializationSettingsAndroid =
+ AndroidInitializationSettings('@mipmap/ic_launcher');
+
+ final DarwinInitializationSettings initializationSettingsDarwin =
+ DarwinInitializationSettings(
+ requestAlertPermission: true,
+ requestBadgePermission: true,
+ requestSoundPermission: true,
+ );
+
+ final InitializationSettings initializationSettings =
+ InitializationSettings(
+ android: initializationSettingsAndroid,
+ iOS: initializationSettingsDarwin,
+ );
+
+ await localNotifications.initialize(
+ initializationSettings,
+ onDidReceiveNotificationResponse: (NotificationResponse response) {
+ _handleLocalNotificationTap(response.payload);
+ },
+ );
+
+ // 请求通知权限(Android 13+)
+ await localNotifications
+ .resolvePlatformSpecificImplementation<
+ AndroidFlutterLocalNotificationsPlugin>()
+ ?.requestNotificationsPermission();
+ }
+
+ /// 处理推送消息
+ void _handleNotification(Map message) {
+ try {
+ final extras = message['extras'] as Map?;
+ final title = extras?['title']?.toString() ??
+ message['title']?.toString() ??
+ '新消息';
+ final body = extras?['body']?.toString() ??
+ message['alert']?.toString() ??
+ '';
+
+ _showLocalNotification(title, body, message);
+ } catch (e) {
+ debugPrint('❌ 处理推送消息失败: $e');
+ }
+ }
+
+ /// 处理推送点击
+ void _handleNotificationTap(Map message) {
+ try {
+ final extras = message['extras'] as Map?;
+ final type = extras?['type']?.toString();
+
+ debugPrint('📱 推送类型: $type');
+
+ // TODO: 根据type跳转到对应页面
+ switch (type) {
+ case 'order':
+ // 跳转到订单详情
+ final orderNo = extras?['orderNo']?.toString();
+ debugPrint('📱 跳转到订单: $orderNo');
+ break;
+ case 'asset':
+ // 跳转到资产页面
+ debugPrint('📱 跳转到资产页面');
+ break;
+ default:
+ // 默认跳转到首页
+ debugPrint('📱 默认跳转');
+ break;
+ }
+ } catch (e) {
+ debugPrint('❌ 处理推送点击失败: $e');
+ }
+ }
+
+ /// 显示本地通知
+ Future _showLocalNotification(
+ String title,
+ String body,
+ Map data,
+ ) async {
+ try {
+ const AndroidNotificationDetails androidPlatformChannelSpecifics =
+ AndroidNotificationDetails(
+ 'monisuo_channel',
+ '模拟所通知',
+ channelDescription: '模拟所应用通知',
+ importance: Importance.max,
+ priority: Priority.high,
+ showWhen: true,
+ enableVibration: true,
+ enableLights: true,
+ );
+
+ const DarwinNotificationDetails iOSPlatformChannelSpecifics =
+ DarwinNotificationDetails(
+ presentAlert: true,
+ presentBadge: true,
+ presentSound: true,
+ );
+
+ const NotificationDetails platformChannelSpecifics =
+ NotificationDetails(
+ android: androidPlatformChannelSpecifics,
+ iOS: iOSPlatformChannelSpecifics,
+ );
+
+ await localNotifications.show(
+ DateTime.now().millisecondsSinceEpoch ~/ 1000,
+ title,
+ body,
+ platformChannelSpecifics,
+ payload: jsonEncode(data),
+ );
+
+ debugPrint('✅ 本地通知显示成功: $title - $body');
+ } catch (e) {
+ debugPrint('❌ 显示本地通知失败: $e');
+ }
+ }
+
+ /// 处理本地通知点击
+ void _handleLocalNotificationTap(String? payload) {
+ if (payload != null) {
+ try {
+ final data = jsonDecode(payload) as Map;
+ _handleNotificationTap(data);
+ } catch (e) {
+ debugPrint('❌ 处理本地通知点击失败: $e');
+ }
+ }
+ }
+
+ /// 设置别名(通常是用户ID)
+ Future setAlias(String userId) async {
+ try {
+ if (!_initialized) {
+ debugPrint('⚠️ 推送服务未初始化,无法设置别名');
+ return;
+ }
+
+ jpush.setAlias(userId);
+ debugPrint('✅ 设置推送别名: $userId');
+ } catch (e) {
+ debugPrint('❌ 设置别名失败: $e');
+ }
+ }
+
+ /// 删除别名
+ Future deleteAlias() async {
+ try {
+ if (!_initialized) {
+ debugPrint('⚠️ 推送服务未初始化,无法删除别名');
+ return;
+ }
+
+ jpush.deleteAlias();
+ debugPrint('✅ 删除推送别名');
+ } catch (e) {
+ debugPrint('❌ 删除别名失败: $e');
+ }
+ }
+
+ /// 设置标签
+ Future setTags(List tags) async {
+ try {
+ if (!_initialized) {
+ debugPrint('⚠️ 推送服务未初始化,无法设置标签');
+ return;
+ }
+
+ jpush.setTags(tags);
+ debugPrint('✅ 设置推送标签: $tags');
+ } catch (e) {
+ debugPrint('❌ 设置标签失败: $e');
+ }
+ }
+
+ /// 获取注册ID
+ Future getRegistrationId() async {
+ try {
+ if (!_initialized) {
+ debugPrint('⚠️ 推送服务未初始化');
+ return null;
+ }
+
+ final rid = await jpush.getRegistrationId();
+ debugPrint('📱 注册ID: $rid');
+ return rid;
+ } catch (e) {
+ debugPrint('❌ 获取注册ID失败: $e');
+ return null;
+ }
+ }
+
+ /// 测试本地通知(用于开发环境)
+ Future testNotification() async {
+ await _showLocalNotification(
+ '测试通知',
+ '这是一条测试推送消息',
+ {
+ 'type': 'test',
+ 'title': '测试通知',
+ 'body': '这是一条测试推送消息',
+ },
+ );
+ }
+
+ /// 发送充值审批通知
+ Future sendDepositApprovalNotification({
+ required String userId,
+ required String orderNo,
+ required String amount,
+ required bool approved,
+ }) async {
+ final title = approved ? '充值审批通过' : '充值审批驳回';
+ final body = approved
+ ? '您的充值订单已审批通过,金额: $amount USDT'
+ : '您的充值订单已被驳回,金额: $amount USDT';
+
+ await _showLocalNotification(title, body, {
+ 'type': 'order',
+ 'orderNo': orderNo,
+ 'title': title,
+ 'body': body,
+ });
+ }
+
+ /// 发送提现审批通知
+ Future sendWithdrawApprovalNotification({
+ required String userId,
+ required String orderNo,
+ required String amount,
+ required bool approved,
+ }) async {
+ final title = approved ? '提现审批通过' : '提现审批驳回';
+ final body = approved
+ ? '您的提现申请已处理,金额: $amount USDT'
+ : '您的提现申请已被驳回,金额: $amount USDT';
+
+ await _showLocalNotification(title, body, {
+ 'type': 'order',
+ 'orderNo': orderNo,
+ 'title': title,
+ 'body': body,
+ });
+ }
+
+ /// 发送资产变动通知
+ Future sendAssetChangeNotification({
+ required String userId,
+ required String message,
+ }) async {
+ await _showLocalNotification('资产变动', message, {
+ 'type': 'asset',
+ 'userId': userId,
+ 'title': '资产变动',
+ 'body': message,
+ });
+ }
+}
diff --git a/flutter_monisuo/pubspec.yaml b/flutter_monisuo/pubspec.yaml
index 623cbbc..6f62920 100644
--- a/flutter_monisuo/pubspec.yaml
+++ b/flutter_monisuo/pubspec.yaml
@@ -33,6 +33,11 @@ dependencies:
# 字体
google_fonts: ^6.2.1
+ # 推送通知
+ jpush_flutter: ^2.5.0
+ flutter_local_notifications: ^16.0.0
+ permission_handler: ^11.0.0
+
dev_dependencies:
flutter_test:
sdk: flutter