把数据放在文件里而不是数据库里
存储 · 文件 · 取舍
只需说话,就能让应用变成你想要的样子
安卓修改大师智改工坊 · 把改 APK 从技术活变成一句话

一个能管项目、管历史、管用量、管账号的桌面软件,你会很自然地以为它背后有个数据库。但安卓修改大师智改工坊没有——它一个数据库都不装,所有东西都放在文件里。

具体说:你的项目是磁盘上的目录;每个项目的配置是一个 config.ini;改过的需求记录在 history.ini;界面偏好写在 settings.ini;登录缓存一类写在 local.ini;连那 3000 条话术都是一个 xml 文件。

这不是"省事",是一个明确的取舍。数据库带来事务、并发、索引、查询能力——这些都是真的好处;但代价是要有服务、要有迁移、要有备份策略、出了问题你打不开看。而这套软件的定位是"一个人在自己电脑上改自己家的包",在这个场景里,那些好处大部分用不上,而那些代价天天要付。

产品介绍页在 https://www.apkeditor.cn/ai-version.aspx,官网是 www.apkeditor.cn。这篇文章就拆这个取舍:把数据放在文件里,赚到了什么、亏掉了什么、什么时候会真正吃亏。

一、四个 ini,各管一件事

先认清楚它们的分工,因为分工本身就说明了设计思路。

settings.ini —— 全局的"偏好"。窗口尺寸、两个窗口宽度合计占屏比例、间隙、轮询间隔、最小宽高、启动时是否跟随、退出时是否关闭右侧进程、主题、首页技巧条开不开。这些的共同点是"你想要的",所以放在一个你能打开、能看懂、改坏了还能改回来的地方。

local.ini —— 全局的"既成事实"。登录缓存、头像地址、机器码、登录方式。这些不是偏好,是"这台机器上已经发生过的事",所以不放在给人改的那个文件里。

config.ini —— 每个项目一份。项目自己的信息:包名、版本、图标位置、启动页组件名、用哪套签名。注意它是"跟着项目走"的——换个项目就是另一个 config.ini。

history.ini —— 每个项目一份,记需求。按"记录1、记录2"这样递增,每一条就是你在输入框里写过的那句原话。

这个分法的核心是"跟着谁走":跟机器走的两份放在工作目录根上,跟项目走的两份放在项目目录里。于是"备份"这件事变得可以精确到"我要备份什么"——想留你的活,拷 Project;想留你的习惯,拷 settings.ini;local.ini 拷了也没用,它认机器。

一个很实用的读法

INI 是纯文本,用记事本就能打开。遇到"某个项目行为不对"的时候,直接打开那个项目的 config.ini 看一眼,往往比在界面里翻半天快。尤其是签名设置、启动页组件名这类"你设过一次就再没碰过"的东西——它们可能还停在几个月前的状态,而你早就忘了。

二、项目列表是"读磁盘"读出来的

这一条是整套设计的根:项目列表不是一个存在某处的清单,而是"扫一遍 Project 目录"的结果。

换句话说,一个项目之所以存在,是因为磁盘上有一个目录;它之所以消失,是因为那个目录没了。中间没有任何"索引"或"登记表"需要同步。

这个决定带来了一串很实际的性质,每一条都能对应到你日常会做的事:

性质一:拷走目录就等于拷走了项目。你把某个项目目录复制到另一台机器的 Project 下,打开软件,它就在列表里了。不需要"导入"、不需要"注册"、不需要联网验证。

性质二:删掉目录就等于删掉了项目。反过来也成立——这是它"没有回收站"的原因,也是为什么删除要有防呆:只允许删 Project 的直接子目录。这条限制看着别扭,实际是在保护你:你不可能因为点错一层,把整个工作目录连同工具链一起删了。

性质三:项目不按账号分家。列表是扫磁盘得来的,所以它跟"当前登录的是谁"无关。同一个工作目录,换个账号登进来,看到的还是那些项目。在小团队共用一台机器时这是优点(交接不用挪文件);把电脑借人时这是要注意的点(退出登录不会把项目藏起来)。

