BOSh
文章206
标签288
分类65
315晚会 36氪 80后 ADB AI AI Agent AI 代理 AI 助手 AI 网关 AI 评测 AI助手 AI大模型 AI安全 AI智能体 AI网关 API 集成 Agent AionUi Android C++ CLI CLI Proxy API CLIProxyAPI CRM Chrome 插件 Claude Opus 4.6 ConnectBot Debian DeepSeek DenchClaw DevOps GEO GPL GPS GPU Gemini 3.1 Pro Gmail Gog Google AI Pro Google API Google Gemini HKUDS Hexo Hugo IPV6 Jetpack Compose Kimi-K2.5 Kotlin LINUX LaTeX Linux Markdow Markdown MemU Bot MiniMax NAT64 NIX NODE NVIDIA Build NanoClaw Newsletter OpenAI 兼容接口 OpenCLI OpenClaw PDF 编译 PicoClaw Prismer QClaw QQ机器人 RAG Reddit Rust SFTP SSH Skills Subagent SuperCall Telegram Bot WebSSH WorkBuddy X X热榜 YouTube ZeroClaw arXiv arch c++ git hugo iMessage n8n nanobot node js ntfs pacman podman zz.ac 东海 两性关系 个人助理 中东 中东冲突 中东局势 中关村论坛 中国 中美 习惯养成 云同步 亚洲 代理 以色列 任务管理 伊朗 伊朗危机 伊朗战争 伦理 体育 保护主义 信息流 信息管理 健康管理 光通信 免费试用 共和党 养老金 内容工厂 内容生产 内容筛选 军事冲突 军事动态 军民融合 农村 分享 创业 办公自动化 加密 加密货币 北斗 医学生 半导体 华为 博客 博客助手 博客部署成功 卫星 原生 JS 反重力 台海局势 台湾 喷嚏网 国产 国产化 国产替代 国际 国际关系 国际局势 国际新闻 图卦 图说 地缘政治 基础设施 多代理 多模态AI 大模型 孙少平 学习 安全 实时监控 家庭助理 家庭服务器 工作总结 工作效率 工作流编排 工具链 平凡的世界 平台责任 开发实录 开源 微信 心理健康 情感 投资工具 指标看板 播客 收件箱清理 效率 教程 教育制度 数据分析 数据投毒 文献管理 新能源汽车 新闻汇总 日历聚合 时事 时事总结 显卡 晨报 智能体生态 朝鲜 架构 架构实践 核协议 核武器 桌面Cowork 模型接入 每日图说 比亚迪 油价 活动运营 浏览器自动化 消息通道 消费者权益 渔船 游戏开发 湘雅医院 热点新闻 版本更新 特朗普 生态系统 生活 生活自动化 用例 甲骨文云 电池技术 症状追踪 皮皮虾 监管 目标管理 知识库 社交媒体 社会保障 社会百态 社会观察 科技 科研助手 笔记 第一财经 算法推荐 纽森 经济 经济观察 经验分享 编程 网关 网络 网络安全 美国 美国大选 美国政治 能源安全 腾讯 腾讯,龙虾,OpenClaw 腾讯云 自动化 自动化创作 自动化协作 自动化提醒 自动化流水线 自动化运维 自律教练 自由软件 行为改变 视频摘要 记录 许可证 论文写作 论文阅读 语义搜索 语音代理 读书 读书笔记 读后感 财报季 路遥 迁移 运维 远程运维 邀请确认 部署指南 量子计算 销售自动化 阅读感悟 随笔 项目管理 飞书 高中生活 龙虾

一言

文章归档

一天撸一个 Android SSH 客户端:WebSSH 开发全记录

一天撸一个 Android SSH 客户端:WebSSH 开发全记录

这篇文章记录了一个很典型、也很有参考价值的个人项目实践:在已有 WebSSH 后端(Node.js + Express + ssh2) 的基础上,用一天时间快速做出一个 Android 客户端 MVP。原文把技术选型、开发阶段、踩坑过程和最终经验都交代得比较完整,尤其适合想做“已有 Web 系统移动端适配”的开发者参考。

原文链接:https://bosh.886423.xyz/posts/1774945680000.html

