只需说话,就能让应用变成你想要的样子
安卓修改大师智改工坊 · Windows 桌面端 · 拖入安装包,用中文写需求

先说清楚这篇要解决的真实问题:测试同事的手机上要同时装两个「同一款应用」—— 一个是从应用市场装的正式版,一个是带新功能、还没上线的内测版。你不想让内测版覆盖正式版(那会把登录态、聊天记录、本地数据全搅在一起),也不想每测一轮就把正式版卸掉重装。你要的是两个图标并排躺在桌面上,互不干扰,各自升级。

安卓修改大师智改工坊是一款 Windows 桌面工具:拖入安装包,用中文写需求,AI 去改 smali 与资源,改完自动回编、对齐、签名、校验,再一键装到手机或模拟器上看效果。它的介绍页在 https://www.apkeditor.cn/ai-version.aspx,官网是 www.apkeditor.cn。共存改造恰好是它最擅长的活:这类改动「点多、面广、每一点都不难」,人手工做容易漏,交给一句话 + 一份清单反而更稳。

这篇分成两半:前半讲原理(安装器怎么判定同一应用、改包名之后为什么就变成两个应用、哪些地方会因为「两个包共用一个标识」而打架),后半讲用法(需求怎么写、清单怎么排、两套包怎么在工具里各占一个项目并行迭代)。所有例子都来自我们自己和同事的自家应用,不会涉及任何他人的商业应用。

内测版与正式版并存示意
共存的目标:两个图标、两个包名、两份数据,各自能升级,互不覆盖

一、先弄清 Android 是怎么判断「这两个包是同一个应用」的

共存这件事的全部难度,都来自系统的一句话:安装时的唯一身份是包名(applicationId),而同一个包名的更新必须签名一致。 把这句话拆成两条规则,就能推出后面所有的行为:

规则一:包名不同 = 两个不同的应用

系统会把它们放在两个独立的数据目录里,各有一份自己的登录态、缓存、本地数据库;权限要分别授权;桌面各自一个图标;升级也各升各的。这一条正是「共存」的实现基础 —— 我们要做的,就是把内测版变成一个「包名不同、但功能一致」的应用。

规则二:包名相同 = 同一个应用,签名必须一致

包名相同、签名相同,覆盖安装(数据保留);包名相同、签名不同,安装器会直接拒绝,报的错就是那句让人抓头的「签名不一致」。工具在装机这一步对这种情况有明确的处理:检测到这个报错会给出一句人话提示(说明设备上已经装了签名不一样的同名应用),并弹出确认,问你要不要「卸载并重装」—— 因为卸载会清掉那个应用的数据,这个决定必须由人来做。

顺带说清一个经常被混淆的点:版本号不参与「是不是同一个应用」的判定,它只影响「能不能覆盖上去」。设备上已经装了更高版本时,安装器会拒绝降级;工具在装机链路里对这种情况会先按常规覆盖安装试一次,如果设备回的就是版本降级,会自动改成允许降级的参数再装一次,数据保留 —— 这样你在调试阶段「新包版本号比设备上的低」也不会白折腾一轮。另外如果是清单里带了仅供测试标记的包,工具也会自动换用对应的参数重试,这些套路都写在装机那一步里,不需要你记。

内测包与正式版的关系 安装时会发生什么 数据
包名相同、签名相同 覆盖安装,桌面还是一个图标 保留
包名相同、签名不同 直接拒绝,提示先卸载 卸载会清空
包名不同 当作两个应用并存 各自独立,等于全新安装
包名不同、但共用了同一个组件标识 安装失败(冲突类报错) 还没装上,谈不上数据

表格最后一行是共存改造里最典型的坑,也是本文第三章要展开的清单核心:包名分开了,不代表应用内部那些「跨应用唯一的标识」就自动分开了。系统只帮你按包名分区,剩下的要靠改。

签名这一关:共存改造为什么一定会牵出重签

还有一条规则必须知道:任何对包内容的修改,都会让原来的签名失效,所以改完必须重新签名,这一点对共存改造同样成立。工具的做法是在打包链路里自动完成这一步:回编之后对齐,然后签名,最后再校验一遍。签名用的密钥放在工作目录根目录下面(testkey.pk8 与 testkey.x509.pem),这两个文件是可以替换的 —— 团队如果有自己的测试签名,把它们换掉即可,换完不需要改任何配置。

