Flutter 终端模拟器 - 写一个 Termux,开源篇
废话
最近社区输出越来越少了,实习回到家,一般8.30多吧,收拾收拾,电脑一开,一般就会写过12点,有时候累了是完全无心情写。自己写东西时间已经极少了,还得负责学校一个项目的后台,一个web项目,所谓的“能者多劳”,还有学校里面杂七杂八的学分上的事要处理,感觉这样时间长了,估计得直接转行。
这个终端的灵感主要来自 termux 和 termius 还有很早的 Android Terminal,起初想做一个和 termius 相似的产品,估计也是心有余而力不足了。(有生之年一定弄个!)
该终端涉及到的各部分细节以及相关技术难点,个人还是决定比较多,我就不挨个将其中的东西拿来解析了,这篇主要是介绍这个使用 Flutter 框架开发的终端模拟器以及开源相关的内容。
还有很多得之后才能写上,大家感兴趣的先随便玩玩。
系列文章
- Flutter 终端模拟器探索篇(一)| 简易终端模拟器
- Flutter 终端模拟器探索篇(二)| 完整终端模拟器
- Flutter 终端模拟器探索篇(三)| 原理解析与集成
- 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 一样。
软件源相关
同步软件源
更新软件包
安装软件包
不能使用
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!
Flutter 终端模拟器 - 写一个 Termux,开源篇
http://blog.nightmare.press/2021/04/22/Flutter-终端模拟器-写一个-Termux,开源篇/