性质四:工作目录换位置,列表就"空了"。这就是那个最吓人的现象——启动时按 D → E → F → G → C 挑盘,取第一个能读写且剩余不少于 1GB 的。D 盘掉到 1GB 以下,程序就去 E 盘新建一个空的 Project,于是列表是空的,但你的项目一个都没丢。

这四个性质合起来,说明"读磁盘"这个选择买到了什么:一致性。目录在,项目就在;目录不在,项目就不在。不存在"数据库里说有、磁盘上没有"这种撕裂状态——而这种撕裂,正是很多软件出现"幽灵项目"(点进去报错、删也删不掉)的根源。

项目列表等于扫一遍目录的结果
没有登记表,就没有"登记表和实物对不上"这件事

三、出问题的时候,你能直接打开看

这一节讲的是"可调试性"——这个词很技术,但它对应的是一个很朴素的能力:东西不对的时候,你能不能亲眼看到它现在是什么样。

数据库方案下,这个能力是有门槛的。你得知道库在哪儿、用什么工具连、表叫什么、字段什么意思。普通用户到这一步就停了,只能靠界面提供的那些入口——而界面只显示它想显示的字段。

文件方案下,这个能力是零门槛的。双击打开,看到的就是全部。没有"界面没显示的那部分"——因为文件本身就是全部。

举个具体到能立刻用的例子:某个项目打出来的包,装到设备上老是起不来。你可能已经忘了半年前设过一次启动页组件名。

打开那个项目的 config.ini,看两行:包名对不对、启动页组件名写的是什么。如果组件名是空的,那程序就得靠"问设备"去解析——而解析失败的时候,它只能退回最后那一档猜测,猜错了自然起不来。这个判断,在文件里是三十秒,在界面里可能是半小时。

可调试性还有一个不那么显眼的好处:可以把"现场"发给别人。你遇到问题,把 config.ini 或者一段日志贴给同事。如果数据在数据库里,你要先想办法导出——而"导出"这件事本身就可能失败,或者导出一堆看不懂的结构。

当然,这个能力有前提:你得知道该打开哪个文件。这就是第一节那张分工表的意义——跟机器走的在根目录,跟项目走的在项目目录。知道这个,你就不会在根目录里翻一个项目的签名设置。

再补一个"该看什么"的清单,都是不看文件很难想起来的:包名和版本对不上——看 config.ini;启动页起不来——看 config.ini 里的启动页组件名;打包出来的证书不对——看 config.ini 里的签名设置,再看 pack.log 里 verify 那一段;某条需求改完没效果——看 history.ini 确认"当时到底怎么写的"。这四类加起来,能覆盖日常八成"莫名其妙"。

四、history.ini 那种"删一节就删一条"的设计

history.ini 的组织方式值得单独讲:它按"记录1、记录2、记录3"这样一节一节往下排,删掉某一节,就等于删掉了那一条记录。

这个设计看起来很原始——没有 ID、没有时间戳字段、没有索引,就是"第几节"。但它换来了三件事,每一件都是数据库不容易给的。

第一件:修改的最小单位是"一条",而且你能直接动手。界面上看到某条记录写得不好、或者不想留,删掉它,文件里就少一节。不需要"先查出主键再删",也不用担心删了主记录留下孤儿数据。

第二件:内容就是原话,没有编码。展开详情页的历史,每条显示 #序号 + 时间 + 需求原文,完整显示不截断;右边有「选择」,能把那条需求填回输入框。

这里有一个很关键的设计细节:history.ini 里只留用户原话,附件说明不进历史。为什么这很重要?因为附件说明里全是文件路径,路径是"当时那台机器上那个位置"——换台机器就失效了。如果把它也存进历史,那么"照上次那条再改一遍"这个动作就会失败,因为一半内容是无效路径。只留原话,历史就永远是可复用的。

第三件:备份是"拷文件夹",不是"导数据库"。这条最实际。你不需要任何工具、不需要停机、不需要"先导出再复制"。把 Project 拷到移动硬盘,就是完整备份——包括每个项目的配置、历史、工程、打包日志。

而恢复也是文件级的:某个项目的 config.ini 改坏了,只恢复那一个文件就行,其他项目完全不受影响;历史误删了一条,从备份里把那一个 history.ini 拷回来就行。