测试签名这件事在共存场景里反而是一种保护:内测包用的是你自己这套签名,与市场渠道那份签名天然不同,所以就算有人误把内测包当成正式包去装,也只会得到一个「签名不一致、装不上去」的结果,而不是把正式版覆盖掉。但代价也在这里:所有「按签名认你」的第三方能力(推送、开放平台、部分统计与支付通道)都需要为新组合重新登记一次 —— 这就是清单里第 3、4 项存在的原因。

二、改包名之后,为什么就能独立安装了

从技术上说,改包名改掉的是安装包清单里的包声明,以及代码与资源里所有引用到这个包名的地方。工具的做法是把安装包反编译成一个工程目录,AI 在这个工程里改,改完再由工具回编。所以「改包名」在工具里不是一次魔法替换,而是一次覆盖到点的批量修改:清单里的包声明、代码里写死的包名字符串、需要保持唯一的组件标识,都会被点到。

这里有一个设计上的取舍值得说明:为什么不让工具「一键改包名」自动全自动跑完?因为改包名这件事没有全局正确的答案:加什么后缀(.beta / .inner / .test)、哪些标识要跟着改、哪些必须保持原样(比如服务端认识的那个包名白名单),这些都是项目决策,不是机械替换。工具选择把反编译工程、原始包副本和历史记录都摊在你面前,让你用一句话把决策说清楚,再由 AI 执行 —— 这也是本文第四章教你怎么写需求的原因。

还有一个边界要提前说:不是所有包都能顺利改包名。分包(apks / xapk / apkm)、加密包、以及以 jar / class 形式导入的内容,本来就可能解析不出完整包信息 —— 工具在这种情况下的行为是「以文件名继续建项目,并在页面上给一句说明」,也就是说项目照建、活照干,但你要知道它拿到的信息不完整,改包名这类动作要更谨慎。加固类应用则是另一条劝退线:壳里的代码与资源不在你能改的范围里,硬改只会得到装得上、打不开的结果。

包名变化带来的分区示意
包名是系统给应用划的「身份分区」;分区一变,数据、权限、图标就都分开了

三、共存改造清单:八处连带改动,少一处就出问题

下面这份清单是我们自己在做内测版共存时反复用到的。它的组织方式是「改造项 → 不改的后果 → 改法要点 → 怎么验证」,你可以直接把它改写成一句需求发给 AI。清单里前两项是硬门槛(不改就直接装不上或者装上了互相覆盖),中间四项是功能类(装上了但某个功能不工作),最后两项是数据类(数据不干净、看板对不上)。

改造项 不改的后果 改法要点 怎么验证
1. 包名 被当成同一应用,互相覆盖 加后缀,全工程同步 桌面两个图标;应用列表两条
2. provider 的 authorities 安装直接失败(标识冲突) 同样加后缀,做到全局唯一 装包成功;拍照 / 分享文件可用
3. 推送接入 推送收不到,或报「应用不存在」 给内测包单独登记一套配置 冷启动后能收到一条测试推送
4. 分享 / 登录回调 分享出去回不来、登录回调失败 为内测包登记「包名 + 签名」 完整走一次分享并成功回跳
5. 自定义 scheme(深链) 从浏览器唤起时弹「选择应用」 内测版换一个前缀 浏览器唤起的是内测版
6. 桌面区分(名字 / 图标) 测试同事点错应用 名字加「内测版」、图标加角标 肉眼扫一眼就能分清
7. 渠道与上报 内测数据混进正式看板 指向测试渠道 / 测试环境 抓包看渠道字段与上报域名
8. 数据与登录态 以为能继承,结果要重新登录 把它当全新安装来安排测试 登录一次,确认能正常用

第 1、2 项为什么是硬门槛:包名管的是「应用」,而 authorities 这类标识管的是「这个应用对外暴露的入口」。系统的安装校验会检查跨应用唯一的组件标识是否被占用 —— 两个包如果声明了同一个 authorities,第二个包根本装不上,报的还是一种看起来跟包名无关的冲突错误。工具在装机环节会把人话提示与原始报错一起给你,但根治办法只有一个:让 authorities 跟着包名一起变成唯一的。

