Flutter控制台调试插件fconsole的使用

发布于 1周前 作者 yibo5220 来自 Flutter

Flutter控制台调试插件fconsole的使用

fconsole 是一个用于调试的面板组件,类似于微信小程序的 v-console。它在页面上创建一个可拖拽的悬浮窗,点击悬浮窗可启用 log 列表面板。本文将介绍如何在Flutter项目中使用 fconsole 插件,并提供完整的示例代码。

主要功能

  • 显示悬浮窗,随时打开 Log 页面
  • 可自定义页面插入,项目专属调试页不用藏
  • 使用 FlowLog 可记录流程事件,网络 Log 清晰可见(支持json树状展示)
  • 分享完整 FlowLog 网络请求,一键反馈(甩锅)后端报错

示例截图

Log Flow Flow Detail
Log Flow Flow Detail

使用方法

启动应用并显示悬浮窗

void main() => runAppWithFConsole(
      MyApp(),
      delegate: MyCardDelegate(),
      beforeRun: () async {
        WidgetsFlutterBinding.ensureInitialized();
        // Do some init before runApp
      }
    );

启动和隐藏悬浮窗

// 启动悬浮窗
showConsole();
// 隐藏悬浮窗
hideConsole();

自定义页面

你可以通过扩展 FConsoleCardDelegate 来自定义页面:

class MyCardDelegate extends FConsoleCardDelegate {
  [@override](/user/override)
  List<FConsoleCard> cardsBuilder(DefaultCards defaultCards) {
    return [
      defaultCards.logCard,
      defaultCards.flowCard,
      /// Custom Page by
      FConsoleCard(
        name: "my",
        builder: (ctx) => CustomLogPage(),
      ),
      defaultCards.sysInfoCard,
    ];
  }
}

class CustomLogPage extends StatelessWidget {
  const CustomLogPage({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment.center,
      child: Text('custom page content'),
    );
  }
}

拦截原生 print 函数和未捕获的异常

替换 runApprunFConsoleApp

void main() => runFConsoleApp(MyApp());

然后,原生 printthrow 将被拦截:

SettingRow(
  icon: Icons.warning,
  text: '原生Print',
  right: Container(),
  onTap: () {
    print('${DateTime.now().toIso8601String()}');
  },
),
SettingRow(
  icon: Icons.warning,
  text: '原生Throw',
  right: Container(),
  onTap: () {
    throw '${DateTime.now().toIso8601String()}';
  },
),

添加 log

// 添加log
FConsole.log("打印了一行log");
FConsole.error("打印了一行error");

创建 FlowLog(支持JSON)

FlowLog.of('分享启动').log('用户进入页面 $id');
FlowLog.of('分享启动').log(map); // 传入Map/List将会以json形式展示
FlowLog.of('分享启动').error('查询分享信息4错误: $map');
FlowLog.of('分享启动').end();

FlowLog with Dio

使用 FlowLog 记录每一次网络请求:

extension _GetLogID on RequestOptions {
  String get logId {
    return '[$method]${uri.path}';
  }
}

_http = Dio();
_http!.interceptors.add(InterceptorsWrapper(
  onRequest: (RequestOptions options, handler) {
    var _logger = FlowLog.ofNameAndId(
      options.logId,
      id: '${options.hashCode}',
    );
    _logger.log('开始请求 ${options.method}');
    _logger.log('data:${options.data}');
    handler.next(options);
  },
  onResponse: (e, handler) {
    var _logger = FlowLog.ofNameAndId(
      e.requestOptions.logId,
      id: '${e.requestOptions.hashCode}',
    );
    _logger.log('请求结束');
    _logger.end();
    handler.next(e);
  },
  onError: (e, handler) {
    var _logger = FlowLog.ofNameAndId(
      e.requestOptions.logId,
      id: '${e.requestOptions.hashCode}',
    );
    _logger.error('请求错误:$e');
    _logger.end('请求错误结束');
    handler.next(e);
  },
));

完整示例代码

