Day9_开源鸿蒙_Flutter_for_OpenHarmony_logger实战_本地日志与异常捕获
2026/5/8 15:12:32 网站建设 项目流程

开源鸿蒙 Flutter for OpenHarmony:logger 实战(本地日志 + 全局异常捕获)

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

离线笔记做到 Day8,功能看起来已经很“像样”了,但只要开始真机跑,就会遇到一个很现实的问题:用户说“闪退/点不了/没反应”,你没有任何线索

尤其是 OpenHarmony 场景下:

  • 有些问题只在真机/模拟器出现
  • 没接入远程日志平台(我们这个项目是纯离线)
  • print很难统一格式,也不方便在手机上复制出来发给你排查

Day9 的目标:把日志做成“可用工具”

  • 统一日志格式(带时间、级别)
  • 在应用内保存一份“最近 300 行日志”
  • 加一个“应用日志”页面:复制/清空/手动写日志/模拟异常
  • 全局捕获未处理异常:FlutterError / PlatformDispatcher / runZonedGuarded

1. 今天用到的第三方库:logger(为什么不用 print)

print的问题不在于它不能用,而在于:

  • 没级别(info/warn/error)
  • 没统一格式(时间、tag、堆栈)
  • 打出来之后,手机上很难“拿到一份完整日志”

logger就是做这件事的:把日志当成一个正式能力来用。

添加依赖:

flutter pubaddlogger

2. 实现一个 AppLogger:既写控制台,也写“内存日志”

📌 文件:lib/shared/app_logger.dart

我们做一个单例AppLogger,有两个输出方向:

  1. logger输出到控制台(调试时看)
  2. 自己维护一个lines(最多 300 行),用于 App 内展示/复制
classAppLogger{AppLogger._();staticfinalAppLoggerinstance=AppLogger._();final_logger=Logger(printer:PrettyPrinter(methodCount:0,errorMethodCount:20,colors:false,printEmojis:false,dateTimeFormat:DateTimeFormat.onlyTimeAndSinceStart,),);finallines=<String>[].obs;}

然后封装 3 个最常用的方法:i/w/e

voidi(Stringmessage){_logger.i(message);_add('I',message);}voidw(Stringmessage,{Object?error,StackTrace?stackTrace}){_logger.w(message,error:error,stackTrace:stackTrace);_add('W',_format(message,error,stackTrace));}voide(Stringmessage,{Object?error,StackTrace?stackTrace}){_logger.e(message,error:error,stackTrace:stackTrace);_add('E',_format(message,error,stackTrace));}

📌_add里做两件事:

  • 拼一个本地时间戳(更适合读)
  • 超过 300 行就裁掉最旧的
void_add(Stringlevel,Stringtext){finalnow=DateTime.now();finalts='${now.year}-${_two(now.month)}-${_two(now.day)}${_two(now.hour)}:${_two(now.minute)}:${_two(now.second)}';lines.add('[$ts][$level]$text');if(lines.length>300){lines.removeRange(0,lines.length-300);}}

3. 全局异常捕获:把“没抓住的异常”也写进日志

很多异常不是你主动 try/catch 的,它会直接冒到框架层。
这一步就是把三条常用的“兜底入口”接上。

📌 文件:lib/main.dart

3.1 FlutterError.onError(Flutter 框架错误)

FlutterError.onError=(details){FlutterError.presentError(details);AppLogger.instance.e('FlutterError',error:details.exception,stackTrace:details.stack,);};

3.2 PlatformDispatcher.instance.onError(更底层的 uncaught)

PlatformDispatcher.instance.onError=(error,stack){AppLogger.instance.e('PlatformDispatcher',error:error,stackTrace:stack);returntrue;};

3.3 runZonedGuarded(兜底一层)

runZonedGuarded(()=>runApp(constNotesApp()),(error,stack)=>AppLogger.instance.e('Zone',error:error,stackTrace:stack),);

到这里,哪怕你忘了 try/catch,至少也能在“应用日志”页看到异常堆栈。


4. 做一个“应用日志”页:复制/清空/模拟异常

📌 文件:lib/features/debug/ui/app_logs_page.dart

4.1 日志列表:用 Obx 实时刷新

linesRxList<String>,所以用Obx渲染:

Expanded(child:Obx((){finallines=logger.lines;if(lines.isEmpty)returnconstCenter(child:Text('暂无日志'));returnListView.builder(itemCount:lines.length,itemBuilder:(_,i)=>SelectableText(lines[i]),);}),)

4.2 顶部按钮:复制/清空

复制时直接把整份dump()放到剪贴板:

awaitClipboard.setData(ClipboardData(text:logger.dump()));

清空就一句:

logger.clear();

4.3 “模拟异常”按钮(方便自测)

这一步不是给用户用的,是开发时确认“全局兜底有没有生效”:

Timer.run(()=>throwStateError('Day9 模拟异常'));

点一下,日志页应该能看到一条 error 级别的堆栈信息。

📷 截图位(建议 2~3 张)

![Day9-日志入口按钮](图_day9_log_entry.png) ![Day9-日志页列表与复制](图_day9_log_page.png) ![Day9-模拟异常日志出现](图_day9_throw_log.png)

5. 给日志页加入口:放在列表页右上角

📌 文件:lib/features/note/ui/notes_list_page.dart

IconButton(onPressed:(){Navigator.of(context).push(MaterialPageRoute(builder:(_)=>constAppLogsPage()),);},icon:constIcon(Icons.bug_report),tooltip:'日志',),

这样真机遇到问题时,让对方打开日志页点“复制”,直接把文本发过来,排查成本会小很多。


📷


6. 自测清单(Day9)

  • 打开日志页,点“写日志” → 列表出现一条 info 记录
  • 点“模拟异常” → 列表出现 error + 堆栈
  • 点“复制” → 能把日志完整复制到剪贴板(随便粘贴到备忘录验证)
  • 点“清空” → 列表清空

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询