前言
我的上篇文章 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<String> 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<String> args = <String>[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参考:
本篇文章开源地址: