f2-hap:把短视频无水印下载器搬上 HarmonyOS NEXT 的纯 ArkTS 原生实践
项目背景:从 macOS 到鸿蒙 NEXT
f2-hap 是一个抖音 / X(Twitter) / 微博无水印视频与图集下载器的 HarmonyOS NEXT 原生应用,由 macOS 版 F2 Downloader 移植而来,采用 Apache-2.0 协议开源。
它最有意思的地方在于移植方式:没有 Python 运行时,没有第三方解析 API。桌面版是「Swift 进程 + Python 常驻服务 + 文件队列」三段式架构,跨进程通信还曾导致「任务一直停在等待中」的诡异 Bug(Python 子进程退出后 daemon 线程被杀)。而 HAP 版把全部签名算法与解析逻辑都用 ArkTS 在设备本机重写了一遍,联网只跟平台自家接口打交道——没有中间商赚差价,也就没有中间商挂掉。
能做什么
| 平台 | 视频 | 图集 | 登录要求 | 说明 |
|---|---|---|---|---|
| 抖音 Douyin | ✅ | ✅ | 需 Cookie | 本机 a_bogus 签名(SM3 + 自定义 RC4),走 aweme/v1/web/aweme/detail |
| X (Twitter) | ✅ | ✅ | 免登录 | 主路线 cdn.syndication.twimg.com;兜底 guest_token + GraphQL |
| 微博 Weibo | ✅ | ✅ | 需 Cookie | weibo.com/ajax/statuses/show,自动下潜转发原文 |
| TikTok | ⚠️ | ⚠️ | — | 需 XBogus 签名 + 设备注册,当前版本未移植,成功率极低 |
除了解析下载,工程还把「用起来顺手」这件事做得很细:
- 系统分享接入:在抖音/微博里点「分享 → F2 HAP」直接建任务,不用手动复制链接
- 剪贴板自动识别:打开应用即读剪贴板,识别到链接自动填入(动态申请
READ_PASTEBOARD权限) - 短链展开:
v.douyin.com/t.cn/t.co自动跟随跳转,展开后重新判定平台 - 多档码率择优:视频取
video/mp4中 bitrate 最高档,跳过 m3u8;图片直接取原图 - 存入系统相册:走
showAssetsCreationDialog弹窗授权,不申请受限权限,无需 ACL 审批 - 断点式落盘:流式写
.part临时文件,完成后 rename,避免半成品混入 - 并发闸门:1~5 并发可调,任务队列常驻同一 ArkTS 运行时
- 实时日志:分级过滤、一键复制,解析失败能直接看到是哪一步断的
架构:单运行时,没有进程边界
整个应用跑在同一个 ArkTS 运行时里,数据流非常清晰:
1 | UI (ArkUI) ──订阅──▶ TaskManager(内存队列 + 并发闸门) |
工程结构也按这条链路组织:
1 | f2-hap/ |
对独立开发者来说,这个架构有个很实际的好处:没有进程边界,任务不会凭空停住。代价则是——签名算法必须自己在 ArkTS 里重写一遍。
技术亮点:在 ArkTS 里重写抖音签名
这可能是整个项目含金量最高的部分。抖音 Web 接口的 a_bogus 参数依赖 SM3 国密哈希 + 自定义 RC4 的组合签名,通常这类算法只在 Python/JavaScript 社区流传(配合 execjs 或者 Node 子进程调用)。f2-hap 直接用 ArkTS 原生实现了 SM3.ets 和 ABogus.ets,签名完全在设备本机完成。
X(Twitter) 的解析则展示了「免登录双路」的设计思路:主路线走 cdn.syndication.twimg.com 的公开聚合接口,失败时兜底 guest_token + GraphQL,全程不需要用户登录。
隐私设计:能不申请的权限都不申请
鸿蒙的权限体系比传统 Android 严格得多,f2-hap 的应对策略很值得借鉴:
- Cookie 只存在应用沙箱的
preferences里,不上传、不出设备 - 除目标平台自家域名外,不连任何服务器;没有统计、没有埋点
- 下载文件落在沙箱
filesDir/downloads,存相册走showAssetsCreationDialog系统弹窗逐次确认,而不是申请受限的相册写权限 - 剪贴板权限在启动时动态申请,并在
module.json5里写明 reason
构建踩坑实录:DevEco 签名的那些暗坑
项目的 docs/BUILD.md 简直是一份鸿蒙构建踩坑百科,几个典型的坑:
1. 调试 profile 与包名强绑定。 调试 .p7b 里写死了 bundle-name,与 app.json5 不一致时 SignHap 阶段直接报 00303074。本工程包名 cn.lancenas.f2hap,必须在 DevEco 里为本工程重新自动签名。
2. products 必须引用 signingConfig。 即使 signingConfigs 配好了证书和口令,如果 products[].default 少了 "signingConfig": "default" 这一行,hvigor 会静默产出未签名包(部署报 9568320 no signature file)——不报错、不警告,这个坑最阴。
3. 环境变量指向。 DEVECO_SDK_HOME 必须指向含 default/ 的父级目录(hvigor 会自己拼路径);JAVA_HOME 必须指向 DevEco 自带 JBR(JDK 21),否则打包阶段报 00308018,真实原因藏在日志深处是 Unable to locate a Java Runtime。
仓库自带的 scripts/dev-build.sh 把这些全封装了:自动探测 JDK/SDK、从 ~/.ohos/config 读调试证书、校验 p7b 绑定包名、trap 无条件还原 build-profile.json5 防止签名口令入库。一条命令构建安装:
1 | git clone https://github.com/Lancenas/f2-hap.git |
ArkTS 严格模式速查:写给被编译器毒打的开发者
从 TypeScript 转 ArkTS 的人都会经历一段「为什么这也不行」的时期,BUILD.md 里整理的速查表相当实用:
| 限制 | 禁止 | 替代 |
|---|---|---|
arkts-no-indexed-signatures |
interface Q { [k: string]: T } |
type Q = Record<string, T> |
arkts-identifiers-as-prop-names |
{ 'Content-Type': v } |
先声明常量再 obj[KEY] = v |
arkts-no-untyped-obj-literals |
字段不全的对象字面量 | class 构造函数 / 工厂函数 |
arkts-no-destruct-decls |
const [a, b] = s.split('_') |
用下标 |
arkts-no-structural-typing |
结构相同即可赋值 | 显式构造目标类型 |
arkts-no-is |
x is T 类型谓词 |
返回 boolean,调用方自行收窄 |
连 String.replace 的回调重载都被禁了,得手写字符扫描。可以说这个项目本身就是一个「ArkTS 严格模式大型实战场」。
总结
f2-hap 的价值不只是一个能用的无水印下载器,更是一份完整的 HarmonyOS NEXT 原生开发参考实现:
- 纯 ArkTS 解析引擎:国密签名算法本机化,摆脱对 Python/Node 子进程的依赖
- 单运行时架构:用 TaskManager 内存队列替代跨进程文件队列,规避了桌面版的经典坑
- 合规的权限策略:能用弹窗授权的绝不申请受限权限
- 可复制的工程化经验:一键构建脚本、签名防泄漏、ArkTS 严格模式避坑表
如果你正在做鸿蒙原生应用(尤其是需要网络请求、文件下载、系统集成类的),这个仓库的 core/ 目录和 docs/ 目录都值得逐文件细读。
项目地址:
免责声明:该项目仅供个人学习与备份自己可访问的公开内容使用,请遵守各平台服务条款与著作权法。