这种"最小可恢复单位"是很值钱的性质。数据库方案下,恢复往往是"整个库回滚到某个时间点"——代价是中间那段时间的所有改动一起没了。而文件方案下,恢复的粒度是"一个文件"甚至"一段文字"。代价小,是因为隔离做得好:一个项目出事,不会牵连另一个项目。

历史按节排列,删一节即删一条
只留原话,历史才永远可复用

一个能救命的习惯

如果你打算手改任何 ini 文件,先把它复制一份,改个后缀放在旁边(比如 config.ini.bak)。INI 对格式比想象中敏感:多一个空格、少一个等号、编码从 UTF-8 变成 ANSI,都可能让那一节读不出来。而有备份的情况下,出问题只需十秒就能回去;没备份,你可能要重新配一遍签名。

五、代价一:没有事务,写到一半断了怎么办

前面讲的全是好处。从这一节开始讲代价——而且尽量讲得具体,因为"没有事务"这四个字对大多数人没有意义。

事务解决的是"要么全做完,要么一点不做"这个问题。比如转账:扣了 A 的钱、还没加给 B 的时候断电了,钱就消失了。数据库靠事务保证这种事不会发生。

文件方案没有这个保证。写一个 ini 文件的过程通常是:打开、写入、关闭。如果在这中间断电、蓝屏、或者进程被杀,文件可能变成"写了一半"的状态。

但这件事的严重程度,要看"坏的是哪个文件":

  • settings.ini 坏了——界面回到默认,你重新调一次窗口比例和主题,两分钟。
  • local.ini 坏了——重新扫一次码登录,一分钟。
  • config.ini 坏了——这个项目要重设签名(如果你用的是自己的签名)。烦,但你手上还有签名文件。
  • history.ini 坏了——这个项目的需求记录没了。这个是真损失,因为"以前那条好用的说法"找不回来了。

请注意这个清单里没有 apk、没有工程文件。为什么?因为它们不是"一次写入"的——它们是大量文件,逐个写出来的。断电最多让最后几个文件不完整,而不会让整个项目变成一堆乱码。

这就是"文件方案"的容错特征:损失是局部的、可估的。它不会给你"全有或全无"的保证,但它把"坏"的规模控制在"一个文件"这个量级。而一个文件通常对应一件可以在几分钟内重建的事。

还有一个更常见的"半写状态",比断电常见得多:手动编辑出了错。你打开 config.ini 想改一个值,不小心删掉了某个等号,或者把编码存成了 ANSI。这时候的症状通常不是"打不开",而是"某一项读不出来,用了默认值"。——这种"坏了一半"的状态,比彻底坏掉更难发现。

所以对付这件事的办法不是"更小心",是"留痕"。打包全过程写进 pack.log,反编译输出写进 apktool.log。这些日志的作用,就是在"配置看起来不对"的时候,给你一份"当时实际发生了什么"的证据。——没有事务的系统,靠日志补;这是所有文件型设计的共同套路。

最该记住的一条

手改 ini 之前先复制一份。这不是"以防万一"的客套话——因为这类错误最典型的特征是"不会立刻报错"。你可能三天后打包才发现签名设置丢了,而那时候你已经想不起来是哪次改动造成的。有备份,你只需要做一次文件对比;没备份,你要重新推理三天。

六、代价二:两个人不能同时动同一个项目

第二个代价是并发。说清楚它的具体形态,比说"不支持并发"有用。

ini 文件是"整文件重写"的。意思是:程序要改其中一个值时,通常是读出整个文件、改掉那一处、再整个写回去。如果两个程序(或者两台机器)同时这么做,最后写入的那一份会覆盖掉另一份的改动——这叫做"后写者赢"。

表现出来的症状很典型:你在这边改了签名设置,同事在那边改了启动页设置,过了一会儿你发现启动页设置变回去了——因为他的写入覆盖了你的。而且没有任何提示,因为从文件的角度看,一切正常。

这个代价在什么场景下会真的咬人?三个:

场景一:把 Project 目录放在网盘同步里。这是最容易踩的坑。网盘客户端在后台同步文件,程序在本地写文件,两者会打架:轻则同步冲突生成一堆"副本"文件,重则某一方写的时候文件被锁住,直接报错。

