更新安卓通知栏提示
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
class ServiceConstant {
|
||||
// static const String baseHost = "zhmht.swes.com.cn:27021"; //服务地址 眠花糖测试地址
|
||||
// static const String baseHost = "zhmht.swes.com.cn:27020"; //服务地址 眠花糖正式地址
|
||||
static const String baseHost = "vsbs-test.he-info.cn"; //服务地址 本地测试地址
|
||||
static const String baseHost = "zhmht.swes.com.cn:27020"; //服务地址 眠花糖正式地址
|
||||
// static const String baseHost = "vsbs-test.he-info.cn"; //服务地址 本地测试地址
|
||||
// static const String baseHost = "vsbst-api.he-info.cn";//服务地址
|
||||
// static const String service_address = "http://$baseHost";
|
||||
static const String service_address = "https://$baseHost";
|
||||
@@ -53,5 +53,8 @@ class ServiceConstant {
|
||||
|
||||
static const String weather_url =
|
||||
"/api/weather/info"; //天气信息
|
||||
|
||||
static const String app_system_push_message =
|
||||
"/api/user/push/info"; //系统消息推送
|
||||
|
||||
}
|
||||
|
||||
@@ -54,8 +54,8 @@ class AppConstants {
|
||||
|
||||
//系统参数
|
||||
//运行打包APP模式
|
||||
// int ent_type = APPPackageType.MHT.code; //1.默认太和 2.欢睡 3.眠花糖
|
||||
int ent_type = APPPackageType.TH.code; //1.默认太和 2.欢睡 3.眠花糖
|
||||
int ent_type = APPPackageType.MHT.code; //1.默认太和 2.欢睡 3.眠花糖
|
||||
// int ent_type = APPPackageType.TH.code; //1.默认太和 2.欢睡 3.眠花糖
|
||||
// int ent_type = APPPackageType.HUANSHUI.code; //1.默认太和 2.欢睡 3.眠花糖
|
||||
int text_length = 8;
|
||||
|
||||
|
||||
@@ -1,66 +1,67 @@
|
||||
import 'dart:io';
|
||||
import 'package:img_picker/img_picker.dart';
|
||||
import 'package:archive/archive_io.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
class DailyLogUtils {
|
||||
// 获取日志文件路径(按日期命名)
|
||||
// 获取当天日志文件路径
|
||||
static Future<File> _getLogFile() async {
|
||||
final dir = await getApplicationDocumentsDirectory();
|
||||
final date = DateFormat('yyyy-MM-dd').format(DateTime.now());
|
||||
final filePath = '${dir.path}/$date.log';
|
||||
final file = File(filePath);
|
||||
final file = File('${dir.path}/$date.log');
|
||||
if (!await file.exists()) {
|
||||
await file.create(recursive: true);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
// 写入日志核心方法,带日志等级
|
||||
// 写日志核心方法,带日志等级,固定 UTF-8
|
||||
static Future<void> _writeLogWithLevel(String level, String content) async {
|
||||
final file = await _getLogFile();
|
||||
final now = DateTime.now();
|
||||
final time = DateFormat('HH:mm:ss').format(now);
|
||||
final logLine = '[$time][$level] $content\n';
|
||||
await file.writeAsString(logLine, mode: FileMode.append);
|
||||
await file.writeAsString(logLine, mode: FileMode.append, encoding: utf8);
|
||||
}
|
||||
|
||||
// 写入 info 日志(原 writeLog 保留)
|
||||
// Info 日志
|
||||
static Future<void> writeLog(String content) async {
|
||||
print("[dailylog-->info] $content]");
|
||||
print("[dailylog-->info] $content");
|
||||
await _writeLogWithLevel('INFO', content);
|
||||
}
|
||||
|
||||
// 写入 warning 日志
|
||||
// Warning 日志
|
||||
static Future<void> writeWarning(String content) async {
|
||||
print("[dailylog-->waring] $content]");
|
||||
print("[dailylog-->warning] $content");
|
||||
await _writeLogWithLevel('WARNING', content);
|
||||
}
|
||||
|
||||
// 写入 error 日志
|
||||
// Error 日志
|
||||
static Future<void> writeError(String content) async {
|
||||
print("[dailylog-->error] $content]");
|
||||
print("[dailylog-->error] $content");
|
||||
await _writeLogWithLevel('ERROR', content);
|
||||
}
|
||||
|
||||
// 写入 debug 日志
|
||||
// Debug 日志
|
||||
static Future<void> writeDebug(String content) async {
|
||||
print("[dailylog-->debug] $content]");
|
||||
print("[dailylog-->debug] $content");
|
||||
await _writeLogWithLevel('DEBUG', content);
|
||||
}
|
||||
|
||||
static Future<void> printLog(String content) async {
|
||||
print("logger--->" + content);
|
||||
// await writeLog(content);
|
||||
}
|
||||
|
||||
// 读取当天日志
|
||||
// 读取当天日志,容错 UTF-8
|
||||
static Future<String> readTodayLog() async {
|
||||
final file = await _getLogFile();
|
||||
return await file.readAsString();
|
||||
try {
|
||||
return await file.readAsString(encoding: utf8);
|
||||
} catch (e) {
|
||||
final bytes = await file.readAsBytes();
|
||||
return utf8.decode(bytes, allowMalformed: true);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取所有日志文件(返回 File 列表)
|
||||
// 获取所有日志文件
|
||||
static Future<List<FileSystemEntity>> listLogFiles() async {
|
||||
final dir = await getApplicationDocumentsDirectory();
|
||||
final files = dir.listSync();
|
||||
@@ -75,7 +76,7 @@ class DailyLogUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取指定日期范围内的日志文件(包含起止日期)
|
||||
// 获取指定日期范围内日志文件
|
||||
static Future<List<File>> getLogsBetween(
|
||||
DateTime fromDate, DateTime toDate) async {
|
||||
final dir = await getApplicationDocumentsDirectory();
|
||||
@@ -85,16 +86,14 @@ class DailyLogUtils {
|
||||
for (DateTime date = fromDate;
|
||||
!date.isAfter(toDate);
|
||||
date = date.add(Duration(days: 1))) {
|
||||
final fileName = '${dateFormat.format(date)}.log';
|
||||
final file = File('${dir.path}/$fileName');
|
||||
if (await file.exists()) {
|
||||
logFiles.add(file);
|
||||
}
|
||||
final file = File('${dir.path}/${dateFormat.format(date)}.log');
|
||||
if (await file.exists()) logFiles.add(file);
|
||||
}
|
||||
|
||||
return logFiles;
|
||||
}
|
||||
|
||||
// 读取日期范围内日志,合并返回
|
||||
static Future<String> readLogsByDateRange(
|
||||
DateTime fromDate, DateTime toDate) async {
|
||||
try {
|
||||
@@ -102,43 +101,80 @@ class DailyLogUtils {
|
||||
final dateFormat = DateFormat('yyyy-MM-dd');
|
||||
String combinedLogs = '';
|
||||
|
||||
// 遍历从 fromDate 到 toDate 的日期
|
||||
for (DateTime date = fromDate;
|
||||
!date.isAfter(toDate);
|
||||
date = date.add(Duration(days: 1))) {
|
||||
final dateStr = dateFormat.format(date); // 格式化日期
|
||||
final file = File('${dir.path}/$dateStr.log'); // 日志文件路径
|
||||
|
||||
final file = File('${dir.path}/${dateFormat.format(date)}.log');
|
||||
if (await file.exists()) {
|
||||
final logContent = await file.readAsString();
|
||||
combinedLogs += '日志日期: $dateStr\n$logContent\n\n'; // 合并日志内容
|
||||
String content;
|
||||
try {
|
||||
content = await file.readAsString(encoding: utf8);
|
||||
} catch (_) {
|
||||
final bytes = await file.readAsBytes();
|
||||
content = utf8.decode(bytes, allowMalformed: true);
|
||||
}
|
||||
combinedLogs += '日志日期: ${dateFormat.format(date)}\n$content\n\n';
|
||||
}
|
||||
}
|
||||
|
||||
if (combinedLogs.isNotEmpty) {
|
||||
return combinedLogs; // 返回合并后的日志
|
||||
} else {
|
||||
return '该时间段内没有日志记录'; // 如果没有日志
|
||||
}
|
||||
return combinedLogs.isNotEmpty ? combinedLogs : '该时间段内没有日志记录';
|
||||
} catch (e) {
|
||||
return '读取日志失败: $e';
|
||||
}
|
||||
}
|
||||
|
||||
// 添加分享功能
|
||||
// static Future<void> exportLog(DateTime date) async {
|
||||
// try {
|
||||
// final dir = await getApplicationDocumentsDirectory();
|
||||
// final dateStr = DateFormat('yyyy-MM-dd').format(date);
|
||||
// final file = File('${dir.path}/$dateStr.log');
|
||||
// if (await file.exists()) {
|
||||
// await Share.shareXFiles(
|
||||
// [XFile(file.path)],
|
||||
// text: '应用日志 $dateStr',
|
||||
// );
|
||||
// }
|
||||
// } catch (e) {
|
||||
// print('导出日志失败: $e');
|
||||
// }
|
||||
// }
|
||||
// 导出所有日志为 zip 并分享(系统分享)
|
||||
static Future<void> exportAllLogs() async {
|
||||
try {
|
||||
final dir = await getApplicationDocumentsDirectory();
|
||||
final dateStr = DateFormat('yyyy-MM-dd_HH-mm-ss').format(DateTime.now());
|
||||
final zipPath = '${dir.path}/logs_$dateStr.zip';
|
||||
|
||||
final archive = Archive();
|
||||
|
||||
// 遍历日志文件
|
||||
final logFiles = dir
|
||||
.listSync()
|
||||
.whereType<File>()
|
||||
.where((f) => f.path.endsWith('.log') && f.existsSync());
|
||||
|
||||
if (logFiles.isEmpty) {
|
||||
print("没有日志文件可压缩!");
|
||||
return;
|
||||
}
|
||||
|
||||
for (var file in logFiles) {
|
||||
final name = file.path.split('/').last;
|
||||
final bytes = await file.readAsBytes(); // 读取原始字节
|
||||
final content =
|
||||
utf8.decode(bytes, allowMalformed: true); // 转 UTF-8,允许非 UTF-8
|
||||
final utf8Bytes = utf8.encode(content); // 写入压缩包
|
||||
archive.addFile(ArchiveFile(name, utf8Bytes.length, utf8Bytes));
|
||||
print("添加日志文件: ${file.path}, 大小: ${utf8Bytes.length}");
|
||||
}
|
||||
|
||||
// 写入 zip 文件
|
||||
final zipData = ZipEncoder().encode(archive);
|
||||
final zipFile = File(zipPath);
|
||||
await zipFile.writeAsBytes(zipData!);
|
||||
|
||||
print("压缩包生成成功: ${zipFile.path}, 大小: ${await zipFile.length()} 字节");
|
||||
|
||||
// 分享
|
||||
await Share.shareXFiles([XFile(zipFile.path)], text: '应用日志打包 $dateStr');
|
||||
} catch (e) {
|
||||
print('导出日志失败: $e');
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> printLog(String content) async {
|
||||
print("logger---> $content");
|
||||
// 如果你希望顺便写入 info 日志,也可以取消下面注释
|
||||
// await writeLog(content);
|
||||
}
|
||||
|
||||
static Future<String> readLogByDate(DateTime date) async {
|
||||
// 调用 readLogsByDateRange,fromDate 和 toDate 都是同一天
|
||||
return await readLogsByDateRange(date, date);
|
||||
}
|
||||
}
|
||||
|
||||
196
lib/common/util/JPushUtil.dart
Normal file
196
lib/common/util/JPushUtil.dart
Normal file
@@ -0,0 +1,196 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:EasyDartModule/EasyDartModule.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
import 'package:jpush_flutter/jpush_flutter.dart';
|
||||
import 'package:jpush_flutter/jpush_interface.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
||||
import 'package:vbvs_app/common/util/NotificationRouteManager.dart';
|
||||
import 'package:vbvs_app/controller/user_info_controller.dart';
|
||||
|
||||
class JPushUtil {
|
||||
static final JPushFlutterInterface _jpush = JPush.newJPush();
|
||||
static final GetStorage box = GetStorage();
|
||||
|
||||
/// 初始化极光推送
|
||||
static Future<void> initJPush() async {
|
||||
// 先申请通知权限
|
||||
await _requestNotificationPermission();
|
||||
|
||||
// 初始化 JPush
|
||||
_jpush.setup(
|
||||
appKey: 'ef31d487137311ed3d63ea7d', // 替换为你在极光控制台获取的 appKey
|
||||
channel: 'developer-default',
|
||||
production: true,
|
||||
debug: false,
|
||||
);
|
||||
|
||||
// 获取 RegistrationID
|
||||
_jpush.getRegistrationID().then((rid) {
|
||||
EasyDartModule.logger.info("[消息推送]flutter get registration id: $rid");
|
||||
print("flutter get registration id : $rid");
|
||||
box.write('rid', rid);
|
||||
});
|
||||
|
||||
// 添加推送消息回调
|
||||
_jpush.addEventHandler(
|
||||
onReceiveNotification: (Map<String, dynamic> message) async {
|
||||
print("接收到通知: $message");
|
||||
EasyDartModule.logger.info("[消息推送]接收到通知: $message");
|
||||
},
|
||||
onOpenNotification: (Map<String, dynamic> message) async {
|
||||
print("通知打开: $message");
|
||||
EasyDartModule.logger.info("[消息推送]通知打开: $message");
|
||||
openAppRouteByNotification(message);
|
||||
},
|
||||
onReceiveMessage: (Map<String, dynamic> message) async {
|
||||
print("接收到自定义消息: $message");
|
||||
EasyDartModule.logger.info("[消息推送]接收到自定义消息: $message");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 请求通知权限
|
||||
static Future<void> _requestNotificationPermission() async {
|
||||
if (Platform.isIOS) {
|
||||
_jpush.applyPushAuthority(const NotificationSettingsIOS(
|
||||
sound: true,
|
||||
alert: true,
|
||||
badge: true,
|
||||
));
|
||||
} else if (Platform.isAndroid) {
|
||||
var status = await Permission.notification.status;
|
||||
if (status.isDenied) {
|
||||
await Permission.notification.request();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 根据通知跳转页面
|
||||
// static Future<void> openAppRouteByNotification(
|
||||
// Map<String, dynamic> message) async {
|
||||
// try {
|
||||
// int type = message['extras']['cn.jpush.android.EXTRA']['mType'];
|
||||
// if (type == 1) {
|
||||
// var person =
|
||||
// jsonDecode(message['extras']['cn.jpush.android.EXTRA']['person']);
|
||||
// String mac = person['mac'];
|
||||
// UserInfoController userInfoController = Get.find();
|
||||
|
||||
// if (userInfoController.model.login == 0) {
|
||||
// box.write("needSleepReport", "true");
|
||||
// box.write("needSleepReport_person", person);
|
||||
// box.write("needSleepReport_mac", mac);
|
||||
// Get.toNamed("/loginPage");
|
||||
// } else {
|
||||
// Get.toNamed(
|
||||
// "/newSleepReportPage",
|
||||
// arguments: {
|
||||
// 'mac': mac,
|
||||
// 'type': 1,
|
||||
// "person": person,
|
||||
// 'backgroundImg': 'assets/images/new_background.png',
|
||||
// 'date': DateTime.now().millisecondsSinceEpoch,
|
||||
// 'person_show': false,
|
||||
// 'reportPadding': false,
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// } catch (e) {
|
||||
// EasyDartModule.logger.error("[打开APP异常]:$e");
|
||||
// DailyLogUtils.writeError("[打开APP异常]:$e");
|
||||
// }
|
||||
// }
|
||||
// static Future<void> openAppRouteByNotification(
|
||||
// Map<String, dynamic> message) async {
|
||||
// try {
|
||||
// int type = message['extras']['cn.jpush.android.EXTRA']['mType'];
|
||||
// if (type == 1) {
|
||||
// var person =
|
||||
// jsonDecode(message['extras']['cn.jpush.android.EXTRA']['person']);
|
||||
// String mac = person['mac'];
|
||||
// UserInfoController userInfoController = Get.find();
|
||||
|
||||
// if (userInfoController.model.login == 0) {
|
||||
// // 登录状态为 0,先保存需要跳转的标记
|
||||
// box.write("needSleepReport", "true");
|
||||
// box.write("needSleepReport_person", person);
|
||||
// box.write("needSleepReport_mac", mac);
|
||||
|
||||
// // 这里不要直接跳转,改为保存一个待跳转路由
|
||||
// box.write("pendingRoute", {
|
||||
// "route": "/loginPage",
|
||||
// "arguments": null,
|
||||
// });
|
||||
// } else {
|
||||
// // 已登录,保存跳转参数
|
||||
// box.write("pendingRoute", {
|
||||
// "route": "/newSleepReportPage",
|
||||
// "arguments": {
|
||||
// 'mac': mac,
|
||||
// 'type': 1,
|
||||
// "person": person,
|
||||
// 'backgroundImg': 'assets/images/new_background.png',
|
||||
// 'date': DateTime.now().millisecondsSinceEpoch,
|
||||
// 'person_show': false,
|
||||
// 'reportPadding': false,
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// } catch (e) {
|
||||
// EasyDartModule.logger.error("[打开APP异常]:$e");
|
||||
// DailyLogUtils.writeError("[打开APP异常]:$e");
|
||||
// }
|
||||
// }
|
||||
static Future<void> openAppRouteByNotification(
|
||||
Map<String, dynamic> message) async {
|
||||
try {
|
||||
int type = message['extras']['cn.jpush.android.EXTRA']['mType'];
|
||||
if (type == 1) {
|
||||
var person =
|
||||
jsonDecode(message['extras']['cn.jpush.android.EXTRA']['person']);
|
||||
String mac = person['mac'];
|
||||
UserInfoController userInfoController = Get.find();
|
||||
|
||||
if (userInfoController.model.login == 0) {
|
||||
NotificationRouteManager().box.write("needSleepReport", "true");
|
||||
NotificationRouteManager()
|
||||
.box
|
||||
.write("needSleepReport_person", person);
|
||||
NotificationRouteManager().box.write("needSleepReport_mac", mac);
|
||||
|
||||
NotificationRouteManager().savePendingRoute("/loginPage");
|
||||
} else {
|
||||
NotificationRouteManager().savePendingRoute(
|
||||
"/newSleepReportPage",
|
||||
arguments: {
|
||||
'mac': mac,
|
||||
'type': 1,
|
||||
"person": person,
|
||||
'backgroundImg': 'assets/images/new_background.png',
|
||||
'date': DateTime.now().millisecondsSinceEpoch,
|
||||
'person_show': false,
|
||||
'reportPadding': false,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 如果 APP 已经在前台,立即处理跳转
|
||||
NotificationRouteManager().handlePendingRoute();
|
||||
}
|
||||
} catch (e) {
|
||||
EasyDartModule.logger.error("[打开APP异常]:$e");
|
||||
DailyLogUtils.writeError("[打开APP异常]:$e");
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取 RegistrationID
|
||||
static Future<String?> getRegistrationID() async {
|
||||
return await _jpush.getRegistrationID();
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,11 @@ LanguageController languageController = Get.find();
|
||||
MHLanguageController mhLanguageController = Get.find();
|
||||
|
||||
class MyUtils {
|
||||
|
||||
static String formatTimestampToSleep(int milliseconds) {
|
||||
final date = DateTime.fromMillisecondsSinceEpoch(milliseconds);
|
||||
return "${date.year}-${date.month}-${date.day}";
|
||||
}
|
||||
static String formatDate(DateTime dateTime) {
|
||||
return "${dateTime.year}-${dateTime.month}-${dateTime.day.toString().padLeft(2, '0')}";
|
||||
}
|
||||
|
||||
33
lib/common/util/NotificationRouteManager.dart
Normal file
33
lib/common/util/NotificationRouteManager.dart
Normal file
@@ -0,0 +1,33 @@
|
||||
import 'package:ef/ef.dart';
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
|
||||
/// 单例通知路由管理
|
||||
class NotificationRouteManager {
|
||||
static final NotificationRouteManager _instance =
|
||||
NotificationRouteManager._internal();
|
||||
factory NotificationRouteManager() => _instance;
|
||||
NotificationRouteManager._internal();
|
||||
|
||||
final box = GetStorage();
|
||||
|
||||
/// 保存待跳转的路由
|
||||
void savePendingRoute(String route, {Map<String, dynamic>? arguments}) {
|
||||
box.write("pendingRoute", {
|
||||
"route": route,
|
||||
"arguments": arguments,
|
||||
});
|
||||
}
|
||||
|
||||
/// 立即尝试执行跳转(如果 GetMaterialApp 已就绪)
|
||||
void handlePendingRoute() {
|
||||
var pending = box.read("pendingRoute");
|
||||
if (pending != null) {
|
||||
String route = pending["route"];
|
||||
var args = pending["arguments"];
|
||||
Future.delayed(const Duration(milliseconds: 200), () {
|
||||
Get.toNamed(route, arguments: args);
|
||||
});
|
||||
box.remove("pendingRoute");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user