返回开发博客 工程更新

2026 年 7 月开发更新:更稳的 Desk,更聪明的键盘在路上

这个月三件事:一个今天就能下载的 SharkTTY Desk 修复构建;iPhone / iPad 应用开发进展的 如实汇报(进行中——尚未发布);以及一个实验性终端传输的状态报告。这里是工程视角的版本; 简明的用户向说明在新功能页。

SharkTTY Desk 0.8.0 — 7 月 10 日构建(现已可用)

这是上周 0.8.0 发布的后续构建,版本号仍为 0.8.0。 在这里下载

「停止共享」的 bug

这个坑是我们自己日常使用时踩到的。屏幕被查看时,macOS 会在菜单栏放一个自己的指示器, 带着自己的「停止共享」按钮。从那里结束会话——而不是在 SharkTTY 里——可能让 Desk 卡死:二维码消失、服务显示启动中、每次重连都失败,直到退出并重启应用。把远程控制 开关关掉再打开也没用。这是最糟的一类故障:不是能上报的崩溃,而是一个安静地不再是服务的服务。

实际发生的是:会话结束后,agent 会重建网络监听以迎接下一次连接,重建需要拿回同一个本地端口。 但旧监听的端口释放只是内部清理的副作用,清理时机取决于会话是怎么结束的——在这条特定路径上, 清理可能远远落后于重建,甚至永远不会完成。重建尝试绑定端口,发现端口仍被占用,在一个事后看来 比清理时间还短的重试窗口内放弃,然后让 agent 落在没有任何监听的状态。从外面看:永远「启动中」。

修复把这次交接从巧合变成契约:关停现在会显式释放端口,并在确认释放之后才允许重建继续; 重绑本身也更有耐心,每次尝试都会写日志,将来的报告可以直接从 Console 定位。我们带走的教训: teardown 应当得到与 startup 同等的确定性。「端口最终会自己释放」不是契约。

连接密钥显示

三个针对 Mac 端连接密钥显示的小修复,全部只涉及显示——密钥的生成与保护方式没有任何变化。 隐藏的密钥现在显示固定长度的占位符,而不是每字符一个点,遮蔽状态不再暗示密钥的长度。 超长的自定义密钥会缩放到一行放下,不再溢出卡片(元凶是不随字号缩小的字符间距)。 Desk 还会跨启动记住你选择了隐藏——隐藏不该是每天早上都要重复的杂务。查看密钥仍需 Touch ID 或密码,和以前一样。

兼容性不变:此构建适配 iPhone / iPad 上的 SharkTTY 1.6 或更新版本。 如果你的应用版本更旧,SharkTTY Desk 0.5.0 构建仍然可用。

SharkTTY iPhone / iPad 版 — 开发中

先把话说清楚:本节内容都还没有发布。这是我们开发构建里已经工作、面向下一次 App Store 更新的内容——我们宁可告诉你事情进展到哪,也不愿闷声等到上线。

浮动键盘,第二幕

浮动键盘迎来第二幕。布局从一种变成六种——US、UK ISO、日语 JIS、法语 AZERTY、德语 QWERTZ、 西班牙语 ISO——而且是真布局,不是换了贴纸的键帽:欧洲布局带完整的 AltGr 第三层 (打不出 | { } [ ] \ 的终端根本不算终端),ISO 键盘有左 Shift 旁的附加键,fn→F1–F12 按物理位置逐布局映射。 我们写了一个遍历所有布局、证明每个终端关键字符都可达的测试——它在开发中真的逮到了两个漏键, 测试就该在这种事上让人脸红。浮动键盘、语音板、系统键盘之间的切换,现在住进了键盘自己的 设置弹窗里——它本来就该在那儿。

键区上方新增候选词条:补全来自终端最近的输出、你本次会话敲过的词,以及一小份常用 shell 命令表。全部在设备端就地计算,基于你屏幕上本来就有的文字——不会为了给出建议把任何内容 发到任何地方。键盘的麦克风按钮支持按住即说,实时预览就显示在同一条词条里,松手后只有 点击结果才会插入。最后这一点是刻意的:终端对听错的词毫不留情,语音永远不直接进 shell。

语音输入板

语音输入板补上了浮动键盘已有的那套窗口礼仪:可移动、可缩放、透明度可调到 shell 能透出来。一套控制,两块板子,没有意外。

断线后仍在的远程桌面标签

一个早该做的一致性修复:断开远程桌面会话会关掉它的标签,而断开 SSH 会话则保留标签并给出 重连按钮。同一个应用,两套哲学。Desk 标签现在和 SSH 标签行为一致——断开保留标签,重连一次 点击,关闭标签只会发生在标签本身上。

同步健壮性

这个月最不显眼、也许最重要的工作。你保存的主机、脚本、设置会在设备间同步,而任何一次 版本铺开期间,你的设备都会混跑不同的应用版本——这不是边缘情况,而是每次发版前后几周的 世界常态。我们重做了同步格式的处理:新版本写的数据穿过旧版本时原封不动——旧应用保留它 不认识的部分并原样写回,而不是被噎住,或悄悄压扁成它认识的形状。我们现在恪守的规则很简单: 旧应用永远不能毁掉新应用写的东西。你永远不会看到这个功能——这正是它的意义。

实验性:Eternal Terminal 传输

SharkTTY 说 SSH 和 Mosh。Mosh 是让终端穿过火车隧道还活着的那个——但它跑在 UDP 上, 而有些网络就是不放行 UDP。Eternal Terminal 用纯 TCP 解决同一个问题,而且很多人的机器上本来就跑着 etserver。我们的立场很简单: 你已经在运行一个能解决这个问题的服务器,就不该被迫用我们的基础设施才能受益—— 应用应该直接说你服务器的语言。

所以我们用 Rust 从零实现了开放 ET 协议的客户端,它现在能对着真实的 etserver 走完全程: 连接、输入、中途掐断链路、重连,不丢一个字节。它暂时躲在实验开关后面积累真实里程; 攒够之后,会作为 SSH 和 Mosh 之外按主机选择的第三种传输出现。如果你今天就在跑 etserver、想在开关打开时 帮忙踩踩,盯着这个博客就好。

对以上任何内容有问题或 bug 报告?反馈板是最快找到我们的方式。