You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
224 lines
6.9 KiB
224 lines
6.9 KiB
import 'dart:io';
|
|
import 'package:get/get.dart';
|
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
|
import 'package:device_info_plus/device_info_plus.dart';
|
|
import 'package:permission_handler/permission_handler.dart';
|
|
import '../providers/agent_provider.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
class NotificationService extends GetxService {
|
|
static NotificationService get to => Get.find();
|
|
|
|
FlutterLocalNotificationsPlugin? _flutterLocalNotificationsPlugin;
|
|
bool _notificationActive = false;
|
|
bool _isRequestingPermission = false;
|
|
|
|
String get _defaultAgentName {
|
|
final agent = AgentProvider.getAgentById('personal_assistant');
|
|
return agent?.name ?? 'Deep Voice';
|
|
}
|
|
|
|
Future<void> init() async {
|
|
try {
|
|
if (Platform.isIOS || Platform.isAndroid || Platform.isMacOS) {
|
|
_flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
|
|
|
|
// 使用应用图标作为通知图标
|
|
const initializationSettingsAndroid = AndroidInitializationSettings('mipmap/ic_launcher');
|
|
|
|
final initializationSettingsDarwin = DarwinInitializationSettings(
|
|
requestSoundPermission: false,
|
|
requestBadgePermission: false,
|
|
requestAlertPermission: false,
|
|
);
|
|
|
|
final initializationSettings = InitializationSettings(
|
|
android: initializationSettingsAndroid,
|
|
iOS: initializationSettingsDarwin,
|
|
macOS: initializationSettingsDarwin,
|
|
);
|
|
|
|
await _flutterLocalNotificationsPlugin?.initialize(
|
|
initializationSettings,
|
|
onDidReceiveNotificationResponse: (details) {
|
|
if (Get.currentRoute != '/chat') {
|
|
Get.toNamed('/chat');
|
|
}
|
|
},
|
|
);
|
|
}
|
|
|
|
// 创建通知渠道 - 使用高重要性确保通知在后台可见
|
|
if (Platform.isAndroid) {
|
|
await _flutterLocalNotificationsPlugin?.resolvePlatformSpecificImplementation<
|
|
AndroidFlutterLocalNotificationsPlugin>()?.createNotificationChannel(
|
|
const AndroidNotificationChannel(
|
|
'foreground_service',
|
|
'Foreground Service',
|
|
description: 'Used for the foreground service notification',
|
|
importance: Importance.high, // 提高重要性
|
|
playSound: false,
|
|
enableVibration: false,
|
|
showBadge: true,
|
|
),
|
|
);
|
|
}
|
|
|
|
// 请求权限,但避免重复请求
|
|
await _requestPermissionIfNeeded();
|
|
|
|
// 在初始化完成后显示前台服务通知
|
|
if (Platform.isAndroid) {
|
|
await showForegroundNotification();
|
|
}
|
|
|
|
// Add macOS-specific code for status bar icon
|
|
if (Platform.isMacOS) {
|
|
await showMacOSStatusBarIcon();
|
|
}
|
|
} catch (e) {
|
|
print('通知服务初始化失败: $e');
|
|
}
|
|
}
|
|
|
|
Future<void> showForegroundNotification() async {
|
|
if (_notificationActive) return;
|
|
|
|
try {
|
|
final androidDetails = AndroidNotificationDetails(
|
|
'foreground_service',
|
|
'Foreground Service',
|
|
channelDescription: 'Used for the foreground service notification',
|
|
importance: Importance.high, // 提高重要性
|
|
priority: Priority.high, // 提高优先级
|
|
ongoing: true,
|
|
autoCancel: false,
|
|
showWhen: false,
|
|
enableVibration: false,
|
|
playSound: false,
|
|
icon: 'mipmap/ic_launcher', // 使用应用图标
|
|
visibility: NotificationVisibility.public,
|
|
category: AndroidNotificationCategory.service,
|
|
actions: [
|
|
const AndroidNotificationAction(
|
|
'chat',
|
|
'开始对话',
|
|
showsUserInterface: true,
|
|
),
|
|
],
|
|
);
|
|
|
|
const iosDetails = DarwinNotificationDetails(
|
|
presentAlert: false,
|
|
presentBadge: false,
|
|
presentSound: false,
|
|
interruptionLevel: InterruptionLevel.passive,
|
|
);
|
|
|
|
final notificationDetails = NotificationDetails(
|
|
android: androidDetails,
|
|
iOS: iosDetails,
|
|
);
|
|
|
|
await _flutterLocalNotificationsPlugin?.show(
|
|
0,
|
|
_defaultAgentName,
|
|
'点击开始对话',
|
|
notificationDetails,
|
|
);
|
|
|
|
_notificationActive = true;
|
|
} catch (e) {
|
|
print('显示前台服务通知失败: $e');
|
|
}
|
|
}
|
|
|
|
Future<void> cancelNotification() async {
|
|
if (!_notificationActive) return;
|
|
try {
|
|
await _flutterLocalNotificationsPlugin?.cancel(0);
|
|
_notificationActive = false;
|
|
} catch (e) {
|
|
print('取消通知失败: $e');
|
|
}
|
|
}
|
|
|
|
Future<void> _requestPermissionIfNeeded() async {
|
|
// 避免重复请求权限
|
|
if (_isRequestingPermission) {
|
|
print('已有权限请求正在进行中,跳过此次请求');
|
|
return;
|
|
}
|
|
|
|
_isRequestingPermission = true;
|
|
|
|
try {
|
|
if (Platform.isMacOS) {
|
|
// On macOS, we don't need to request notification permissions through permission_handler
|
|
// Instead, we'll use the flutter_local_notifications plugin directly
|
|
final bool? granted = await _flutterLocalNotificationsPlugin
|
|
?.resolvePlatformSpecificImplementation<MacOSFlutterLocalNotificationsPlugin>()
|
|
?.requestPermissions(
|
|
alert: true,
|
|
badge: true,
|
|
sound: true,
|
|
);
|
|
if (granted != true) {
|
|
debugPrint('MacOS Notifications: Permission request was denied');
|
|
}
|
|
} else if (Platform.isAndroid || Platform.isIOS) {
|
|
// 检查权限状态,避免不必要的请求
|
|
final status = await Permission.notification.status;
|
|
if (status != PermissionStatus.granted) {
|
|
await Permission.notification.request();
|
|
}
|
|
}
|
|
} catch (e) {
|
|
print('请求通知权限失败: $e');
|
|
} finally {
|
|
_isRequestingPermission = false;
|
|
}
|
|
}
|
|
|
|
Future<void> showNotification({
|
|
required String title,
|
|
required String body,
|
|
}) async {
|
|
if (_flutterLocalNotificationsPlugin == null) return;
|
|
|
|
try {
|
|
const androidDetails = AndroidNotificationDetails(
|
|
'chat_channel',
|
|
'聊天消息',
|
|
channelDescription: '接收新的聊天消息',
|
|
importance: Importance.high,
|
|
priority: Priority.high,
|
|
icon: 'mipmap/ic_launcher', // 使用应用图标
|
|
);
|
|
|
|
const iosDetails = DarwinNotificationDetails(
|
|
presentAlert: true,
|
|
presentBadge: true,
|
|
presentSound: true,
|
|
);
|
|
|
|
const notificationDetails = NotificationDetails(
|
|
android: androidDetails,
|
|
iOS: iosDetails,
|
|
);
|
|
|
|
await _flutterLocalNotificationsPlugin?.show(
|
|
0,
|
|
title,
|
|
body,
|
|
notificationDetails,
|
|
);
|
|
} catch (e) {
|
|
print('显示通知失败: $e');
|
|
}
|
|
}
|
|
|
|
Future<void> showMacOSStatusBarIcon() async {
|
|
// Implementation using platform channel to communicate with native macOS code
|
|
}
|
|
}
|