场景二:两台机器通过共享盘或 U 盘打开同一个工作目录。同上,而且更糟——因为网络盘的延迟会让"读-改-写"这段窗口变长,冲突概率上升。

场景三:同一台机器上开了两个这个软件。这个不需要担心太多——因为两个实例会抢同一批窗口位置和同一份配置,通常你很快就自己关掉一个了。但如果你确实需要同时处理两批包,正确做法是给它们两个不同的工作目录(用命令行参数指定)。

反过来说,单机单人使用时,这个代价等于零。因为不存在"同时写"。而这套软件的定位就是单机单人——所以它愿意用"不支持并发"换前面那些好处。这是一个把使用场景想清楚之后做的取舍,而不是"技术上做不到"。

整文件重写带来的后写者赢问题
单机单人时这个代价是零,放进网盘就不再是零

一条实操建议

工作目录不要放进任何自动同步的文件夹。想备份就手动拷,或者用"只在某个时间点同步一次"的工具,而不是实时双向同步。如果你确实需要两台机器协作,正确做法不是共享同一个目录,而是各自有目录、需要时把 Project 下的某个项目整个拷过去。——这也正好是文件方案最擅长的事:一个项目就是一个目录,拷它就完了。

七、代价三:统计没有索引,只能算

用户中心那张资料卡上有四个数字:项目数量、修改总次数、占用空间、所在磁盘剩余。这四个数字正好展示了"没有数据库"的第三类代价。

先说这四个数字分别怎么来:

  • 项目数量——数一数 Project 下面有几个目录。
  • 修改总次数——把每个项目 history.ini 里的记录条数加起来。
  • 占用空间——把目录下所有文件的大小加起来。
  • 所在磁盘剩余——问一下系统。

看到"加起来"这三个字,代价就出来了:这些数字不是查出来的,是算出来的。

在数据库里,"项目数量"可能是一条查询语句,因为数量是维护在索引里的。在文件方案里,它必须真的去数。十个项目的时候是瞬间的事;两百个项目、每个项目里几千个文件的时候,这个"加起来"就要花时间了。

所以你可能会注意到一个现象:打开用户中心那一下,数字不是立刻出来的。那不是"卡",是它在算。而这类计算通常被安排在"你主动打开这个页面时"才做——因为它是统计,不是实时状态,没必要每秒钟更新。

反过来,这个代价换来了一个数据库不容易做到的好处:数字永远和实物一致。

举个具体场景:你从同事那里拷了一个项目目录进来,放进 Project。打开软件,项目数量立刻多了一个,占用空间立刻变了。因为统计是"数出来的",所以它天然包含这个新来的目录。

数据库方案下,这个过程通常需要"导入"——因为新来的目录在数据库里没有记录。如果不导入,就会出现"文件在、但软件不认"的状态。而这套软件不需要导入,是因为它压根没有"记录"这一层。

顺便说一句"修改总次数"这个数字的用法。它不是"你点了多少次立刻修改"这么无聊的一个计数器——它能反映一个项目的"折腾程度"。一个项目改了三轮就定了,说明需求想清楚了;改了十几轮还在改,说明问题不在工具上。而这类判断,正需要一个不撒谎的原始计数。

这四个数字里,最该看的是第四个

"所在磁盘剩余"是唯一会直接导致失败的一个。低于 1GB,程序启动时会跳过这个盘去找下一个——你的项目列表看起来就"空了";打包时盘满,失败会发生在中间某一步,现象是"昨天还能打,今天打不出来"。所以前三个数字是了解自己,第四个数字是防止踩坑。

八、话术库为什么也是 xml,不是数据库

3000 条成型指令,六大分类,存在程序目录下的 Resources\话术库.xml 里。这个选择和前面所有选择是同一个思路的延伸。

先看"为什么不用数据库"。因为那 3000 条的价值,有一半在"你能改它"。

想象一下如果它在数据库里:你想加一条"我们公司改包时总要改这三个地方",得找工具打开库、找对表、照着字段塞一条、注意编码、注意主键冲突,然后祈祷程序别把它当成脏数据清掉。而实际上,90% 的人想要的操作是"打开记事本,复制一段,改两个字,存盘,点刷新"。

