音乐解析 2.0 → 2.8.3:把一条转换队列做成安静的本地工具


项目仍在维护。本文只讨论工程结构、产品取舍和体验边界,不提供绕过版权或付费限制的方法,也不提供 APK 下载。所有处理都发生在用户自己的设备上,只针对用户合法拥有的音频文件。
起因
做“音乐解析”的起点,比想象中更普通:我有一堆从不同设备、不同时间留下来的音频文件,格式不统一,有些能直接播放,有些必须先在某个 App 里转一次;每次都要打开电脑、找工具、等进度,最后还得手动把文件拖回手机。
我想做的不是“再做一个下载器”,而是一个更窄的东西:把文件选进来,让它在手机本地完成整理,然后直接得到能播放的文件。不需要登录、不需要上传、不需要把文件交给第三方服务器。
项目从早期的“音乐解锁 Pro”一路改到 2.8.3。名字换成了“音乐解析”,界面从工具页变成了一个带底栏、主题、推荐和更新日志的完整 App,但核心目标一直没变:本地、队列、可见的进度、可恢复的失败。
它到底做了什么
到 2.8.3 时,它已经不只是一个“选文件 → 出结果”的按钮:
- 转换队列:支持多文件排队,逐条显示进度、当前文件和完成数量;失败的文件不会被静默跳过。
- 输出选择:可以选输出格式、压缩档位和保存目录;不想重新编码时,也可以保留原始音频流。
- 速度档位:从高音质到极速,编码速度和文件体积之间可以自己取舍。
- 通知栏进度:切到后台也能看到当前文件和完成数;完成、失败、清空队列都有明确状态。
- 推荐与更新:内置推荐页、版本检查、更新日志和公告,至少让“这个版本改了什么”有地方可查。
- 反馈入口:网页端有独立的反馈板,不要求注册,问题可以公开补充。
- 外观设置:浅色/深色、底栏样式、毛玻璃、液态玻璃和界面缩放,尽量让工具看起来不像一个临时脚本。
这些功能里,真正每天会被用到的其实只有前三项。后面的推荐、公告、反馈和主题,是项目逐渐“长出来”的部分,也是后来维护成本变高的原因。
技术结构
整体是“Android 壳 + 本地服务 + WebView 前端”的结构:
- Android 壳:负责启动本地服务、承载 WebView、处理文件选择/保存/分享和生命周期。
- 本地 Python 服务:只监听本机,处理文件识别、队列、转码、标签和落盘;所有数据都留在设备上。
- Java 编码层:把耗时的编码任务放进独立线程池,避免 Python 侧等待编码时把整个队列卡住。
- WebView 前端:队列、设置、推荐、关于和更新日志都在这一层完成;桌面浏览器也能打开网页端。
- 更新源:一个静态
update.json,只比对版本号;没有账号系统,也不依赖云端数据库。 - 反馈板:独立的小服务,负责收集公开反馈;和主程序解耦,挂了也不影响本地转换。

