ARTICLE · 1305870
抖音去水印,我把它做成了 57KB 的安卓 App
| 安卓实战 | NO.14 / 码途日记 |
先把这东西干什么的说清楚。在抖音里点分享、复制链接,把那一串粘进去,它就能把无水印的视频和图集解析出来,直接存到手机上。视频能选画质,图集能整组下,也能只挑其中一张。
它原来是给 Windows 写的。双击 exe,浏览器弹出来,粘链接,解析,下载。用了一个月,唯一别扭的地方是我只能在电脑前用它。手机上刷到想留的素材,得先分享到微信,再回电脑上粘一遍。
搬这个的念头就是这么来的。整个过程我从头记一遍,从 1008 宽的窗口到 412 宽的屏,中间改的都是很具体的东西。
| 01 | 它原来长这样 |

上面是解析出来的单条视频,下面是图集,两个窗口都是 1008 宽。界面上的东西不多:封面、标题、画质选项,再加一个下载按钮。
它不是一个命令行脚本。python3 douyin_dl.py 跑起来干两件事:起一个本地 HTTP 服务,然后用默认浏览器开一个页面。1452 行 Python 里一大半是在实现接口,界面是另外那个 52KB 的 index.html。
接口只有四个。/api/parse 解析,/api/task 轮询任务进度,/api/download 落盘,/api/stream 代理媒体流。桌面版和网页之间就靠这四个 URL 说话,别的不共享。
这一点很重要,后面所有决定都是从这个形状推出来的。
| 02 | 三条路,选了最笨的那条 |
安卓版有三条路。
Kivy 或者 BeeWare,用 Python 直接跑在手机上。听着最省事,实际是把那 52KB 网页整个重画一遍,CSS 重写,动效重调,等于做第二个产品。
Chaquopy 把 CPython 塞进 apk,Python 代码几乎原样不动。代价是包里带一整套运行时,几十兆起步,冷启动也慢。
第三条是逻辑用 Java 重写,界面继续用那个网页。
我选了第三条。理由不复杂:接口形状不用变。安卓这边把四个 URL 的路径和参数对齐,返回的 JSON 长得一样,index.html 一行都不用改,连带上面那些动效和布局细节全都白捡。
代价是 1452 行 Python 得逐行翻成 Java,最后出来 1904 行。
| 03 | 五份代码,拼成一个 App |
拆下来是五个文件。
Douyin.java 707 行,管 ttwid 注册、拉作品详情,把带 playwm 的播放地址换成无水印的源地址。Api.java 578 行,四个接口的路由和 JSON 组装。HttpSrv.java 335 行,手写的 HTTP 服务,ServerSocket 加线程池。Store.java 149 行,负责落盘。MainActivity.java 135 行,WebView 壳和剪贴板桥,负责返回键。
三个地方换了写法。
剪贴板。navigator.clipboard.readText() 在 WebView 里多数机型直接 rejected,虽然 127.0.0.1 按规范算安全上下文。不跟它较劲,自己开个口子:
请求正文。原来的写法很顺手,BufferedReader 一行行读请求头,读到空行,再按 Content-Length 去原始流读正文。
问题出在 BufferedReader 内部有 8KB 缓冲,它读头的时候顺手把正文也吸进去了。回头再去 InputStream 读,拿到空字符串。表现是「解析按钮点了没反应」,这类不报错的坑最难查。
改成一个字节一个字节读行,不多读一个:
改完专门测了一遍,发 4012 个字符的 JSON 过去,服务端收到的长度一个不差。
落盘。桌面版先写 .part 临时文件,写完 os.replace 改名,靠这个保证「你看到的文件一定是完整的」。安卓上换一套:API 29 以后要往 MediaStore 插一条记录,系统给 content URI,你往里写,写完这条记录才成为一个真文件。好处是文件直接出现在系统「下载」里,文件管理器和相册都能引用。
三个地方改完,第一版打出来 53KB,装到手机上长这样:

界面跟桌面版一模一样。复用的好处就在这儿,一行 CSS 没动。
但屏幕从 1008 宽变成 412 宽,同一份 CSS 在两个尺寸上算出来的东西不一样。下面三处是装上去之后一处一处改的。
| 04 | 不用 Gradle,五条命令 |
打包没走 Gradle。
这台机器没装 Android Studio,dl.google.com 十分钟连不上。后来从国内镜像单独拉了 build-tools 和 platform 两个压缩包,解到 D:/develop/android-sdk,干脆不要 Gradle,直接调底层:
一条 shell 脚本串起来,十几秒跑完。往 apk 里塞 classes.dex 那一步卡了一下:习惯性写了 zip -qf,这台机器没装 zip 命令,最后用 Python 的 zipfile 三行补上。
| 05 | 第一个改的是「目录」 |
第一版留了个「打开文件夹」按钮,ACTION_VIEW 指向 content://media/external/downloads。点下去弹的是这个:

夸克、阿里云盘、百度网盘,一个文件管理器都没有。
原因是那个 URI 没带 MIME 类型。系统拿不到类型,就按 */* 去匹配所有声明能收 content URI 的应用,而真正在这条路径上注册过的恰好是那堆网盘。查文档才明白这是按类型匹配的必然结果,没有哪个文件管理器会主动声明自己能收裸的 content://。
那就别调系统了,App 里自己列。API 29 以上按相对路径查,只捞自己下载的:
29 以下退回遍历目录。两套都留着,minSdk 定的是 21。
列表页第一版只把结果存内存 Map,App 一重启就空了。改成每次打开都去 MediaStore 现查一遍,查一次几十毫秒,比维护缓存省心。
列表用 iframe 浮层盖在主页上,不整页跳转,这样解析结果不会丢。分享走 ACTION_SEND 带 MIME,落到系统分享面板,微信、抖音、文件管理都在里面。
| 06 | 31 张图,和那行 aspect-ratio |
抖音图集到 31 张的时候,缩略图开始互相压:

上面那张是改之前的,第二行盖在第一行上,点第二行实际点到的是第一行那张。下面是 23 张的同一套布局。
格子按竖版 3:4,CSS 写得很顺手:
aspect-ratio 和 height: 100% 放一起会形成循环依赖。图片高度依赖容器高度,容器高度由 grid 行高决定,行高又希望由内容撑开。桌面 Chrome 恰好能算出一个对的结果,WebView 算错了。
改成用 padding 撑比例,图片绝对定位铺满:
133.333% 就是 4/3,撑出一个竖版盒子。绝对定位的百分比参照的是 padding box,循环断了。
顺带一个触屏的事。缩略图上的下载图标原来是 opacity: 0 靠 hover 显形,这是桌面版的习惯。手机上根本没有 hover,那排按钮永远看不见。窄屏下改成常显,代价是图上有几个小方块,比点不到强。
有没有真的对齐,别用眼睛判断。在 WebView 里注入一段脚本,把所有格子的 getBoundingClientRect() 打出来,一行行看顶边和底边。我那次发现第七格的顶是 145,第一行底是 139,差 6 像素,肉眼看不出,手指点下去就是错的。
| 07 | 大图底下那个按钮,改了三版 |
点开大图要能单独存这一张。左边是刚装上那会儿,底下只有页码;右边是最后的样子,按钮改了三版:

第一版是个 position: absolute,贴在大图下方。缩略图挤在一起的时候,人点开大图就是因为小图上点不准,结果按钮还叠在图片上,被盖掉一半。
第二版把它挪到浮层底部,加 padding、加 z-index,又把兼容性加固一遍(inset: 0 要 Chrome 87 以上,改成写四个边)。装上还是看不到。
第三版不缝了,改结构。
原来那个浮层是 position: fixed 的全屏层,图、左右箭头、关闭按钮全靠绝对定位在一个坐标系里往上叠,图一高就把按钮顶出去。改成两段:上面一段放图和箭头,下面一段放按钮和页码,两段都在正常文档流里,用 flex 分高度。
min-height: 0 不能省。不加这行,flex 子项的最小高度会按内容算,图一高照样把下面那段挤出去。
按钮本身做成三态,可下载、下载中、已下载。判断依据不是点没点过,是服务端返回的 files 字段,也就是真落盘的记录,缩略图上那个绿对勾用的是同一份数据。轮询到文件出现,按钮才转绿;点完到转绿之间写「下载中」,按不动,防连点。
中间有个小坑。服务端每轮询返回的都是新数组,items = data.items 一整个替换,灯箱里存的那个对象引用就变成旧的了,读不到新 files。解法是每次按 index 从当前数组重新取,别信引用。
| 08 | 57KB |
53KB 到 57KB,多出来的 4KB 是一个文件列表页 3.9KB、大图浮层的样式重写、下载状态机那几十行 JS。
这个体量下,每加一个功能都能在体积上看见。也正因为小,改起来才敢一次一次试,改完到打好包十几秒,装上就能测。
要是走的是 Chaquopy 那条路,包几十兆,装一次要等,我大概改到第二版就懒得动了。
抖音去水印下载器 v1.3 现在能用了,安卓手机直接装,不用 root,不用装任何框架。
拿的方式:公众号后台回「去水印」,自动回你下载链接。网盘也存了一份,密码在自动回复里。
装完先看一眼首页标题下面那行小字,写着 v1.3 就是最新的。旧版要先卸载再装,签名换了,覆盖装会失败。
这个工具不收费,也不打算收费。用着不顺的地方回我,能改的我都改。
你手上有没有哪个只在电脑上用着顺的小工具,想搬到手机上?
评论区聊聊,我一条条回
关注「码途日记」,写点技术人真实做过的事
已关注的设个星标,不然容易收不到















































