再看"为什么是 xml,不是别的格式"。这里有三个候选:

CSV —— 不够。一条话术的正文可能有几百字,里面还可能有换行、有引号。CSV 在这些字符上非常脆弱,一个引号没转义,整个文件就错位了。而话术正文恰恰是最容易带这些字符的内容。

JSON —— 可以,但看中文难受。JSON 结构清晰,机器友好,但中文内容在编辑时经常被转义成 \u 开头的一串编码,人打开一看全是乱码一样的字符,立刻就不想改了。而这个文件的全部意义就是"人愿意改"。

XML —— 刚好。它有结构(分类、条目、正文各就各位),能直接放中文不转义,而且它的错误是"看得见"的:少一个闭合标签,用浏览器打开就会明确告诉你"哪一行出错了"。这一点对"手改文件"的场景非常重要——错误必须能被人自己定位。

而"点刷新重新读"这个动作,是这套设计的最后一块。它意味着改文件不用重启程序——改一条、刷一下、当场看效果。如果每次改都要重启,那么"可改"这个承诺的实际价值会掉一半,因为人不会为了改一个错别字去重启一个正在干活的软件。

话术库用 xml 的理由:结构、可读、错误可见
选格式的标准不是"先进",是"人愿不愿意改"

附:同样四件事,两种存法各要几步

把前面讲的拢成一张对照表,看得更清楚。四件事都是日常会做的:

要做的事 文件方案(这套软件) 如果换成数据库
备份 拷 Project 目录。一步。 停服务、导出、再拷文件。三步,而且要考虑一致性。
查"这个项目设了什么" 打开 config.ini。一步。 连库、找表、查那一行。要么会,要么等别人。
把项目交给同事 拷那个目录。一步,且自带全部状态。 导出成包、对方导入。两步,还得保证格式兼容。
两个人同时改 会冲突,后写者覆盖前写者。 能处理,靠事务和锁。

这张表最能说明问题的地方在最后一行:前三件事,文件方案是压倒性的"步数少";第四件事,数据库是压倒性的"能处理"。

所以真正的判断标准不是"哪个更先进",是"前三件事你做多少次,第四件事你遇到多少次"。一个人改自家的包,前三件事每周都在做,第四件事一辈子遇不到一次——那这个选择没有任何悬念。

九、什么时候真的该换成数据库

讲取舍最怕讲成"我的选择对,别的都不行"。所以这一节说清楚:什么情况下,文件方案会真的不够用。

情况一:多人同时改同一批项目。

这是最硬的一条。只要有两个人在同一时间改同一个项目目录,就会撞上"后写者赢"。这不是"偶尔出问题",是"一定会出,而且不会提示"。如果你们的真实工作形态是三个人一起维护五十个包,那文件方案就是不合适的——该上数据库,或者至少该上"服务器端存项目 + 客户端只做编辑"的结构。

情况二:需要跨机器实时看到同一份数据。

比如"我在公司改了一半,回家接着改,两边要看到同样的历史"。文件方案下这个需求只能靠"拷目录"来满足,而拷目录意味着"某一时刻的快照",不是"实时同步"。如果你需要实时,那必须有一个中心。顺带提醒一句:不要用实时双向同步的网盘去凑这个需求——那会撞上第六节讲的锁定与覆盖问题。

情况三:项目数量到了几千个。

遍历是要花时间的。几十个项目、几百个项目,文件方案的表现完全够用;到了几千个,光是"数一遍"就会让你在搜索框里打字时感到迟滞。而且那时候你需要的不只是快,还需要"按时间、按包名、按状态"这种多条件筛选——这恰恰是索引擅长、遍历不擅长的事。

情况四:需要审计、权限、不可否认。

比如"谁在什么时候改了哪个项目的哪个设置,要留下不可篡改的记录"。文件方案做不到——因为文件可以被任何有权限的人直接用记事本改,改完连痕迹都没有。这不是缺点,是它的性质:它假设使用者就是所有者。一旦"使用者"和"所有者"分开,就必须有中心化的记录。

