149 lines
4.2 KiB
Dart
149 lines
4.2 KiB
Dart
import 'dart:convert';
|
|
import 'dart:developer';
|
|
|
|
import 'package:awesome_notifications/awesome_notifications.dart';
|
|
import 'package:flutter/cupertino.dart';
|
|
|
|
import '../page/child/ChatPage.dart';
|
|
import '../page/child/UpdateCheckPage.dart';
|
|
import 'NotifyImageCache.dart';
|
|
import 'RouteAnimation.dart';
|
|
import 'StringTool.dart';
|
|
|
|
enum NotifyChannel { update, ad, message }
|
|
|
|
class Notify {
|
|
static BuildContext? _context;
|
|
|
|
/// 初始化(必须在 main() 中调用一次)
|
|
static Future<void> init() async {
|
|
await AwesomeNotifications().initialize(null, _channels, debug: true);
|
|
|
|
bool isAllowed = await AwesomeNotifications().isNotificationAllowed();
|
|
if (!isAllowed) {
|
|
await AwesomeNotifications().requestPermissionToSendNotifications();
|
|
}
|
|
|
|
// 直接传静态方法
|
|
AwesomeNotifications().setListeners(
|
|
onActionReceivedMethod: _onActionReceivedMethod,
|
|
);
|
|
}
|
|
|
|
/// 必须是静态或顶级方法
|
|
static Future<void> _onActionReceivedMethod(ReceivedAction action) async {
|
|
onClick(action.payload);
|
|
}
|
|
|
|
static void setBuildContext(BuildContext context) {
|
|
_context = context;
|
|
}
|
|
|
|
static List<NotificationChannel> get _channels => [
|
|
NotificationChannel(
|
|
channelKey: NotifyChannel.update.name,
|
|
channelName: '更新通知',
|
|
channelDescription: '新版本通知',
|
|
importance: NotificationImportance.Default,
|
|
),
|
|
NotificationChannel(
|
|
channelKey: NotifyChannel.ad.name,
|
|
channelName: '推广',
|
|
channelDescription: '新品推广',
|
|
importance: NotificationImportance.High,
|
|
),
|
|
NotificationChannel(
|
|
channelKey: NotifyChannel.message.name,
|
|
channelName: '新消息',
|
|
channelDescription: '新消息通知',
|
|
importance: NotificationImportance.Max,
|
|
),
|
|
];
|
|
|
|
/// 发送通知
|
|
static Future<void> showNotification({
|
|
required NotifyChannel channel,
|
|
required String title,
|
|
required String body,
|
|
String? smallIcon,
|
|
String? bigPicture,
|
|
Map<String, String>? payload,
|
|
}) async {
|
|
String? finalIcon = smallIcon;
|
|
String? finalBigPic = bigPicture;
|
|
|
|
// ✅ 如果是网络图,优先使用缓存
|
|
if (smallIcon != null && smallIcon.startsWith('http')) {
|
|
finalIcon = await NotifyImageCache.getCachedImage(smallIcon) ?? smallIcon;
|
|
}
|
|
|
|
if (bigPicture != null && bigPicture.startsWith('http')) {
|
|
finalBigPic =
|
|
await NotifyImageCache.getCachedImage(bigPicture) ?? bigPicture;
|
|
}
|
|
// 2. 转成本地文件路径格式
|
|
if (finalIcon != null && finalIcon.startsWith('/')) {
|
|
finalIcon = 'file://$finalIcon';
|
|
}
|
|
if (finalBigPic != null && finalBigPic.startsWith('/')) {
|
|
finalBigPic = 'file://$finalBigPic';
|
|
}
|
|
String text = StringTool.stripMarkdown(body);
|
|
text = text.length > 25 ? text.substring(0, 24) + "..." : text;
|
|
await AwesomeNotifications().createNotification(
|
|
content: NotificationContent(
|
|
id: DateTime.now().millisecondsSinceEpoch.remainder(100000),
|
|
channelKey: channel.name,
|
|
title: title,
|
|
body: text,
|
|
largeIcon: finalIcon,
|
|
bigPicture: finalBigPic,
|
|
notificationLayout: finalBigPic != null
|
|
? NotificationLayout.BigPicture
|
|
: NotificationLayout.Default,
|
|
payload: payload,
|
|
),
|
|
);
|
|
}
|
|
|
|
/// 清除全部消息
|
|
static Future<void> clearAll() async {
|
|
await AwesomeNotifications().cancelAll();
|
|
}
|
|
|
|
static void onClick(Map<String, String?>? payload) {
|
|
log(payload.toString());
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
switch (payload?["type"]) {
|
|
case "NEW_MESSAGE":
|
|
if (_context != null) {
|
|
Navigator.push(
|
|
_context!,
|
|
RouteAnimation(
|
|
ChatPage(
|
|
roomId: payload!["roomId"]!,
|
|
robotAvatar: payload["avatar"]!,
|
|
robotName: payload["name"]!,
|
|
),
|
|
Offset(1, 0),
|
|
),
|
|
);
|
|
|
|
break;
|
|
}
|
|
case "NEW_VERSION":
|
|
{
|
|
if (_context != null) {
|
|
Navigator.push(
|
|
_context!,
|
|
RouteAnimation(UpdateCheckPage(), Offset(1, 0)),
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|