不用电脑!手机直刷树莓派:安卓烧录器开发实录(自带 SSH/WiFi 预配置注入)
树莓派 Zero W 只有 Micro USB 数据口,电脑不在身边时想烧个系统、配好 SSH 和 WiFi,有没有可能只靠一部手机完成?这篇文章记录了我把一个开源烧录器改造成"下载 → 解压 → 注入配置 → 直写 SD 卡"全流程安卓 App 的过程,以及过程中踩过的那些坑。
一、为什么做这个 App
树莓派 Zero W 的典型痛点:没有 HDMI 接口方便接屏幕,没有标准 USB 口,只能靠 SSH/WiFi 远程连接。传统流程是:
1. 用电脑下载官方镜像( .img.xz ,2.5GB 左右)
2. 解压成 .img
3. 用 rpi-imager / balenaEtcher 写入 SD 卡
4. 手工创建 ssh 空文件、 user-data 、 network-config 配置首启动参数
5. 插卡开机
这套流程每一步都离不开电脑。而现实中很多场景(出差、学生宿舍、临时设备)只有一部手机。于是有了这个项目:把"下载 + 解压 + 配置注入 + 烧录"四步全部搬进安卓 App,插入 OTG 读卡器即可完成一切。
二、核心功能一览
表格
功能 说明
官方镜像源 实时拉取树莓派官方 os_list_imagingutility_v4.json ,内置 3 条 32 位 Trixie 兜底条目(Zero W 可用)
多线程断点下载 16 线程分块下载、断点续传、失败自动降级(Range → HEAD → 流式)
即下即解压 .xz 流式解压成 .img ,按官方 extract_size 精确校验完整性
SSH 配置注入 账号密码任意填写(不写死),生成 cloud-init user-data + meta-data + ssh 触发文件
WiFi / 有线配置 WiFi SSID/密码注入 network-config ;有线 USB 网卡走默认 DHCP
烧录前回读验证 注入后立即回读 boot 分区校验,失败绝不写盘
免 root USB 直写 基于 libaums + libusb 通信栈,U 盘/SD 卡直写,无需 root
写后全量校验 官方 WorkerService 写完后逐块比对,检测坏盘/掉线
断点续烧 写入中断后从上次偏移继续,不重头再来
兼容鸿蒙 荣耀 X10 / HarmonyOS 3.0 实测可装可跑
三、系统架构
整个工程是**"反向合并"**:官方 EtchDroid 核心一行不改,外面包一层树莓派专属的 UI 与流程编排。
技术栈:Kotlin 1.9.22 · Compose + Material3 · AGP 8.2.2 · minSdk 26 / targetSdk 29 · JDK 17。
targetSdk 29 不是偷懒:荣耀 X10 的鸿蒙 3.0 对应 Android 10(API 29),与系统版本一致最兼容,且该 App 是侧载分发,不受 Google Play 的 targetSdk 33 要求约束。
四、关键流程:下载 → 解压 → 注入 → 烧录
整个流水线是一个状态机,核心顺序严格对齐树莓派官方 rpi-imager:
为什么"先注入再烧录"?
官方 rpi-imager 是边解压边写设备,配置注入发生在写入过程中(临时挂载 boot 分区)。但安卓端没有 root 无法挂载,所以换了个思路:先把 .xz 解压成完整 .img,在文件层面用 FAT32 直写完成注入,验证通过后再交给官方核心整体写入。这样注入的每一字节都经过回读校验,坏配置永远不会落到 SD 卡上。
注入链是纯 JVM 的
Fat32Tool / Sha256Crypt / BootConfigGenerator / ConfigInjector 四个文件零 Android 依赖(只 import java.* / javax.crypto ),这意味着它们可以在 PC 上独立编译跑真实镜像测试——我确实这么干过:
注入后回读 user-data ,密码字段是 $5$... 形式的 SHA-256 crypt 哈希(非明文),用 openssl passwd -5 独立验证一致:
FAT32 直写的关键实现
boot 分区是 FAT32,直写需要手工解析 BPB(BIOS Parameter Block):
写文件 = 遍历目录项找目标 → 若存在则覆盖(同簇写回,不动目录项)→ 不存在则分配新簇 + 更新 FAT 表(注意 FAT32 有两份 FAT 表要同步写)。删文件 = 把目录项首字节置 0xE5 并释放簇链。
五、免 root USB 直写原理
安卓不能像 PC 那样直接 dd ,靠的是 USB Mass Storage 协议(BOT 传输)。项目采用官方 EtchDroid 同款组合:
- libaums core 0.10.0:实现 SCSI 块设备协议,把 U 盘/SD 卡读卡器识别为块设备,提供 BlockDeviceDriver (read/write 按块操作)
- libusbcommunication 0.3.0:把传输层从系统 bulkTransfer 换成 libusb 原生栈
这里有个重要经验:系统 UsbDeviceConnection.bulkTransfer() 有 5 秒写死超时,树莓派镜像 2.5GB 写入过程中 USB 稍微繁忙就会超时掉线——这正是"拼接版老掉线、原版不掉线"的根因。切到 libusb 通信栈后,超时可控、错误恢复机制完善,同一根线再没掉过。
六、多线程下载引擎的竞态教训
16 线程分块下载带断点续传,过程中踩了三个典型的并发坑,分享给大家:
1. 线程数变化导致断点错位:上次 16 线程下了一半,这次只开 4 线程续传,旧 .partN 分块会和新分块交错,文件损坏。修复: start() 时校验已下载分块数 ≠ 当前分块数 → 清空进度重新下。
2. 取消/重下同名文件的误删:取消任务的后台清理线程,如果按文件名前缀匹配删除分块,可能把"用户立刻重下"的新任务分块删掉。修复:删除只针对本次会话登记的分块列表(加锁保护),不再前缀通配。
3. 主线程网络请求闪退:暂停→继续的恢复逻辑里直接调了网络探测,触发 NetworkOnMainThreadException 。修复:所有引擎启动/恢复都放进后台线程。
七、安装环境与兼容性(鸿蒙 3.0)
这个 App 的真实运行环境是荣耀 X10(TEL-AN10)+ HarmonyOS 3.0.0 + 麒麟 820,属于 arm64-v8a。为了在鸿蒙上顺利侧载安装,两个点很关键:
1. 签名必须 v1+v2+v3 共存
鸿蒙 3.0 安装 APK 时报过"安装包无效或不完整"(错误码 -2)。根因是 AGP 8 在 minSdk ≥ 24 时默认关闭 v1(JAR)签名,而部分系统安装器只认 v1 证书。修复方式:显式开启全部签名方案:
2. native 库不压缩
libaums 的 .so 要保证 extractNativeLibs = true (不压缩打包),否则部分 ROM 上运行期加载失败。
3. 目标 SDK 与系统版本对齐
鸿蒙 3.0 = Android 10 = API 29, targetSdk 29 与系统一致,避免高版本 targetSdk 触发行为变更(如后台服务限制)导致烧录中途被杀。
八、踩坑清单(浓缩版)
表格
现象 根因 解法
鸿蒙报"安装包无效或不完整" APK 缺 v1 签名 开启 v1+v2+v3
暂停后点"继续"闪退 主线程发起网络探测 引擎启动/恢复移后台线程
烧录中途 USB 掉线 系统 bulkTransfer 5s 超时 换 libusb 通信栈
下载进度百分比不动 进度回调传了 total=0 状态通知携带真实 total
换镜像烧错卡 选新镜像后旧设备残留 选镜像时清空 selectedDevice
取消后重下文件损坏 清理线程误删新任务分块 只删本次会话登记的分块
镜像解压出残缺文件 下载截断 按官方 extract_size 精确校验
九、总结
这个项目最核心的收获有三点:
1. "先注入再烧录"的文件级方案,绕开了安卓无 root 无法挂载 FAT 分区的限制,且注入可回读验证,比边写边配更安全;
2. 官方核心零改动 + 外层流程编排的合并策略,让可靠性继承了久经考验的开源实现,自己只需专注注入链和 UI;
3. 鸿蒙侧载兼容不是玄学——签名方案、native 库打包方式、targetSdk 对齐,三件事做对就能装。
如果你也想折腾树莓派 Zero W 又不想被电脑绑住,这个思路可以完全复刻
:官方 EtchDroid(烧录核心)+ 官方 rpi-imager(配置生成逻辑移植)+"先解压注入再写盘"的流程编排,一部手机就能完成从下载到开机的全部工作。
本文所有代码片段均来自真实工程,注入链已用真实镜像完成端到端验证。
通过百度网盘分享的文件:927a5307…
链接:https://pan.baidu.com/s/1-4yPrcrkEYygKoNXO-0D7g?pwd=pbd0
提取码pbd0
复制这段内容打开「百度网盘APP 即可获取」
更多推荐




所有评论(0)