锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

我用Flutter Deskstop做了一个Mars Xlog日志解析工具

时间:2023-02-03 12:00:00 高压电阻器5w500m

前言

我的最后一篇文章 2022腾讯Mars Xlog日志系统集成指南-iOS篇 详细的介绍iOS下接入Xlog日志系统指南。 Xlog日志接入了之后,我们要对它进行解析,如果不解析那就是一堆加密的二进制数据。常规的分析方案是使用Mars官方的python文件 修改一下private key可以直接分析,但因为是用的python2且需要pip安装一堆库,很多人用起来很痛苦,所以我是基于Flutter Deskstop 做的Mars Xlog日志分析工具XlogDecoder就这样诞生了。此工具采用Flutter目前只支持编写Mac,不需要内置解码库python环境。

代码过程

一、编译Python文件成可执行文件

Mars解析Xlog这三个日志主要由官方源码组成Python文件构成,一个是加密分析脚本,一个是不加密分析脚本,另一个是提供生成RSA Key脚本。如果我们想做桌面GUI如果工具不依赖机器环境,我们只能使用这三个py将文件编译成可执行文件供应直接运行。

编译python文件成为可执行文件,我们使用著名的文件pyinstaller制作。

  • 安装方式
pip3 install pyinstaller 

由于Mars的脚本都是python2.我们需要这个,而且版本很低。我花了很长时间才确认版本可以支持编译。我们需要这样安装 (注意Mac 12.3 之后会移除自带python2.如果需要自己安装python2)

 python -m pip install PyInstaller==3.3.1  
  • 开始编译可执行文件

decode_mars_crypt_log_file.py

因为默认是写死的private_key, 我们需要修改脚本,让脚本支持输入参数private key

//decode_mars_crypt_log_file.py 修改  PRIV_KEY=sys.argv[1] # PRIV_KEY = "145aa7717bf9745b91e9569b80bbf1eedaa6cc6cd0e26317d810e35710f44cf8"  //main 函数转换为接收参数2 main(sys.argv[2:])  然后执行编译命令:  python -m PyInstaller ./decode_mars_crypt_log_file.py  

新添加的编译产品disk在目录下,会有一个人和你在一起py同名文件夹,剩下两个py我们可以用同样的方式编译文件。

二、导入编译产品到flutter项目

我们将导入三个可执行文件flutter image目录,

pubspec.yaml 指定目录

三、应用内获取assets目录

Flutter编译包装后,所有资源都放在一起flutter_assets在目录中,我强行找到它。

 static final String _assetsPath = Platform.isWindows       ? '../data/flutter_assets/images'       : '../../Frameworks/App.framework/Resources/flutter_assets/images';   static File mainFile = File(Platform.resolvedExecutable);   static Directory _assetsDir =       Directory(path.normalize(path.join(mainFile.path, _assetsPath)));  

四、通过相关UI事件以及Flutter 自带 Process类运行执行文件

  • 例如,生成一个新的RSA

 //操作方法  Future genKey() async {     var pyPath = path.joinAll([       _assetsDir.path,       "gen_key",       "gen_key"     ]);      var process = await Process.run(pyPath, []);     print("result:\n");     print("${process.stdout}");     return process.stdout;   }    //按钮事件  PushButton(                                 buttonSize: ButtonSize.large,                                 child: Text('生成 RSA Key'),                                 onPressed: () async {                                   var result = await controller.genKey();                                   showMacosAlertDialog(                                     barrierDismissible: true,                                     useRootNavigator: false,                                     context: context,                                     builder: (context) => MacosAlertDialog(                                       appIcon: Image.asset(                                         "images/app_icon.png",                                         width: 64,                                         height: 64,                                       ),                                       title: Text(                                         '请记住你生成的RSA Key',                                         style: TextStyle(                                             fontWeight: FontWeight.w500,                                             fontSize: 16),                                       ),                                       message: Text(                                         result,                                       ),                                       horizontalActions: false,                                       primaryButton: PushButton(                                         buttonSize: ButtonSize.large,                                         child: const Text(复制),                                         onPressed: () {                                           ClipboardData data =                                               ClipboardData(text: result);                                           Clipboard.setData(data);                                           showToast("粘贴板已复制",                                               textPadding: EdgeInsets.all(15));                                           Navigator.of(context).pop();                                         },                                  ),
                                      secondaryButton: PushButton(
                                        buttonSize: ButtonSize.large,
                                        child: const Text('取消'),
                                        onPressed: Navigator.of(context).pop,
                                      ),
                                    ),
                                  );
                                },
                              ),
 

  • 解析日志

解析日志我们可以选择直接拖动xlog日志文件过来,也可以选择点击按钮选择。如果是文件夹拖过来我也会遍历目录符合xlog后缀的我全都是添加进去队列解析。

核心解析日志方法:


void beginCompressTask({required XlogInfoItemViewModel vm}) async {
    if (savePath.value.length == 0) {
      print("save path no define");
      vm.updateStatus(XlogInfoStatus.fail);
      taskList.refresh();
      return;
    }

    if (this.isEnableCrypt.value == true && (this.cryptMd5.value.isEmpty || this.cryptMd5.value.length != 64)) {
      print("private key is empty");
      showToast("Private Key 为空或长度不对(64位)", textPadding: EdgeInsets.all(15));
      vm.updateStatus(XlogInfoStatus.fail);
      taskList.refresh();
      return;
    }

    print("save path : $savePath");

    var dir = await createDirectory(savePath.value);
    if (dir == null) {
      vm.updateStatus(XlogInfoStatus.fail);
      taskList.refresh();
      return;
    }

    var pyPath = path.joinAll([
      _assetsDir.path,
      "decode_mars_crypt_log_file",
      "decode_mars_crypt_log_file"
    ]);

    if (this.isEnableCrypt.value == false) {
      pyPath = path.joinAll([
        _assetsDir.path,
        "decode_mars_nocrypt_log_file",
        "decode_mars_nocrypt_log_file"
      ]);
    }

    List args = [vm.file.path];
    if (this.isEnableCrypt.value == true) {
      args.insert(0, this.cryptMd5.value);
    }

    var process = await Process.run(pyPath, args);

    if (process.exitCode != 0) {
      showToast("Xlog解析失败,请检查你的Private Key是否正确", textPadding: EdgeInsets.all(15));
      vm.updateStatus(XlogInfoStatus.fail);
      taskList.refresh();
      return;
    }

    var file = File(vm.file.path + ".log");

    var isExist = await file.exists();
    if (isExist) {
      await Process.run("mv", [
        "-f",
        file.path,
        savePath.value,
      ]);
      vm.saveFile = File(path.joinAll([savePath.value, file.fileName]));
      vm.updateStatus(XlogInfoStatus.success);
      taskList.refresh();
    } else {
      vm.updateStatus(XlogInfoStatus.fail);
      taskList.refresh();
    }
  }

末尾

本次开源的工具暂时只支持Mac。 pyinstaller输出的也是mac才支持的可执行文件,由于pyinstaller也是跨平台的,理论上在windows机器安装 pyinstaller 直接输出适配windows的可执行文件,不同平台则替换一下相应文件,就可以适配windows。如果本次开源了反响比较大,后续我也会支持windows。否则本篇文章则可以给大家供学习,理论上Flutter的很多工具类软件都可以基于此方法编写。

附件

iOS接入xlog的Demo参考:

  • xlog_ios_demo

本篇文章开源地址:

  • xlog_decoder
锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章