把这四条反过来读,就是这套软件为什么能不用数据库:它假设单机、单人、几十到几百个项目、使用者就是所有者——这四条假设,恰好是绝大多数"改自家包"的真实处境。而在这四条都成立的场景里,文件方案的短板全部不成立,长处却全部成立。这就是"把使用场景想清楚"带来的收益:你不需要什么都会,你只需要在目标场景里不犯错——而在目标场景之外,你大可以承认自己不行。

一个判断口诀

问自己三个问题:(1)有没有两个人同时改?(2)要不要跨机器实时看?(3)项目会不会过千?三个都是"没有",文件方案就是更优解——它更快、更简单、更好备份、更好排查。任何一个变成"有",就该重新考虑了——而三个都变成"有"的那天,说明你已经不是这套工具的目标用户了,那是件好事。

十、迁移的完整动作,以及哪些东西会跟、哪些不会

"可迁移"这个好处,最好用一次真实迁移来说明。下面是换一台电脑的完整动作,一共四步。

第一步:拷 Project。从旧机器的 <盘符>:\AiApkEditor\Project 拷到新机器的同位置。这一步就是"把你的活带走"。

第二步:装软件,让它自己补工具链。新机器上装好之后,去「参数设置」看工具链体检——缺什么点「立刻更新」就行。这一步不用拷 tools,因为工具是可以重新下载的,而且新下的那套版本更新。

第三步:重新登录。因为登录态跟机器绑,换了机器要重扫一次码。这一步不是麻烦,是"这份登录缓存不该跟着文件走"的必然结果。

第四步:打开项目列表,确认项目都在。如果不在,先看工作目录指向哪儿——新机器上的盘符可能跟旧机器不一样(旧机器五块盘,新机器只有两块),而挑盘规则是 D → E → F → G → C。

现在说"哪些会跟、哪些不会",这一节最有用:

  • 会跟:项目本身、每个项目的 config.ini(包括你设过的签名)、history.ini(所有需求原话)、反编译出来的工程、打包产物、pack.log 和 apktool.log。
  • 不会跟:登录态(local.ini 认机器)、界面偏好(settings.ini 在工作目录根上,如果你只拷了 Project,主题和窗口比例会回到默认)。
  • 跟着走但要注意:如果旧机器上你改过 settings.ini 里的占屏比例、间隙、轮询间隔,想让新机器也一样,就把那份 settings.ini 也拷过去——它是纯文本,跟机器无关。

还有一个"换盘不换机器"的情况,动作更小:去「参数设置」把工作目录改到新盘就行。但要注意——改的是"家在哪儿",不是"把家搬过去"。程序不会替你搬文件。所以正确顺序是:先把旧目录整个拷到新盘,再改工作目录。反了的话,你会看到一个空列表,以为项目丢了——而实际上它好好躺在旧盘里,只是没人指向它。

迁移时哪些文件会跟走哪些不会
拷 Project 带走的是活,拷 settings.ini 带走的是习惯

十一、两个自家实例:文件方案在真实事故里救了什么

实例一:项目列表突然空了。

这是我自己踩过的。某个周一早上打开软件,项目列表是空的。第一反应是"硬盘坏了",第二反应是"要不要重装",第三反应是"我上周改的那个包还在不在"。

当时的处理顺序(现在回看是对的):先不重装、先不动任何东西。去「参数设置」看工作目录——指向 E 盘。而我记得一直在 D 盘。打开 D 盘的 AiApkEditor\Project,目录都在;再看 D 盘的剩余空间,不到 500MB。

原因就这么简单:启动时按 D → E → F → G → C 挑第一个"能读写且剩余不少于 1GB"的盘。D 盘不够了,它跳过了 D,在 E 盘新建了一个空的 Project。列表是空的,因为新目录里确实什么都没有。

怎么解决的:把 D 盘清出 1GB 以上,然后把工作目录改回 D 盘。项目全部回来,包括历史、包括签名设置、包括之前打过的包。

这个事故说明了什么?说明"文件方案"的一个隐藏优点:出问题的时候,你能顺着"文件在哪儿"这条线一路查下去。如果项目清单在数据库里,那么"列表空了"可能是清单被清、可能是路径变了、可能是服务没起——而文件方案下,你只要回答一个问题:目录还在吗?这个问题回答完,剩下的都能自己推。