这套结构的好处是“离线优先、数据在本地”;坏处也很直接:Android 壳、Python 服务、Java 编码层和前端是四种技术栈,任何一层出问题,用户看到的都只是“转换失败”。
最难的部分不是“转码”
真正做过之后,最难的是下面这些事:
- 文件类型比想象中杂。 容器、音频流、采样率、声道、裸 PCM、超大 WAV、不同平台的命名习惯,都会让“同一条转换链路”出现例外。一个格式能读,不代表能直接写;一个文件能播,不代表能被系统编码器接受。
- 队列要让人安心。 转换不是瞬间完成的,用户需要知道“现在到哪了、还剩几首、哪首失败了、失败原因是什么”。进度条如果只是装饰,反而会增加焦虑。
- 并发和内存是跷跷板。 并行数开大,速度上去了,内存也上去了;手机不是桌面,四路并行在千元机上很可能先把后台杀掉。
- Android 的存储不是普通文件系统。 用户选择的目录要通过 SAF 持久化授权,写入失败还要有回退路径;文件名冲突、目录不存在、权限被回收,都是必须处理的正常情况。
- 更新和反馈要形成闭环。 版本检查、公告、更新日志、反馈板,看起来都不是核心功能,但它们决定了用户遇到问题时能不能找到答案。
- 界面的一致性很难。 队列、设置、推荐、关于四个页面如果各写各的样式,最后就会变成一个“功能都在这、但不像一个 App”的拼装物。
这也是为什么后续版本把很多精力放在“状态”和“边界”上,而不是继续加格式:能处理多少种文件不是唯一的价值,能不能让人清楚地知道发生了什么,才是。
做对了什么,没做好什么
做对的地方:
- 本地优先:没有账号、没有云端队列,文件不离开设备。
- 状态可见:当前文件、完成数、失败原因、通知栏进度都在同一个语义下。
- 更新源简单:一个静态 JSON 就够了,不需要为了检查版本再搭一套后端。
- 视觉统一:底栏、卡片、主题和设置分组尽量保持一套语言,工具感没有压过可用性。
- 边界写在明面上:只处理用户合法拥有的文件,不提供内容获取入口,也不把“能解多少”当成卖点。
没做好的地方:
- 功能贪多:推荐、公告、反馈、主题、更新日志同时推进,核心链路的测试时间被稀释。
- 异常提示不够早:有些格式是在转换开始后才报“不支持”,如果能在选择文件时就给出明确状态,体验会更好。
- 真机覆盖不足:部分目录选择器和厂商 ROM 的行为只在代码层验证过,没有足够的真机矩阵。
- 并发默认值偏激进:性能数据好看,但内存和后台存活是另一回事;默认值应该更保守。
边界与停不下来的维护
这个项目最容易走偏的地方,是把“本地工具”做成“内容入口”。一旦开始围绕“能拿到什么”做功能,产品就会从整理工具滑向内容搬运,接下来是无休止的站点适配、登录状态和规则变化。
所以现在的边界是明确的:
- 不提供绕过登录、付费墙或版权限制的功能;
- 不把第三方平台的内容做成可批量下载的资源库;
- 不在文章里写具体的绕过实现,也不提供安装包;
- 只讨论队列、格式、存储、性能和界面这些工程问题。
这也是为什么这篇文章只能写到“怎么做这个工具”,而不能写成“怎么拿到某些文件”。后者不是工程问题,是版权和平台规则问题。
现在的状态
项目仍在维护,当前版本是 2.8.3(versionCode 23,Android 11+,arm64-v8a,安装包约 21 MB)。最近的更新集中在两件事:
- 支持裸 PCM / WAV 的
audio/raw轨道,不再把这类文件一律归为“只能保持原始格式”; - 补充 RF64 识别,让母带/无损导出的大 WAV 也能继续转成 MP3。
更新源仍然是静态 update.json,版本检查只做一件事:比对 versionCode,然后决定要不要提示。没有账号系统,也没有把用户的文件上传到服务器。
给后来者的几句话
- 先做窄,再做全。 队列、进度、失败原因、保存目录,这四件事做好,比再加十个格式更有用。
- 把“不能做什么”写进产品。 边界越早说清楚,越不容易被误解成“什么都能拿”。
- 并发不是越高越好。 手机上的性能优化,最后往往输给内存和后台存活。
- 更新源和反馈入口是产品的一部分。 用户遇到问题时,能找到“这是哪个版本、有没有人遇到过”,比多一个功能更重要。
- 不要用“技术中立”给自己找借口。 工具的能力边界,最终要由做工具的人来划定。
项目归档与 GitHub
这篇文章的完整版本和配图会同步到 GitHub,仓库里只保留复盘文档和架构说明,不包含具体实现,也不提供 APK 下载:
GitHub: https://github.com/foldx-cn/music-parse-retrospective
作者:Sienna Fuca · 2026-11-14 标签:项目复盘 / Android / Python / 音频工具 / 本地优先