第 3、4、5 项的共同点是「第三方平台按包名认识你」。推送、开放平台分享、登录回调,这些能力大多要求你在服务商那边登记「包名 + 签名」的组合。你把包名改了、把包重签了,服务商那头不认识新组合,于是表现就是「功能静默失效」—— 不崩、不报错,就是不工作。这也是共存改造里最容易被漏掉的一类问题:它不在你的代码里,而在你在别处登记的配置里。

第 7 项更值得展开:内测包如果不把渠道与上报切到测试环境,测试同事的每一次启动、每一次点击都会混进正式数据里,看板会莫名其妙地跳。内测包「不报正式渠道」其实是一种设计,而不是故障 —— 这一点我们在讲统计与埋点的那篇文章里会专门展开。

最后提醒一句:清单不要贪多。先做能装上的最小组合(1、2、6),再补功能类(3、4、5),最后处理数据类(7、8),每一轮都装到设备上验证一次,比一口气改十几处然后对着一个装不上的包猜原因,效率高得多。

故障速查:共存改造后最常遇到的六种症状

症状 最可能的原因 处理方向
装包直接失败,报的是一句看不懂的冲突 唯一标识(如 authorities)与正式版重复 把这类标识跟包名一起加后缀
装上了,但拍照 / 分享文件这一步异常 标识改了,代码里另一处还是旧值 全工程搜一遍该标识,统一替换
推送一条都收不到 推送平台登记的仍是老包名 为内测包单独登记一套配置
分享出去回不来、登录回调不触发 开放平台登记的「包名 + 签名」不匹配 把新的包名与签名登记进去
从浏览器点链接会弹「选择应用」 两个包注册了同一个 scheme 内测版换一个前缀
看板上多出一批来路不明的数据 内测包报了正式渠道 / 正式环境 把渠道与上报切到测试环境

这张表可以当成一份「验收时的反查清单」:每一行都对应一个能被观察到的现象,而不是一个抽象名词。测试同事报问题时说的是现象,你按现象查表,比从清单第一项开始逐项回忆快得多。

一句话原则:凡是「跨应用必须唯一」的标识(包名、authorities、scheme、推送登记项、开放平台登记项),都要跟包名一起成为「另一套」;凡是「应用内部自己的东西」(数据、登录态、缓存),都不用管,系统已经替你分开了。

四、这句话该怎么说:需求、附件与历史回填的三个技巧

有了清单,接下来是把它变成一句 AI 能执行的话。工具在详情页中间有一个输入框,写字的地方就是这里;点「立刻修改」之后,这段需求原文会被写进项目的修改历史(history.ini),同时送进右侧那扇被吸附的 AI 窗口执行。发送出去的文本不只是你的原话:工具会自动在它后面补上附件说明与一段固定的环境说明(让 AI 把工作目录切到本项目目录下改、改完在项目目录里留一个标志文件、不要在 AI 窗口里打包),这段环境说明不会写进历史,所以你在历史里看到的永远是你自己写的那句话,干干净净。

由此得到第一个技巧:把清单写进原话,别指望 AI 替你猜项目决策。文档化的写法是——「做成可与正式版共存的内测版:① 包名加 .beta 后缀;② 应用名改成『巡检打卡 内测版』;③ provider 的 authorities 统一加 .beta 后缀;④ 渠道走测试渠道;⑤ 其余功能与正式版完全一致,不要动界面。」这样一句话包含了「要什么、边界在哪、怎么算成功」,比「帮我做个内测版」可靠得多。

第二个技巧:能放进附件的就不要靠描述。新图标、要替换的文案、必须保持原样的渠道配置文件,都可以通过「选择附件」一次选进来,并给每个文件写一句用途(这里的校验是两道:文件本身现在能不能用 —— 存在、不是目录、不是 0 字节、能读出来;以及用途说明不少于 10 个字)。工具会把附件拼成「序号. 文件路径 —— 用途说明」的形式附在需求后面发给 AI。为什么要卡住 10 个字?因为只说一个路径,AI 只能猜你拿它干什么;写下「应用图标换成这个文件」和「把这张图放进启动页」,是两件完全不同的事。

