Flutter冷知识 | 获取dart的print内容

前言

这得从我在群里时不时冒泡说起。

此刻楼上大佬装成萌新,所以我就来了。

也就是看了群里一位老哥写的 Flutter 组件,可以查看当前打印的日志,还是挺厉害,但是打印的时候就只能调用他给定的方法来 print ,在写安卓原生的时候有过这一需求,就是需要在 app 内部拿到 System.out.print 方法打印的字符。

java 中则是开放了这一方法。

1
2
System.setErr(new PrintStream(***));
System.setOut(new PrintStream(***));

这样所有的标准输出与标准错误输出都定向到了自己设置的流中,这个流可以指向文件、管道、或是文件描述符。

大致相关的一些需求:

  • 需要主动获取 dartprint 内容,方便分析,因为过长的内容 print 是会被截断的。
  • 添加少量代码的情况下让自己的上线产品的输出不能随意被看见。

因为在平时的开发中,经常有被调试的手机运行着其他的 Flutter 程序,自己的电脑终端就能拿到它的输出。

初步分析

从 dart 内部

dartstdio.dart 文件中有以下几个变量。

1
2
3
int _stdinFD = 0;
int _stdoutFD = 1;
int _stderrFD = 2;

还有一个重定向输出的方法。

1
2
3
4
5
void _setStdioFDs(int stdin, int stdout, int stderr) {
_stdinFD = stdin;
_stdoutFD = stdout;
_stderrFD = stderr;
}

几乎这个文件所有的东西都加上了 _ ,而我们能拿到的只有 stdin/stdout/stderr,并且能够操作的方法也比较少。

从进程

一个进程至少有 0,1,2 三个文件描述符,它们分别对应 stdin/stdout/stderr

举个例子:

我们在 c 语言用调用以下代码:

1
printf('hi');

它其实等价于:

1
2
char tmp = "hi";
write(1, tmp, strlen(tmp));

所以我考虑拷贝这三个文件描述符,让他们指向其他的地方。

确保在父进程执行拷贝函数,fork 后的子进程的文件描述符是分开。

dup2 函数

dup2 函数用来拷贝文件描述符。

函数原型:

1
int dup2 (int oldfd,int newfd)

若参数 newfd 已经被程序使用,则系统就会将 newfd 所指的文件关闭,若 newfd 等于 oldfd ,则返回 newfd ,而不关闭 newfd 所指的文件。dup2 所复制的文件描述符与原来的文件描述符共享各种文件状态。共享所有的锁定,读写位置和各项权限或 flags 等。

例子

我们调用

1
2
int filefd = open("./tmp.txt", O_RDWR);
dup2(filefd,0);

O_RDWR 表示可读,可写。

此时我们再次调用:

1
printf('hi');

屏幕上不会再出现任何字符,输出就直接写入到了文件 tmp.txt 中。

所以它其实等价于:

1
2
char tmp = "hi";
write(filefd, tmp, strlen(tmp));

这也是伪终端实现的主要原理之一。

Flutter 实现

我们使用 dart:ffi 来完成这个操作。

ffi 相关本文不做具体解释。

流程就是 dart -> dart:ffi -> c -> dup2

所以我们只需要简单的几行代码。

1
2
3
int filefd = open("./tmp.txt", O_RDWR);
dup2(filefd, 1);
dup2(filefd, 2);

如此一来,开发者调用 print 函数,亦或者 dart 内部的一些打印,都等价于:

1
write(filefd, '***', strlen("***"));

所有的内容都会被定向到我们指定的文件中

测试截图:

此时我的 vs code 调试终端拿不到任何输出了,但我能从我设置到的文件中读取输出。

平台差异

在我反复测试 Linux 桌面版Android 平台的时候,发现在 LinuxFlutter 桌面 app 上,dartprint 其实就是写入字符到文件描述符 1,2,但在 Android 设备上,print 写入到的文件描述符是 3

也就是

1
dup2(filefd, 3);

over。有问题留言。有错误指出。

最后欢迎各位加入 Flutter Candies,一起制造可爱好用的 🍬 。 (QQ 群:181398081)

作者

梦魇兽

发布于

2020-07-10

更新于

2023-03-11

许可协议

评论