{"id":19273066,"url":"https://github.com/fluttercandies/fconsole","last_synced_at":"2025-07-08T16:40:12.499Z","repository":{"id":56828725,"uuid":"258953078","full_name":"fluttercandies/fconsole","owner":"fluttercandies","description":"一个用于调试的面板","archived":false,"fork":false,"pushed_at":"2024-06-24T09:31:52.000Z","size":1099,"stargazers_count":56,"open_issues_count":6,"forks_count":13,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-23T21:32:27.339Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fluttercandies.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-26T06:04:48.000Z","updated_at":"2025-04-22T03:45:40.000Z","dependencies_parsed_at":"2024-06-24T10:55:45.363Z","dependency_job_id":"b6c37a03-a5a2-42c7-8709-f1189c4fd896","html_url":"https://github.com/fluttercandies/fconsole","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/fluttercandies/fconsole","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Ffconsole","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Ffconsole/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Ffconsole/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Ffconsole/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fluttercandies","download_url":"https://codeload.github.com/fluttercandies/fconsole/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Ffconsole/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264305712,"owners_count":23588183,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T20:40:41.708Z","updated_at":"2025-07-08T16:40:12.475Z","avatar_url":"https://github.com/fluttercandies.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# fconsole\n\n一个用于调试的面板组件，类似微信小程序的 v-console：在页面上创建一个可拖拽的悬浮窗，点击悬浮窗可启用 log 列表面板。\n\n主要功能：\n\n- 显示悬浮窗，随时打开 Log 页面\n- 可自定义页面插入，项目专属调试页不用藏\n- 使用 FlowLog 可记录流程事件，网络 Log 清晰可见(支持json树状展示)\n- 分享完整 FlowLog 网络请求，一键反馈(甩锅)后端报错\n\n## 截图\n|  Log   | Flow  | Flow Detail  |\n|  ----  | ----  | ----  |\n| ![](./screenshot/log.PNG)  | ![](./screenshot/flow.PNG) | ![](./screenshot/flow-detail.PNG) |\n\n## 使用\n\n```dart\n// 同时拦截原生 print 函数和未捕获的异常\nvoid main() =\u003e runAppWithFConsole(\n      MyApp(),\n      delegate: MyCardDelegate(),\n      beforeRun: () async {\n        WidgetsFlutterBinding.ensureInitialized();\n        // Do some init before runApp\n      }\n    );\n```\n\n然后才可以使用下列方法：\n\n### 启动悬浮窗\n\n只需要调用顶层方法就可以打开悬浮窗\n\n```dart\n// 启动悬浮窗\nshowConsole();\n// 隐藏悬浮窗\nhideConsole();\n```\n\n### 自定义页面\n\n很多时候我们都需要插入自定义页面，可以这样做：\n\n```dart\n/// More code in file: ./example/lib/main.dart\nvoid main() =\u003e runAppWithFConsole(\n      MyApp(),\n      delegate: MyCardDelegate(),\n    );\n\nclass MyCardDelegate extends FConsoleCardDelegate {\n  @override\n  List\u003cFConsoleCard\u003e cardsBuilder(DefaultCards defaultCards) {\n    return [\n      defaultCards.logCard,\n      defaultCards.flowCard,\n      /// Custom Page by\n      FConsoleCard(\n        name: \"my\",\n        builder: (ctx) =\u003e CustomLogPage(),\n      ),\n      defaultCards.sysInfoCard,\n    ];\n  }\n}\n\nclass CustomLogPage extends StatelessWidget {\n  const CustomLogPage({Key key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      alignment: Alignment.center,\n      child: Text('custom page content'),\n    );\n  }\n}\n```\n\n卡片内无法使用OKToast，若要显示 toast 信息，FConsole提供了一个showMessage方法：\n\n```dart\nFConsole.showMessage(\"Copy Success\");\n```\n\n### 拦截原生 print 函数和未捕获的异常\n\n`fconsole`可以拦截原先的`print`函数，包括其他库中的`print`语句和未捕获的`throw`同样可以被拦截。\n\n拦截后，`print`将等效于`FConsole.log`，未捕获的错误将等效于`FConsole.error`。\n\n要使用此功能，请将`runApp`替换为`runFConsoleApp`:\n\n```dart\nvoid main() =\u003e runFConsoleApp(MyApp());\n```\n\n然后，原生`print`和`throw`将被拦截:\n\n```dart\n// 具体代码见example\nSettingRow(\n  icon: Icons.warning,\n  text: '原生Print',\n  right: Container(),\n  onTap: () {\n    print('${DateTime.now().toIso8601String()}');\n  },\n),\nSettingRow(\n  icon: Icons.warning,\n  text: '原生Throw',\n  right: Container(),\n  onTap: () {\n    throw '${DateTime.now().toIso8601String()}';\n  },\n),\n```\n\n### 添加 log\n\n使用 FConsole 添加 log 非常简单：\n\n```dart\n// 添加log\nFConsole.log(\"打印了一行log\");\nFConsole.log(\"打印了一行log\");\nFConsole.log(\"打印了一行log\");\nFConsole.log(\"打印了一行log\");\n// 添加error\nFConsole.error(\"打印了一行error\");\nFConsole.error(\"打印了一行error\");\nFConsole.error(\"打印了一行error\");\nFConsole.error(\"打印了一行error\");\n```\n\n然后就可以在 FConsole 内查看 log 记录。\n\n### 创建 FlowLog(支持JSON)\n\n可以使用`FlowLog`的形式记录 Log:\n\n```dart\nFlowLog.of('分享启动').log('用户进入页面 $id');\nFlowLog.of('分享启动').log('获取到分享值1 $shareId');\nFlowLog.of('分享启动').log('查询分享信息1 成功');\nFlowLog.of('分享启动').log('获取到分享值2 $shareId');\nFlowLog.of('分享启动').log('查询分享信息2 成功');\nFlowLog.of('分享启动').log('获取到分享值3 $shareId');\nFlowLog.of('分享启动').log('查询分享信息3 成功');\nFlowLog.of('分享启动').log('获取到分享值4 $shareId');\nFlowLog.of('分享启动').log(map);// 传入Map/List将会以json形式展示\nFlowLog.of('分享启动').error('查询分享信息4错误: $map');\nFlowLog.of('分享启动').end();\n```\n\n也可以使用变量来记录\n\n```dart\nvar logger = FlowLog.of('分享启动');\nlogger.log('用户进入页面 $id');\nlogger.log('获取到分享值 $shareId');\nlogger.error('查询分享信息错误: $map');\nlogger.end();\n```\n\nFlowLog 可以记录用户的一系列行为，在用户出现问题时，通过 Console 信息即可快速定位问题。\n\nFlowLog 的优势在于，在同一页面上的操作可以分开记录，不会互相干扰，例如同时处理两张图片，一张成功而另一张失败，会按 id 形成两个不同的 FlowLog。\n\n### FlowLog with Dio\n\n一个很好的实践：使用 FlowLog 记录每一次网络请求\n\nTips: 使用“Share”可分享完整网络请求，一键反馈(甩锅)后端报错。\n\n```dart\nextension _GetLogID on RequestOptions {\n  String get logId {\n    return '[$method]${uri.path}';\n  }\n}\n\n_http = Dio();\n_http!.interceptors.add(InterceptorsWrapper(\n  onRequest: (RequestOptions options, handler) {\n    var _logger = FlowLog.ofNameAndId(\n      options.logId,\n      id: '${options.hashCode}',\n    );\n    _logger.log('开始请求 ${options.method}');\n    _logger.log('data:${options.data}');\n    _logger.log('params:${options.queryParameters}');\n    _logger.log('header:${options.headers.toString()}');\n    handler.next(options);\n  },\n  onResponse: (e, handler) {\n    var _logger = FlowLog.ofNameAndId(\n      e.requestOptions.logId,\n      id: '${e.requestOptions.hashCode}',\n    );\n    _logger.log('请求结束');\n    _logger.log('Http Status Code:${e.statusCode}');\n    _logger.log('Response Data:\\n${e.data}');\n    _logger.end();\n    handler.next(e);\n  },\n  onError: (e, handler) {\n    var _logger = FlowLog.ofNameAndId(\n      e.requestOptions.logId,\n      id: '${e.requestOptions.hashCode}',\n    );\n    _logger.error('请求错误:$e');\n    _logger.end('请求错误结束');\n    handler.next(e);\n  },\n));\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluttercandies%2Ffconsole","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffluttercandies%2Ffconsole","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluttercandies%2Ffconsole/lists"}