第三个技巧:历史不是日志,是配方。每条历史记录显示为「#序号 + 时间 + 需求原文」,整条完整显示、不截断,右侧有一个「选择」按钮,一点就把那条原话填回输入框 —— 这就是「照上次那条再改一遍」。做共存改造时,第一套包(比如内测版)改完之后,第二套包(比如另一条产品线)可以直接把同一条需求选回来改,然后在输入框里改掉那几个差异点(包名后缀、应用名)。一致性天然就有了。

话术库能帮上什么忙

如果你不确定一句话该怎么组织,可以先去话术库看看:那里有六大分类(界面美化 / 弹窗引流 / 去除限制 / 常规修改 / 混淆去毒 / 插件添加)的成型指令,每条都把「要做什么 / 细节要求 / 参数参考 / 范围 / 验收」写全了。共存改造通常会从「常规修改」里挑一条打底(比如应用名称与图标替换那条),点「选择」填进输入框,再把你项目的差异点补上去。话术内容来自程序目录下的 Resources\话术库.xml,这个文件是可以手改的 —— 把自己的「共存改造模板」写进去,点一下刷新就能用。

再补一个常被忽略的操作:「去打包」和「立刻修改」是两条路。「立刻修改」是把需求发给 AI 去改工程;「去打包」则是跳过 AI,直接拿当前项目的工程去回编、对齐、签名、校验。所以当工程已经改好、你只是想再出一版包(或者上一轮打包时设备没连上、现在想重来一次),用「去打包」比再发一遍需求更快,也不会往历史里多加一条记录。共存改造这种「同一套工程反复出包验证」的场景,用到它的次数会非常多。

需求输入与附件示意
把清单写成原话、把素材放进附件、把历史当配方,是三件事共同组成的一套用法

五、项目侧的原理:一个项目一个 8 位目录,两套包互不污染

共存改造是典型的「要维护两套东西」,所以工具在项目这一层的设计,几乎就是为这种场景准备的。每个项目在项目目录下有一个8 位随机字符串目录(小写字母 + 数字),同名的概率极低,程序还会先检查目录是否已存在再创建。这个目录就是这一套包的全部家当:

  • config.ini —— 项目配置:项目名、创建日期、工作目录、图标文件名、应用名、包名、版本名与版本号、最低与目标 SDK、启动页组件名、原始源文件路径。程序自动生成,也可以手改。
  • source.apk —— 导入时拷进来的原始包副本。它的意义是「一张干净的原点」:不管后面改了多少轮、改坏哪一步,源包始终没被动过。
  • apktool\ —— 反编译出来的工程(清单、资源、smali 都在里面),AI 真正动手的就是这里;同一个目录下还有 apktool.log,反编译出问题时翻它。
  • history.ini —— 修改历史,按「记录1、记录2……」递增,每条只有日期和你写的需求原话。

把这套结构套到共存场景上,结论很直接:正式版一个项目、内测版另一个项目。两个项目各有一份 source.apk、各有一棵反编译工程、各有一串历史记录,改坏任何一个都不会碰到另一个。而且这里有一个很贴心的顺序设计:建项目时是先落地配置、图标与源包副本,再去做反编译 —— 所以反编译失败也不会让项目本身作废,配置、图标、源包都还在,程序会告诉你失败原因并给日志路径,你修工具链或者换包都可以,项目不用重建。

另外两个细节对「两套包并行」很实用。第一,项目列表读的是磁盘上的真实目录,带搜索和刷新 —— 正式版项目与内测版项目并排出现,用项目名区分(建议在项目名里就写上「正式」「内测」,比如「巡检打卡-正式」「巡检打卡-内测」)。第二,删除项目有防呆:只允许删项目根目录的直接子目录,就算配置文件里的路径被人改坏了,也不会误删到别处去。这条规则平时感觉不到,但一旦你要清理一堆过期变体,它就是最后一道安全网。

想随时掌握「两套包一共占了多少、改过多少次」,用户中心那页有现成的统计:项目数量、修改总次数、项目目录占用空间、所在磁盘剩余空间。这些数字是从磁盘上真实读出来的(读项目列表、逐个读历史记录、递归算目录大小),算的时候在后台线程跑,不卡界面。对做变体的人来说,它最大的用处是提醒你什么时候该清理:反编译工程加上原始包副本,一个项目的体积并不小,并行维护三四个变体之后,占用会明显涨起来;清理的规矩也很简单 —— 源包(source.apk)留着,随时可以从它重新来过,过期的中间产物不心疼。