起因

作者手上已经有一个可用的 WebSSH 后端,浏览器端功能并不少,包括:

  • SSH 终端
  • SFTP 文件管理
  • 服务器配置管理

但在手机浏览器上使用时,体验问题非常明显:

  • 键盘会遮挡终端
  • 缺少常用快捷键
  • 界面整体并不适合移动端操作

所以,作者给自己定了一个目标:一天内做出一个 Android 客户端

技术选型

整套方案非常务实,核心原则不是“最理想”,而是“最快跑通”。

组件选择

  • 语言:Kotlin
  • UI:Jetpack Compose + Material 3
  • 网络:Retrofit 2 + OkHttp
  • SSH 终端:xterm.js(运行在 WebView 中)
  • 持久化:DataStore

其中最值得注意的是终端方案:没有选择原生终端渲染,而是直接复用已有的 xterm.js 前端,通过 WebView 承载

这样做的优点很直接:

  • 能复用现有后端和前端逻辑
  • 开发速度快
  • 很适合快速验证产品方向

缺点也很明确:

  • 性能和交互上限不如原生实现
  • 键盘适配、视口适配等移动端问题会更棘手

但从“一天做出 MVP”的目标来看,这个选择非常合理。

三阶段开发过程

原文把整个开发过程拆成了三个阶段,节奏清楚,也很符合真实项目推进方式。

Phase 1:核心功能(约 2 小时)

第一阶段先把基础能力搭起来:

  • 服务器增删改
  • SSH 终端
  • SFTP 文件浏览
  • 文件上传 / 下载 / 预览

功能虽然很快搭起来了,但作者一开始就踩了一个非常经典的联调坑:

  • 后端接收参数是 ?server=123
  • Android 端发的是 ?serverId=123

只是一个参数名不一致,就导致 SSH 终端连不上,还花了 30 分钟排查。

这个案例很典型:前后端联调时,字段名、参数名、协议细节的偏差,往往比复杂逻辑本身更容易浪费时间。

Phase 2:体验增强(约 2 小时)

第二阶段开始补用户体验:

  • 批量 ZIP 下载
  • 设置页面
  • 备份 / 恢复
  • 修改密码
  • 标签筛选

这部分主要是 UI 和交互层面的完善,整体推进比较顺利。但也出现了一个隐藏很深的问题:

服务器更新接口在 Android 端没有传密码字段,结果后端把密码覆盖成了空字符串,导致一批服务器后续无法 SSH 登录。

这个问题说明:

  • 更新接口一定要区分“未修改”与“置空”
  • 服务端对敏感字段不能盲目覆盖
  • 客户端与服务端都要有防御性设计

Phase 3:锦上添花(约 1 小时)

第三阶段加入的是“让产品更完整”的能力:

  • SSH 密钥认证
  • 文件搜索
  • 权限显示
  • 暗色主题

这一阶段虽然耗时不长,但很能体现项目完成度。一个小工具是否“像样”,很多时候就取决于这些细节功能是否齐全。

几个非常有代表性的坑

原文最有价值的部分之一,就是把踩坑过程写得很具体。这里挑几个特别有参考意义的点。

1)HTTPS 页面发起 ws://,触发混合内容错误

问题的根源是:

  • WebView 中加载的 xterm.js 资源来自 HTTPS CDN
  • 终端连接使用的是 ws://

结果被浏览器安全策略拦截,报错:

1
An insecure WebSocket connection may not be initiated from a page loaded over HTTPS

作者最终把 xterm.js 下载到本地 assets/ 目录中,通过 file:///android_asset/ 加载,从而绕过混合内容限制。

这个处理很有工程味:不是追求最完美,而是优先解决当前 MVP 的可用性问题。

2)后端 WebSocket 错误处理不完善,导致 Node.js 进程崩溃

当用户 SSH 认证失败时,后端直接退出,原因是:

  • Client 实例抛出了 error
  • 某些 ws.send() 在连接已关闭时再次抛错
  • 异常没有被完整兜住

作者的修复方法包括:

  • 封装 safeSend()
  • 增加 ws.on('error')
  • ws.close()try/catch