顺便,这次事故之后我们改了两个习惯:一是每月看一眼用户中心那个"所在磁盘剩余";二是把工作目录主动指定成固定盘,而不是让程序每次自己挑。——让它挑的代价是"可能换位置",而换位置这件事只有在你已经攒了一堆项目之后才会变成麻烦。

实例二:把一个项目整个拷给同事。

我们有一个自家店铺应用,之前是我在维护,后来交给同事。正常的交接方式应该是"文档 + 培训",但那太慢;我们直接拷目录。

具体动作:在 Project 下找到那个 8 位随机名的目录,整个拷到他的机器上,放进他的 Project 下。他打开软件,项目就在列表里——不需要导入、不需要注册、不需要联网。

更关键的是"拷过去了什么":那个项目的 config.ini 里存着我们设过的签名(公司统一的那套),所以他第一次打包就不用重新配签名;history.ini 里有十几条需求原话,他打开历史就知道这个应用被怎么描述过;apktool 目录里是上一次改到一半的工程。

他怎么验证接手成功:什么都不改,直接点「去打包」,打出来的包 verify 一下证书,跟公司那套一致,就说明环境接上了。然后改一句无关紧要的文案,走一遍完整流程,装到设备上确认能起来,交接就算完成。

这个实例最能说明"一个项目就是一个目录"的价值。它把"交接"从"讲一遍"变成了"搬一次"。而这件事之所以能做到,是因为那个目录里自带了一切:配置、历史、工程、日志——没有一样东西存在"别的地方"。

补一个动作:只恢复一个文件

这是文件方案最实用、也最少被提到的一个动作。假设你手上有一份三天前的完整备份(就是那个 Project 文件夹),而现在某个项目的配置坏了。

动作只有一步:从备份里把那个项目的 config.ini 拷回来,覆盖现在的。其他的都不用动——工程文件不用还原、历史不用还原、别的项目更不用碰。

为什么这件事值得单独说?因为它在数据库方案里做不到这么便宜。数据库的恢复单位通常是"整个库"或者"某个时间点的快照"——你要恢复一行,得先把它还原到一个临时库,再挑出来倒回去。而这里,恢复的单位是"一个文件",动作是"拖过去,覆盖"。

这个能力还有一个变种:只恢复一部分历史。history.ini 是按节排的,你可以只把备份里那几节复制回现在的文件,把中间那几条不想要的留在备份里。——这种"挑着恢复"的粒度,本质上是因为文件是文本:文本可以用手拼。而这也再次说明为什么那个"删一节就删一条"的原始设计是有价值的:它让手动修改变得可能,而手动修改的可能性,就是最后的兜底。

两个实例的共同结论

第一个说明出问题时你能查到根因,第二个说明迁移时你不用重建任何状态。而这两件事,恰好是数据库方案最花钱的地方——查根因要懂表结构,迁移要写导出导入。文件方案把这两件事的成本压到了"打开一个文件"和"拷一个目录"。

十二、五个常问到的数据问题

问:我能直接删 Project 下的目录吗?

答:能,而且效果跟界面里删一样——因为界面里删也是删目录。但建议还是从界面删,理由是那条防呆:界面只允许删 Project 的直接子目录。你在资源管理器里删,少了这层保护,手滑删错一层的可能性是存在的。

问:删掉一个项目,会连带删掉工具链吗?

答:不会。tools 和 Project 是同级的两个目录,删除范围被限制在 Project 的直接子目录,tools 根本不在可删范围内。这也是"两个目录分开"的实际收益之一:你清理项目的时候,不会一不小心把 apktool 删掉然后花半小时重装。

问:我能在两台电脑上看同一批项目吗?

答:能,但方式是"拷",不是"同步"。把 Project 拷过去就行,两台机器各自有一份。代价是两份会各自演化——你在 A 机器改的项目,B 机器看不到,除非再拷一次。如果你需要的是"两边永远一致",那就是第九节讲的"该上中心化方案"的情形,别用网盘硬凑。

问:改了一个 ini,程序读不出来,怎么办?