工作目录落在哪、工具有没有备齐

项目目录建在工作目录根目录下,而工作目录是程序启动时自动挑盘的:依次尝试 D、E、F、G,取第一个能读写、且剩余空间不少于 1GB 的盘,拼成 <盘符>:\AiApkEditor,都不行才退回 C 盘(系统盘权限限制多,所以放最后)。根目录下约定两个子目录:tools(java、aapt、apktool、7z、zipalign、apksigner 这些工具,程序会自动递归搜索,不用登记)与 Project(项目)。如果你发现自己所有项目都在 D 盘而不是习惯的 C 盘,原因就在这里。换盘、换工具链之后,去「参数设置」页做一次工具链体检,aapt / java / apktool / zipalign / apksigner 会逐个报是否就绪并给出完整路径 —— 排查「改完了打不出来」这类问题,先看这一页比翻日志快。

项目目录结构示意
一个项目一个随机目录:配置、原始包副本、反编译工程与修改历史各就各位

六、两个自家实例:内测版共存与双版本并行

下面两个例子都来自我们自己团队。按「以前怎么做 / 现在一句话怎么做 / 改完怎么验证」三步展开,重点看清单是怎么落到一次操作里的。

实例一:自家「巡检打卡」应用做一个能和正式版共存的内测版。

以前怎么做:这是一条很长的流水线。先在反编译工程里改包声明,然后要靠搜索把代码与资源里散落的相关引用挨个找出来;改到 provider 的时候撞了车 —— 安装器直接拒绝,报的是一个跟包名毫无关系字面的冲突错误,排查半天才想到是 authorities 重复;把它改掉装上了,结果内测版里「拍照上传巡检照片」的分享链路坏掉,原因是 authorities 改了、代码里另一处还是旧值;最后发现测试同事手机上两个图标长得一模一样,名字也都叫「巡检打卡」,点错了好几次。

现在一句话怎么做:把正式版导入建项目(项目名写成「巡检打卡-正式」),同一个包再导入一次建第二个项目(「巡检打卡-内测」),在内测项目里写:

把这个包改成可与正式版共存的内测版:

1. 包名加 .beta 后缀;

2. 应用名改成「巡检打卡 内测版」,图标换成附件里的内测图标;

3. provider 的 authorities 统一加 .beta 后缀,确保全局唯一;

4. 渠道与上报改成测试渠道;

5. 其余界面与功能保持与正式版完全一致。

把内测图标通过「选择附件」加进来,用途写清楚(比如「应用图标换成这个文件,各密度一起替换」),点「立刻修改」。AI 改完之后会在项目目录里留下标志文件,主窗口那边每 2 秒轮询一次,读到就自动弹出打包窗口,按回编、对齐、签名、校验四步跑完;勾上「打包后自动运行」,包装到设备上并自动拉起。整套动作里唯一需要你盯的,就是最后设备上的画面。

改完怎么验证:四个动作就够 —— ① 桌面出现两个图标、名字不一样;② 打开内测版,确认渠道与上报走的是测试环境;③ 在内测版里走一次拍照上传(这条链路依赖 authorities,是最容易坏的地方);④ 回到正式版看数据还在、功能没变。工具这边在装机后会用系统命令复核前台应用是不是它,避免「装上了但没起来,以为改失败」的误判。

实例二:自家「记账助手」双版本并行迭代。

以前怎么做:正式版继续小步修 bug,同时要出一版带新版报表的内测包。两套东西并行的时候最容易出的事不是改错代码,而是「拿错包」:桌面上的产物名字都叫 signed.apk,测完一圈才发现装的是上一轮的包。为了解决这个,只能在文件名和文件夹上做人工约定,约定一多就没人在遵守了。

现在一句话怎么做:两个项目分开建,各自迭代。第一轮在内测项目里写需求(「把报表页的汇总卡片改成三个指标卡,数据来源不变,先把布局做出来」),点「立刻修改」;出包装机看效果。第二轮如果只是微调,直接去详情页的历史列表里点那条记录的「选择」,原话回填进输入框,改掉要变的部分再发一次 —— 这就是「照上次那条再改一遍」。正式版那边完全不受影响,它的项目目录、源包副本和历史记录都在自己那 8 位目录里。