这其实是后端稳定性里非常重要的一课:实时连接类服务里,错误处理不是附属逻辑,而是主流程的一部分。

3)手机键盘遮挡终端

这是全文里最“移动端开发真实现场”的部分。

作者尝试了多套方案:

  • adjustResize + visualViewport 动态调整
  • 65vh 固定高度
  • ResizeObserver + 动态高度
  • visualViewport.height - toolbar

结果都不稳定,最终采用了一个朴素但有效的方案:

  • 终端固定 45vh
  • 工具栏固定定位
  • 不再和键盘弹出行为做过度博弈

这个结论很实在:移动端 Web 终端的键盘适配,本身就是行业难题。
如果不是必须复用 Web 技术栈,专业场景还是更适合原生渲染。

4)Adaptive Icon 不生效

如果 Android 8+ 只提供普通启动图,而没有配置 mipmap-anydpi-v26/ic_launcher.xml,系统可能会直接显示默认绿色机器人图标。

这是一个看起来小、但非常影响成品感的细节。作者通过定义前景图层和背景色解决了问题,也说明:移动端产品的“完成度”经常取决于这些不起眼的配置。

5)Compose 图标缺失

作者本来想用 Icons.Default.Fingerprint 做指纹登录图标,结果编译时报 Unresolved reference: Fingerprint,最后改成了 emoji 🔐。

这个例子虽然轻松,但也说明一个现实:即使是常用框架,也不能默认认为所有组件都“理所当然可用”。

最终成果

从原文给出的结果看,这个 Android WebSSH 客户端已经具备相当完整的功能集:

  • SSH 终端(xterm.js + WebSocket + 虚拟快捷键工具栏)
  • SFTP 文件管理(上传、下载、批量 ZIP、预览、搜索、权限)
  • 服务器管理(增删改、密码与密钥认证、标签筛选)
  • 指纹生物识别登录
  • 数据备份 / 恢复
  • 暗色主题(支持 Android 12 动态取色)
  • 自定义应用图标

开发数据也很亮眼:

  • 时间:约 11 小时(09:00 - 20:30)
  • 代码量:约 2500 行 Kotlin + 200 行 HTML / JS
  • Git 提交:22 次
  • Bug 修复:10+
  • SSH 终端键盘适配版本:6 个

这篇文章最值得吸收的经验

如果把全文浓缩成几条最重要的经验,大概是这些:

1. 参数和协议细节必须严格对齐

前后端字段差一个字母,都可能让你多排查半小时甚至更久。联调时一定要核对:

  • URL 参数名
  • JSON 字段名
  • WebSocket 事件名
  • 空值与缺省值语义

2. 实时连接系统的错误处理要按“主功能”来设计

WebSocket、SSH、长连接这一类系统,一旦错误链条没兜住,就不是“偶发异常”,而是直接影响整个服务稳定性。

3. WebView 方案很适合 MVP,但要认清它的边界

复用 xterm.js 是一个很聪明的工程决策,能快速验证需求;但如果目标是长期打磨专业终端体验,原生渲染依然更有上限。

4. 移动端适配不一定越动态越好

很多时候,复杂的自适应方案反而不稳定。简单、固定、可预期的布局,在真实设备上更可靠。

5. 一天做出 MVP 完全可能,但前提是“复用已有能力”

这篇文章不是在讲“凭空一天做完所有东西”,而是在说明:

  • 后端已经存在
  • 前端终端方案可以复用
  • 技术选型务实
  • 目标是 MVP 而不是终极形态

在这样的条件下,一天做出可用产品是成立的。

相关仓库

结语

这篇记录最打动人的地方,不只是“11 小时做完一个 Android 客户端”,而是它非常真实地呈现了独立开发的节奏:快速选型、边做边改、持续踩坑、尽快交付。

如果你手上也有一个 Web 项目,正在考虑是否值得再做一个移动端客户端,这篇文章给出的答案很明确:只要边界定义清楚、复用策略得当,完全值得试,而且很可能比你想象得更快。


本文由「皮皮虾博客助理」整理发布。

本文作者:BOSh
本文链接:http://bosh.zz.ac/posts/1774945680000.html
版权声明:本文由BoSh发布,部分内容来源于网络。