Flutter 终端模拟器 - 写一个 Termux,开源篇

Flutter 终端模拟器 - 写一个 Termux,开源篇

废话

最近社区输出越来越少了,实习回到家,一般8.30多吧,收拾收拾,电脑一开,一般就会写过12点,有时候累了是完全无心情写。自己写东西时间已经极少了,还得负责学校一个项目的后台,一个web项目,所谓的“能者多劳”,还有学校里面杂七杂八的学分上的事要处理,感觉这样时间长了,估计得直接转行。

这个终端的灵感主要来自 termux 和 termius 还有很早的 Android Terminal,起初想做一个和 termius 相似的产品,估计也是心有余而力不足了。(有生之年一定弄个!)

该终端涉及到的各部分细节以及相关技术难点,个人还是决定比较多,我就不挨个将其中的东西拿来解析了,这篇主要是介绍这个使用 Flutter 框架开发的终端模拟器以及开源相关的内容。

还有很多得之后才能写上,大家感兴趣的先随便玩玩。

系列文章

运行截图

主要难点

  • 终端序列的解析:这部分要做得很好实际是极难的,目前仅仅参考 xterm.js 进行了相关序列的解析,而从 xterm 序列 来看,Linux 终端涉及到的序列真的太太太多了,全部实现真就得有生之年系列了,而且解析的速度、正确率,都直接跟笔者的技术相关。感觉还是对很多技术的理解不够,写起来很吃力。但如果只实现 xterm.js 实现到的序列的话,经过后续的迭代还是没太大问题。

  • 上层组件的渲染:整个终端组件是完全通过 canvas 根据缓存流计算然后绘制的,内部逻辑也相对复杂,需要确保在一帧的时间内完成整个终端可视窗口的绘制。

  • ffi 的适配:我期望的是各个平台都不需要单独编译 C 语言作为 so library,这样就不会存在很多 c 语言代码,每次都要编译到各个平台。从 ffigen 的出现以来,我尝试将所有的 c 语言代码完全由 dart 改写,但最后在 android 平台上表现不佳,在 dart_pty 的 readme 末尾有提到,所以目前还是采用引入 so 库的方式。

  • android 端源的搭建:这部分也比较麻烦,可躺了不少坑,主要是通过 termux-package 来交叉编译,有相关文章在编写中了。

体验地址

大学在学的方向是前端,但是大部分的时间在学 Flutter,所以前端只学了一些基础,用 web 基础开发写了这个官网,顺便交了作业,在移动端的布局适配问题很大。

PC 平台的包可能会存在打不开的情况,我之前在一台 mac 编译后另一台打开直接显示损坏,搜到的一些方法也没用上,然后在另一台本地编译就行🤣

链接 -> Termare

核心仓库

  • termare_view:终端的上层组件,是一个 Widget,使用 canvas 进行绘制。
  • dart_pty:创建一个伪终端并执行一个子进程,可对进程进行交互。

使用方法

集成了 apt 作为包管理器,就像使用 ubuntu 一样。

软件源相关

同步软件源

1
apt udpate

更新软件包

1
apt upgrade

安装软件包

1
apt install $PKG

不能使用 pkg install,pkg 其实就是 termux 封装的一个 shell 壳,内部去执行了 update ,但是 pkg 这个脚本文件内涉及到的源是 termux 的,不能应用于本软件。

安装 ZSH

跟PC一样,但是在修改字体上会有一点问题。zsh 很多库其实已经兼容了 termux,字体的重载是执行的 termux-reload-settings,这就是一个简单的 shell,调用 am 命令发送广播到 termux,termux 再进行更改,如果要适配到 termare,咱改改 shell 内广播发送到的包名,也监听一个广播,然后主动调用 Flutter 端代码吧(后续,不难的)。

也可以自己粘贴命令,但是设置内部也是自动键入命令来着。

快捷安装

安装 ZSH 主题

以 powerlevel10k 为例

快捷安装 powerlevel10k

安装代码补全

终端设置

这个页面是写得最赶的,后面再维护

遗留问题

性能相关

这部分跟上层组件 termare_view 和 dart_pty 两个仓库都有关系。

反复对比过 termare 相对 termux,在大量输出的情况,例如find /cmatrix -r,termare 性能较低,并且find /命令更耗时,已经尝试过定位耗时状况,与获取终端的轮询和页面构建的时间都有关系,主要在前者。例如 find / 命令,这个命令执行后会有大量的输出写入到终端文件描述符,在这个命令执行完成后,dart 端还在拼命去将内容读出来,解析序列,最后渲染,所以就让使用者感觉是命令本身执行耗时。

页面渲染部分目前尝试用Stopwatch ,在 canvas 内觉得耗时的代码后都打印了一个时间,从一次 build 的开始到结束基本是小于 11 ms的(根据 90 fps刷新率的设备),已经做了很多优化,所以在执行有大量输出的命令时,页面的构建其实并不是主要影响命令执行时间的因素,有点难解决,希望我能再厉害点吧!

序列相关

仅跟 termare_view 有关

按照 xterm.js 的序列文档 链接 适配了其中 90% 的序列,但个别序列实现比较复杂,例如 CSI ps;ps r,目前能正常解析,但在序列的行为表现上还有问题,还有个别序列没获取到具体的行为,例如ESC \

一些命令如 vim,htop,nano,在运行的时候使用到了较多的序列,主要表现在 vim 编写文本时,内容超过终端高度时涉及到的序列。而 htop 输出的终端序列实在太多,完全不好定位是哪个序列的问题导致表现上的差异。

Android 端依赖源相关

目前从 termux 组织 fork 了一份 termux-package 仓库到了 termare,改了关键的配置文件,来单独编译 termare 需要的源。

在 termux-package 内有接近900个包,由于执行 build-all.sh 的时候,有几个依赖的编译报错实在太难解决(个人技术原因),就把编译失败的都跳过了,但是 termux 内涉及到的99%都编译下来了,如果你还有一些需要那极个别的包,可以直接私信我,我如果能够成功编译的话一定会编译到源上。

输入问题

在 PC 上不能输入中文,估计得细读 TextField 源码才成,还有按键等支持也比较少🤯。
在安卓端没有特殊按键的输入😩。

平台支持情况

macOS

Linux

Windwos

windows 的支持不太友好,目前用的 pty 这个 package 来实现的 windows 本地终端的调用,这种方式不兼容旧版的 windows。

后续计划

这将会是我长期维护的开源项目,包括整个组织的其它项目。

  • 完善 termare_view 的终端序列。

目前序列适配的优先级是最高的。

  • 对 PC 端的按键适配。
  • 将底层 c 语言部分除 setNonblock 的所有代码用 dart 重写。(其实已经实现了,还没时间整合)
  • 性能优化。
  • 尝试为 android 平台编译更多的源。

enjoy coding!

作者

梦魇兽

发布于

2021-04-22

更新于

2023-03-11

许可协议

评论