改完怎么验证:打包跑完最后一步的校验会打印出签名证书信息,这一行就是「确实签上了」的凭据(前三步只看退出码,签名到底成没成要校验说了算);产物在项目目录的 build 子目录里依次留下未签名、已对齐、已签名三个中间件,全过程写进打包日志 pack.log。装机之后,正式版与内测版各升各的,互不影响。「保存 APK」的默认文件名是「应用名_版本号_signed.apk」,两个项目导出来的包名天然不同,也就不会再有人拿错包了。

双项目并行示意
两套包 = 两个项目目录;各自的源包、工程与历史互不相干

两个实例的共同点,是「共存改造的价值不在改的难度,而在覆盖面的完整性」。清单有八项,任何一项漏掉,得到的都是一个「看起来装上了、用起来哪里不对」的包。把清单写成一句话、交给工具执行,再按清单逐项验证 —— 这就是从此类改造里省下时间的方式。如果你更习惯手工改,同一套思路也仍然成立:先装得上,再修功能,最后理数据。

七、用户评价:他们是怎么做共存改造的

「以前最坑的就是 authorities 撞车,装不上还看不懂报错。现在需求里直接写上『authorities 一起加后缀』,一次就过。」

—— 老周 · 小型工作室安卓开发

「我们做企业内测的,正式包和测试包必须并存。现在两个项目各占一个目录,历史里只留我们自己的原话,谁改过什么一目了然。」

—— 阿凯 · 企业 IT 运维

「最实用的是『选择』把上次那条需求填回来。给三条产品线各做一个变体,其实就差包名和一个名字,改两下就好了。」

—— 小林 · 高校实验室助研

「分享回调失效那次我查了一下午,最后发现是开放平台那边登记的还是老包名。清单第 4 条现在被我贴在便签上了。」

—— 王工 · 自动化设备厂商软件组

「内测包的渠道我一开始没管,结果看板上多了一堆来路不明的数据。后来按文章思路把上报切到测试环境,才干净下来。」

—— 周舟 · 个人开发者

使用反馈汇总(来自内部试用与技术交流群的问卷整理)

  • 做共存改造的人里,约 七成 卡在过「装不上」这一步,其中绝大多数是标识冲突,而不是包名本身;
  • 约 六成 的人在第二次做同类改造时开始复用历史记录里的那条需求,而不是重新组织语言;
  • 反馈里被提到最多的两个连带项是「桌面上分不清哪个是内测版」和「分享 / 登录回调失效」;
  • 超过 八成 的试用者表示,按「先装得上、再修功能、最后理数据」的顺序推进,返工明显减少。

合规提醒:本工具面向自有版权或已获得授权的应用,适用于学习研究、企业内测、自有应用迭代等合法场景。请勿用于破解他人付费应用、绕过安全机制或未获授权的分发。文中所有实例均基于自有应用与自有素材。

八、结语:共存 = 一套唯一标识 + 两个互不相同的项目

把这篇收成一句话:让两套包共存,就是让所有「跨应用唯一」的标识成为两套,同时让系统替你分开的部分(数据、权限、图标)自然分开。原理只有一条(包名定身份、签名定更新),清单只有八项,剩下的都是执行与验证。

真正让这件事变轻松的,是工具把「反编译工程 + 原始包副本 + 只留原话的历史」这三样东西摆在你面前:改什么、改到哪、上一轮说了什么,都查得到、回得去。于是你打开安卓修改大师智改工坊时的体验,就是那句口号描述的样子:只需说话,就能让应用变成你想要的样子 —— 一句中文需求,左边写、右边改,改完自动回编、对齐、签名、校验,再一键装到手机上看两个图标并排躺着。

产品介绍页与下载入口:https://www.apkeditor.cn/ai-version.aspx(官网 www.apkeditor.cn)。

只需说话,就能让应用变成你想要的样子

Windows 桌面端 · 拖入 APK · 中文写需求 · 自动回编 / 对齐 / 签名 / 校验 · 一键装机看效果

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

环境要求:Windows 桌面系统;首次使用建议在「参数设置」里做一次工具链体检