答:三步。第一,看你有没有备份——有就换回来,十秒的事。第二,如果没有备份,把文件里你刚改的那一段恢复成原来的样子(哪怕记不清,也把明显的格式问题修掉:等号、引号、空行)。第三,检查编码——这是最隐蔽的一种,文件内容看着完全正常,但存成了 ANSI,中文就全乱。用能明确选 UTF-8 的编辑器重存一次。

问:项目目录的名字是一串乱码一样的字符,能改名吗?

答:那是每个项目建目录时生成的 8 位随机字符串。用随机名而不是"包名+版本",是为了避免重名和特殊字符——包名里有小数点,版本号里有加号,直接当目录名容易在某些场景下出问题。至于改名:技术上目录名就是项目标识,改名等于换了一个项目,界面上的项目名是另一回事(那是给人看的)。所以不建议手动改目录名,想区分就用项目名或者配色。

十三、用过的人怎么说

"最实用的是能打开看。有次打包出来的包起不来,我打开项目的 config.ini 一看,启动页组件名是空的——那是我半年前清过一次。填回去就好了,全程两分钟。"

—— 老周 · 做了十几年运维

"交接的时候我直接把那个项目目录拷给同事,他打开就能用,连签名都不用重配。以前交接要写一堆文档,现在文档只剩一句:把这个文件夹拷过去。"

—— 阿凯 · 电商公司内容负责人

"我把工作目录放在网盘同步里,结果项目列表出现了好几个『副本』文件,还报过一次错。后来挪出来就好了。这个教训写下来给后来人:别把工作目录放进实时同步。"

—— 小唐 · 独立开发者

"历史里只留原话这一点我很喜欢。以前用别的工具,历史里全是文件路径,换台机器就一半失效。这里点『选择』直接填回输入框,改两个字就能用。"

—— 阿May · 产品经理

"我们三个人一起维护几十个包,说实话这套不适合我们——不是软件的问题,是我们需要一份共享的、实时的东西。我们现在的做法是各自有目录,改完把项目目录传到共享盘上,约定好谁在改哪个。"

—— 老陈 · 外包团队负责人

十四、把数据放在文件里,本质上是一种承诺

绕了一圈,回到最开始的判断。不装数据库不是一个技术选择,是一个承诺:你的东西始终是你能打开、能拷走、能看懂的。

这个承诺有三层含义:

第一层,你不被锁住。哪天你不想用这个软件了,那些项目目录还在,config.ini 还在,history.ini 还在。它们不需要这个软件才能被理解——它们是纯文本和普通文件,任何一台电脑上都能打开。

第二层,你能自己修。出问题的时候,你有工具(记事本)、有线索(日志)、有边界(一个文件、一个项目)。你不需要等别人回消息,也不需要理解一套别人的表结构,更不需要为此装一个客户端。

第三层,代价是明确的。没有事务、不能并发、统计要算。这三条不是"我们没想到",是"我们算过账,觉得在这个场景里划得来"。而一个愿意把代价写清楚的产品,比一个只说好处的产品更值得信任——因为你迟早会撞上它的边界,早一点知道边界在哪儿,比晚一点撞上去好。

只需说话,就能让应用变成你想要的样子。而"说话"这件事的产物——你写过的每一句需求、你改过的每一个包——都应该留在你自己能碰到的地方。这就是那堆文件的意义:它们不需要许可,也不需要联网,只需要你愿意打开它。

安卓修改大师智改工坊的产品页在 https://www.apkeditor.cn/ai-version.aspx,官网是 www.apkeditor.cn。它替你省掉的是查文件、重打包这些机械的活,留下的是"你想要什么"和"你怎么知道成了"——这两件事,恰好是整条链路上唯二真正属于你的部分。

合规提醒

本文讨论的所有改动,都应在自己拥有版权、或已获得权利人明确授权的应用上进行。请勿用于破解他人软件、绕过授权验证、去除版权标识或任何侵犯他人权益的用途。文中提到的自家应用实例,均为我们有权修改的项目。改包工具本身是中性的,用它做什么,责任在使用者。


安卓修改大师智改工坊

你的项目就是几个文件夹,随时能拿走

导入 → 一句话描述 → 打包 → 装机确认,四步走完
官网 www.apkeditor.cn

立即下载智改工坊(AI 版)

支持 apk / apks / xapk / apkm 等包型 · Windows 桌面端