以下是一个完整的示例代码,展示了如何集成 fconsole 并实现上述功能:

import 'package:flutter/material.dart';
import 'package:fconsole/fconsole.dart';

void main() => runAppWithFConsole(
      MyApp(),
      delegate: MyCardDelegate(),
    );

class MyCardDelegate extends FConsoleCardDelegate {
  [@override](/user/override)
  List<FConsoleCard> cardsBuilder(DefaultCards defaultCards) {
    return [
      defaultCards.logCard,
      defaultCards.flowCard,
      FConsoleCard(
        name: "Custom",
        builder: (ctx) => CustomLogPage(),
      ),
      defaultCards.sysInfoCard,
    ];
  }
}

class CustomLogPage extends StatelessWidget {
  const CustomLogPage({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment.center,
      child: Text('custom page content'),
    );
  }
}

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool get consoleHasShow => FConsole.instance.status.value != FConsoleStatus.hide;

  double slideValue = 0;

  [@override](/user/override)
  void initState() {
    super.initState();
    FConsole.instance.status.addListener(() {
      setState(() {});
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return ConsoleWidget(
      options: ConsoleOptions(),
      child: MaterialApp(
        home: Scaffold(
          appBar: AppBar(
            title: const Text('FConsole example app'),
          ),
          body: ListView(
            children: [
              AspectRatio(
                aspectRatio: 24 / 9,
                child: Center(
                  child: Text('FConsole Example', style: TextStyle(color: Colors.blue)),
                ),
              ),
              SettingRow(
                icon: consoleHasShow ? Icons.tab : Icons.tab_unselected,
                text: consoleHasShow ? 'Console打开' : 'Console关闭',
                right: Container(
                  height: 36,
                  padding: EdgeInsets.only(right: 12),
                  child: Switch(
                    value: consoleHasShow,
                    onChanged: (v) {
                      if (v) {
                        showConsole();
                      } else {
                        hideConsole();
                      }
                      setState(() {});
                    },
                  ),
                ),
              ),
              Container(height: 12),
              SettingRow(
                icon: Icons.info_outline,
                text: '打印log',
                right: Container(),
                onTap: () {
                  fconsole.log('打印信息:', DateTime.now());
                },
              ),
              SettingRow(
                icon: Icons.warning,
                text: '打印error',
                right: Container(),
                onTap: () {
                  fconsole.error('打印Error:', DateTime.now());
                },
              ),
              Container(height: 12),
              SettingRow(
                icon: Icons.edit,
                text: '原生Print',
                right: Container(),
                onTap: () {
                  print('${DateTime.now().toIso8601String()}');
                },
              ),
              SettingRow(
                icon: Icons.edit,
                text: '原生Throw',
                right: Container(),
                onTap: () {
                  var _ = [][123];
                  throw '${DateTime.now().toIso8601String()}';
                },
              ),
              Container(height: 12),
              SettingRow(
                icon: Icons.info_outline,
                text: '滑动事件Flow',
                right: Slider(
                  value: slideValue,
                  onChanged: (v) {
                    FlowLog.of('滑动Slider').log({
                      'type': 'slide',
                      "value": [
                        for (var i = 0; i < 100; i++)
                          {
                            "value": {
                              "value": {
                                "value": "$v",
                              },
                            },
                          },
                      ],
                    });
                    setState(() {
                      slideValue = v;
                    });
                  },
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class SettingRow extends StatelessWidget {
  final double? padding;
  final IconData? icon;
  final Widget? right;
  final Widget? beforeRight;
  final String? text;
  final Color? textColor;
  final Function? onTap;
  const SettingRow({
    Key? key,
    this.padding = 14,
    this.icon,
    this.text,
    this.textColor,
    this.right,
    this.onTap,
    this.beforeRight,
  }) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    var child = Container(
      color: Colors.white,
      padding: EdgeInsets.only(left: 8),
      child: Row(
        children: <Widget>[
          icon == null
              ? Container()
              : Container(
                  margin: EdgeInsets.symmetric(horizontal: 16),
                  child: Icon(
                    icon,
                    size: 20,
                    color: textColor,
                  ),
                ),
          Expanded(
            child: Container(
              padding: EdgeInsets.symmetric(vertical: padding ?? 0),
              decoration: BoxDecoration(
                border: Border(
                  bottom: BorderSide(color: Colors.grey.shade300),
                ),
              ),
              child: Row(
                children: <Widget>[
                  Expanded(
                    child: Container(
                      child: Text(
                        text ?? '--',
                        style: TextStyle(
                          color: textColor,
                        ),
                      ),
                    ),
                  ),
                  Row(
                    children: <Widget>[
                      beforeRight ?? Container(),
                      Container(
                        margin: EdgeInsets.only(left: 8),
                        child: right ??
                            Container(
                              margin: EdgeInsets.only(right: 12),
                              child: Icon(
                                Icons.arrow_forward_ios,
                                color: Colors.grey.shade500,
                                size: 12,
                              ),
                            ),
                      ),
                    ],
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
    if (onTap == null) {
      return child;
    }
    return GestureDetector(
      onTap: () => onTap!(),
      child: child,
    );
  }
}

更多关于Flutter控制台调试插件fconsole的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter控制台调试插件fconsole的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter开发中,fconsole 是一个用于控制台调试的插件,可以帮助开发者更方便地在控制台输出日志、调试信息等。以下是如何在Flutter项目中使用 fconsole 插件的详细步骤和相关代码案例。

1. 添加依赖

首先,在你的 pubspec.yaml 文件中添加 fconsole 依赖:

dependencies:
  flutter:
    sdk: flutter
  fconsole: ^最新版本号  # 替换为实际的最新版本号

2. 导入插件

在你的 Dart 文件中导入 fconsole 插件:

import 'package:fconsole/fconsole.dart';

3. 初始化 FConsole

在你的 Flutter 应用的入口文件(通常是 main.dart)中初始化 FConsole

import 'package:flutter/material.dart';
import 'package:fconsole/fconsole.dart';

void main() {
  // 初始化FConsole
  FConsole.init(
    enable: true, // 是否启用FConsole
    filterLog: (log) {
      // 这里可以过滤日志,返回true表示显示该日志,false表示不显示
      return true;
    },
    logMaxLen: 1000, // 控制台显示的最大日志条数
  );

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter FConsole Demo'),
        ),
        body: Center(
          child: MyHomePage(),
        ),
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        ElevatedButton(
          onPressed: () {
            // 输出普通日志
            FConsole.log('This is a log message.');
          },
          child: Text('Log'),
        ),
        ElevatedButton(
          onPressed: () {
            // 输出警告日志
            FConsole.warn('This is a warning message.');
          },
          child: Text('Warn'),
        ),
        ElevatedButton(
          onPressed: () {
            // 输出错误日志
            FConsole.error('This is an error message.');
          },
          child: Text('Error'),
        ),
      ],
    );
  }
}

4. 运行并查看控制台输出

运行你的 Flutter 应用,并点击按钮,你会在控制台中看到相应的日志输出。

5. 高级用法

fconsole 还支持更多的功能,比如自定义日志格式、分组显示日志等。以下是一个更复杂的示例,展示了如何自定义日志格式:

FConsole.init(
  enable: true,
  filterLog: (log) => true,
  logMaxLen: 1000,
  logFormat: (log) => {
    "time": DateTime.now().toLocal().toString(),
    "level": log.level,
    "tag": log.tag,
    "message": log.message,
  }.toString(),
);

在这个例子中,logFormat 是一个函数,用于自定义日志的输出格式。你可以根据自己的需求来定义日志的格式。

总结

fconsole 是一个功能强大的 Flutter 控制台调试插件,可以帮助开发者更方便地进行日志调试。通过上述步骤,你可以轻松地在 Flutter 项目中使用 fconsole 插件,并自定义日志输出格式以满足你的需求。

回到顶部