只需说话,就能让应用变成你想要的样子
安卓修改大师智改工坊 · 为什么加一张图,会让另一个界面变样
资源 ID 的 0x7f 前缀:改资源时最容易撞的那堵墙
如果你用过反编译工具,一定见过一串这样的东西:0x7f0f0012。它出现在布局文件里、出现在代码里、出现在资源表的每一行。大多数人对它的态度是「看不懂,跳过」。但改包时最容易撞的那堵墙,恰好就在这串数字里。
这篇讲清楚四件事:这串数字是怎么编出来的、为什么开头总是 0x7f、改资源时哪几个动作会产生新编号、以及编号撞了会有什么后果。最后一节会给出一个自己就能做的实验。
一、先看一个具体的编号
把 0x7f0f0012 拆开看,它是四段,每段一个字节。
第一段是 0x7f,它表示「这个资源来自当前应用自己的包」。第二段是 0x0f,它表示「这是哪一类资源」——字符串、图片、布局、颜色,各占一个编号。第三段和第四段合起来是 0x0012,表示「在这一类里排第几」。
所以这个编号读出来是:本应用的、第 15 类资源里的、第 18 个。你不需要记住 0x0f 是哪一类,你只需要知道「三段各管一件事」,遇到问题时就知道该看哪一段。
这个结构是固定的,所有安卓应用都一样。它不是一个随机的数字,而是一个地址:告诉系统去哪里找这个资源。理解了「它是地址」,后面所有关于冲突、关于新增、关于删除的规矩,就都能推出来。
一个资源 ID 的构成
0x7f0f0012 的四段:
0x7f | 0f | 00 | 12
└─┬─┘ └┬┘ └──┬──┘
│ │ └─ 条目序号:这一类里的第 18 个
│ └──────── 类型编号:第 15 类(比如字符串、图片、布局)
└────────────── 包头:0x7f 表示「本应用自己的资源」
二、这个编号是谁编的
不是你编的,也不是应用方手写的。它是编译时自动生成的。
写代码的人给资源起名字,比如「欢迎语」叫 welcome_text、「图标」叫 ic_launcher。这些名字对人友好,对机器不友好——机器要在运行时快速找到它,用字符串去查太慢。所以在编译的时候,工具会给每个名字分配一个数字编号,把「名字到编号」的映射写进资源表,之后代码里用的都是编号。
分配的规则很简单:按类型分组,组内按出现顺序编号。所以同一个资源在不同次编译里,拿到的编号可能不一样——只要它前后的资源有增减,它的序号就会变。
这一点很关键:编号不是永久身份,它是「这一次编译里的排位」。理解了这一点,你就会明白为什么改包时新增或删除资源需要小心:你在改变排位,而排位一变,所有引用它的地方都要跟着变。
三、为什么开头总是 0x7f
这一段的取值有约定:0x01 到 0x7f 表示「应用自己的资源」,0x7f 是最常见的一个;0x01 通常留给系统框架自己的资源。
为什么应用都用 0x7f?因为它是一个「安全的上界」——它足够大,大到不会和系统预留的区间冲突;又足够小,小到不会溢出。所以绝大多数打包工具都默认用它。
这个设计的用意是「隔离」:系统资源和应用资源在同一套编号体系里,但用不同的包头区分。系统升级时可以换掉自己的资源,不会碰到应用的;应用更新时可以换掉自己的,也不会碰到系统的。
所以看到 0x7f,你就知道这是「应用自己的东西」,需要去这个应用的资源表里找。看到 0x01,那是系统的东西,不在包里。这个判断在排查「某个资源到底存不存在」时很有用。
提示:偶尔会看到 0x7e 开头的编号,那通常是某些特殊构建方式下的结果,含义仍是「应用自己的资源」。不要因为不是 0x7f 就以为坏了。
它不是名字,是一个地址
四、类型段里到底有什么
中间那一段(例子里的 0x0f)是类型编号。它决定了「这个资源是什么东西」,也决定了它存在哪里。
字符串、颜色、尺寸这些「值」存在资源表里;图片、布局、音频这些「文件」存在资源目录里,表里只记它们的位置。所以同一个编号体系下,不同的类型背后是完全不同的存储方式。这也是为什么改一张图和改一句文案,风险不一样。
类型的编号顺序也不是固定的,它取决于这个应用定义了哪些类型、按什么顺序定义。所以你不能假设「0x0f 一定是字符串」——在另一个应用里,0x0f 可能是布局。要确认类型,得去看资源表,不能靠记。
这一点带来的实际影响是:你不能靠「记住某个编号」来做判断。同一个编号在不同应用里含义不同,在同一个应用的不同版本里也可能不同。唯一可靠的办法是「每次都查表」。
五、一个编号背后跟着什么
编号本身只是一个钥匙。真正的内容在表里的对应条目上,而那个条目比想象中复杂。
一个字符串资源的条目,至少要记录:默认值是什么、在哪些语言下有不同值、每个值存在哪里。一个图片资源的条目,要记录:在哪些密度目录下有文件、每份的尺寸是多少。一个布局资源的条目,要记录:文件在哪、有没有针对横屏或大屏的另一份。
所以「改一个资源」这个动作,实际可能牵动的不止一处。改一句文案,如果这个应用支持五种语言,那就是五处;换一张图,如果这个应用有六个密度目录,那就是六处。而它们的编号是同一个。
这就是为什么「改了没生效」经常发生:你改了其中一处,运行时读的是另一处。而编号相同这件事,会让问题显得很奇怪——明明是同一个资源,为什么改这里没用?答案就在「一个编号对应多份内容」这个结构里。
六、编号在包里是怎么被引用的
编号会被写进很多地方,这是「撞编号」会引发连锁反应的原因。
第一处是代码。代码里不会写「welcome_text」,而是写一个编号常量。第二处是布局文件。布局里引用一个字符串、一个颜色、一张图,编译之后都变成编号。第三处是资源表自己——表里有些条目会引用另一些条目,比如一个样式引用了几个颜色。
这三处引用构成了一个网。你动了网上的一个节点,所有连着它的地方都会受影响。而这张网有多大,从外面看不出来。
所以在改包时,一个看起来很小的动作——加一个资源、删一个资源——可能会让整张网重排。而重排的后果,往往不是在打包时报错,而是在运行时某个你想不到的地方出问题。
六之二、编号为什么不能直接用名字代替
有人会问:既然编号这么麻烦,为什么不用名字直接定位?比如代码里就写 welcome_text,运行时按名字去表里查。
因为慢。名字是一串字符,比较两串字符要逐字比,还要处理哈希冲突、大小写、编码。而编号是一个整数,比较它是一条指令的事。一个界面要查几百次,用名字查和用整数查,差着一个数量级。
而且名字会在编译后消失。为了减小体积,编译工具会把名字压成最短的形式,甚至完全去掉——因为运行时根本不需要名字。你在反编译工具里能看到的那些名字,是从表里还原出来的,不是包里真的存着。
所以「名字」只存在于开发阶段和你的视角里;「编号」才是包里的真实身份。理解这个分层,你就不会再问「为什么不能按名字改」了。
七、撞编号到底会怎样
「撞」这个词容易让人以为是「两个资源编号相同」,其实更常见的情况是「编号的指向变了」。
想象一下:原本 0x7f0f0012 指向「欢迎语」。你在它前面插了一个新的字符串资源,排位一变,原来的欢迎语变成了 0x7f0f0013,而 0x7f0f0012 现在指向你新插的那个。这时候如果代码还是按旧编号去读,读到的就是你新插的那句话。
表现是什么?界面上一句文案变成了另一句,或者一个按钮的文字变成了一个看不懂的词。它不崩溃、不报错,只是「内容错了」。这类问题最难查,因为所有东西看起来都正常,只有文字不对。
所以「撞编号」的本质不是「两个资源抢一个号」,而是「引用和内容对不上了」。引用是编译时写死的,内容是运行时按编号取的,中间的桥就是编号。桥一挪,两边就对不上。
注意:判断方法:如果改完之后「某些文字变成别的文字」,而且这些文字原本都存在,那就高度怀疑编号错位。这时候不要改文案,要去比对改前改后的编号分配。
八、三种「撞」法
按发生的时机分,有三种。
第一种是新增导致的位移。你在某个类型里加了一个资源,排在它后面的所有资源编号都往后挪一位。这是最常见的一种,也是最容易被忽略的——因为你「只是加了一张图」,没觉得自己动了文字。
第二种是删除导致的断裂。你删了一个资源,后面的往前挪,同时所有引用「被删的那个」的地方都变成了悬空引用。悬空引用的后果比位移严重:位移是「读错内容」,断裂是「读不到内容」,后者通常直接崩溃。
第三种是合并导致的冲突。你把两个包的内容合成一个(比如把两个应用的资源并到一起),两边的编号体系撞在一起,同一个编号在两边指向不同的东西。这种最少见,但只要发生,几乎必然出问题。
| 方式 | 发生了什么 | 典型表现 | 概率 |
| 新增 | 后面的编号整体后移 | 文案变成另一句、图变成另一张 | 常见 |
| 删除 | 后面前移,且留下悬空引用 | 闪退、界面缺块 | 较常见 |
| 合并 | 两套编号撞在一起 | 大面积错乱 | 少见但严重 |
九、加一个资源,为什么会动到别人
这一点最反直觉:我只是加了一张图,跟字符串有什么关系?
关系在于编号是「分类别、按顺序」的。同一个类型内部的顺序会变,但不同类型的编号是独立的。所以加一张图,只会让「图片」这个类型里排在它后面的图片往后挪,不会动字符串。
那为什么实际会出问题?因为很多资源是「跨类型引用」的。一个布局引用了图片、一个样式引用了颜色、一个菜单引用了字符串。这些引用在编译之后都变成了编号。你动了图片的编号,引用它的布局就要跟着更新——如果更新了,没事;如果没更新,就是错位。
而「有没有更新」取决于你用的工具。标准编译流程会重新生成所有引用,所以是安全的;手工往包里塞文件则不会更新任何引用,所以是危险的。这就把问题从「编号会不会乱」变成了「你用的方式会不会重算引用」。
十、删一个资源,为什么会留下悬空
删除比新增危险,因为删除会留下「指向不存在的东西」的引用。
假设一个布局里引用了某张背景图。你把这张图删了,但布局里那一行引用还在。编译的时候,工具通常会报错——因为它找不到这个资源。这是好事,错误在打包阶段就暴露了。
但如果工具没报错(比如它容忍了缺失,或者你绕过编译直接改了包),那这个引用就变成了悬空。运行时读到这里,拿不到内容,最常见的后果是崩溃;有些实现会退回到一个空的默认值,表现是「背景变成透明」或者「图标不见了」。
所以「删资源」这个动作的安全前提是:确认没有任何地方引用它。确认的方法不是凭印象,是搜一遍。搜布局、搜代码、搜资源表里的交叉引用。这一步花十分钟,能省掉一次崩溃排查。
编号是一张网,动一处牵连一片
十一、案例一:加了一张图,另一个界面串了
这是一个很典型的「改动和故障看起来毫无关系」的案例。
需求是给「我的」页面加一个会员标识的小图标。操作是:把图标放进图片目录,然后在布局里引用它。改完出包,装上看,图标正常显示。看起来完美。
但用户反馈:「首页的轮播图变成另一张了」。一查,果然,首页轮播的第一张图变成了会员标识。
原因就在编号上。这个团队是手工改包的:他们解包、往图片目录里放文件、回编,但没有让工具重算资源索引。回编工具在重新生成索引时,把新加的图排在了某个位置,导致它后面所有图片的编号整体后移一位。而首页轮播的布局里写的是「第 N 号图」,于是它读到了后移之后的那一张。
为什么「我的」页面显示正常?因为它的布局是这次新写的,引用的是新编号;而首页的布局是老的,引用的是老编号。同一个包里,两套编号并存,一套新一套旧,于是只有老的那部分出错。
修法很简单:不要手工塞文件,改用标准流程重新出包,让所有引用一起重算。但这个案例的教训值得记住——「我改的地方没问题」和「整个包没问题」是两件事。验证的时候,不能只看你改的那一页。
十二、案例二:删了一个资源,编译过了但闪退
第二个案例的坑更深,因为它在编译阶段没有报错。
一个应用里有三张「季节主题」的背景图,客户说夏天那张不用了,删掉。操作的人删了文件,也删了资源表里的那一行,然后回编。回编成功,签名成功,装上了。
点开应用,进首页正常;点进「活动」页,闪退。
查日志,报的是一个资源找不到的错。看「活动」页的布局,里面引用了那张被删的图——但它不是直接引用,是套在一个「主题」里引用的。删的时候只搜了直接引用,没搜到,就以为安全了。
这就是「间接引用」的坑:资源可以被另一层资源引用,而那一层再被布局引用。你要搜的不是一层,是整条链。
正确的做法是:删之前,先用这个资源的编号在整个包里搜一遍,包括资源表本身。如果只在定义处出现一次,说明没人用,可以删;如果出现在别处,那就是有人引用,得先处理引用。
这个案例说明:编译通过不等于引用干净。编译器只检查「你写的东西对不对」,不检查「你删的东西还有没有人用」——尤其当引用是间接的时候。
十三、怎么查一个编号对应什么
方法有三种,从粗到细。
第一种:看资源表。把它反编译成可读文本,会得到一张列表,每行是「编号、类型、名字、值」。这是最直接的办法,适合确认「这个编号到底是什么」。
第二种:在包里搜这个编号的十六进制写法。如果它出现在某个布局或代码文件里,说明那里引用了它。这适合查「谁在用这个资源」。
第三种:从名字反查编号。你知道资源叫 welcome_text,想知道它的编号是多少,就在资源表里搜这个名字。这适合在改动之前先记下编号,改完再对比。
三种方法合起来,能回答改包时最常问的三个问题:这是什么、谁在用、改了会动到谁。而这三个问题,恰好是「改之前想清楚」的全部内容。
十四、编号在代码里长什么样
在反编译出来的代码里,编号不会写成 0x7f0f0012 这种形式,而是写成一个常量引用。
它通常长这样:一个常量池里的条目,值是 2131623954 这样的十进制数。你把它转成十六进制,就是 0x7f0f0012。所以看到一大串十进制数字,不要以为那是随机数,它很可能就是一个资源编号。
知道这一点有什么用?当你需要在代码里确认「这一处读的是哪个资源」,就把那个十进制数转成十六进制,再去资源表里对。这个动作在排查「文案不对」「图不对」时非常有效。
还有一层:如果这个应用做过资源名混淆,那资源表里的名字会变成 a、b、c 这样的短名,但编号结构不变。这时候你没法靠名字找,只能靠编号。所以「会读编号」这件事,在混淆过的包上是唯一的路。
十五、为什么不能手改编号
有人会想:既然编号会乱,那我手工把它改回去不就行了?不行,而且很危险。
因为编号不是孤立存在的。它被写在代码里、布局里、资源表里的交叉引用里。你改了一处,其他几处不会跟着变,你就制造了一批新的错位。而且这种错位是你亲手造的,比工具造成的更难查——因为它是「有意的改动」,你会下意识觉得它是对的。
更重要的是:编号不是给人读的,是给机器定位的。手工改它,相当于在一本书里手改页码,但目录、索引、交叉引用都还是老页码。书还能翻,但找东西全乱。
正确的做法只有一个:不要动编号,让工具重算。你要改的是「内容」和「名字」,编号是它们的结果。想让结果对,就改输入,别改输出。
要点:这条原则可以推广:凡是「自动生成的东西」,都不要手工改。版本号里的构建号、签名里的指纹、索引里的偏移——它们都是结果。改输入,让结果重新生成。
十六、改包时哪几个动作会产生新编号
不是所有改动都会动编号。分清哪些会、哪些不会,你就能判断一次改动要不要特别小心。
会动编号的:新增一个资源、删除一个资源、改一个资源的名字、把资源从一个目录挪到另一个目录、改变资源被编译的顺序。这五个动作都会让资源表重排。
不会动编号的:改一句文案的内容、换一张图的内容(文件名不变)、改一个颜色的值、改一个尺寸的数字。这四个动作只改内容,不改结构。
所以有一个很实用的判断:你改的是「值」还是「条目」。改值,安全;改条目(增删改名),要小心。而绝大多数改包需求——换图、换文案、换颜色、改字号——都是改值,这也是为什么大部分改包是安全的。
十七、新增资源的正确姿势
如果确实要新增,有四步。
第一步:先把文件放进目录,命名遵守这个应用已有的规则。不要用中文名、不要用空格、不要用特殊符号。名字不规范会导致它在资源表里的排位不稳定。
第二步:用标准流程重新出包,让工具重算索引。不要手工改资源表、不要手工塞进 zip。这一步是全部安全性的来源。
第三步:记录新增前后的编号分配。具体做法是出包前后各导一次资源列表,比对差异。如果差异只有「多了新条目」,说明没问题;如果老条目的编号也变了,那就要检查引用。
第四步:装机之后,不只验证新加的东西,也要验证「最老的几个页面」。因为错位最容易发生在老页面上——它们的引用是按老编号写的。
提示:一个经验:如果新增之后,你发现某个老页面的文字或图片变了,不要去改那个老页面。问题不在它,在编号。正确的动作是回退,换一种方式重新新增(比如把新资源追加到类别末尾,而不是插在中间)。
十八、删除资源的正确姿势
删除的风险比新增高,所以步骤更多。
第一步:找到这个资源的编号。第二步:用编号在整个包里搜一遍,包括资源表本身,看有几处引用。第三步:如果有引用,先处理引用——把引用改成别的资源,或者把引用它的那段逻辑去掉。第四步:确认零引用之后,再删。第五步:重新出包,装机,把用到它的所有页面走一遍。
这五步里,第二步最容易做漏。因为「搜编号」这件事,需要你把十进制转十六进制、需要你搜整个包而不只是搜资源目录。漏了这一步,就会变成前一个案例里的样子:编译过了,某个页面闪退。
还有一个更省事的判断:如果这个资源你不确定有没有人用,就别删。留着一个没人用的资源,代价是几十 K 的体积;删错一个在用的资源,代价是一次线上崩溃。这笔账很好算。
十九、替换资源的正确姿势
替换是改包里最常用的动作,也是最安全的一种——前提是你替换的方式对。
正确的替换是:文件名不变、目录不变、格式不变,只换内容。这样资源表里的条目、编号、引用全都不用变,工具只需要把新内容放进去。整个过程不涉及任何结构改动。
不正确的替换有三种。第一种:改了文件名。这等于「删一个、加一个」,会动编号。第二种:改了目录。比如把图从高密度目录挪到中密度,等于改变了它的配置匹配,行为会变。第三种:改了格式。把 png 换成 webp,虽然内容一样,但有些老系统读不了。
所以「替换」这个词,严格来说是「同名同路径同格式,只换内容」。做到这三点,替换就是零风险的;做不到,它就变成了新增加删除,风险成倍上升。
同名同路径同格式,只换内容
二十、编号稳定,为什么是一种资产
一个长期维护的应用,它的资源编号在多次版本之间通常保持相对稳定。这不是巧合,是构建工具在尽量「少变动」——因为变动意味着风险。
这种稳定性是一种资产。它意味着:改一个小地方,不会牵连一大片;意味着你可以放心地只验证改动的那一处;意味着两个人的改动不会互相干扰。
而破坏这种稳定性的,往往是「聪明的优化」:为了省体积而重排资源、为了统一命名而批量改名、为了清理而删掉「看起来没人用」的东西。这些动作单个看都有道理,合起来就把资产消耗掉了。
所以对改包的人来说,有一条隐含的规矩:不要为了「整洁」去动结构。你想改的是内容,那就只改内容。结构上的整洁是应用方的事,你动了它,风险归你。
二十一、工具是怎么保证编号不乱的
标准出包流程里,编号是由编译环节统一分配的。它的做法是:把所有资源按类别收集起来,排好序,一次性分配编号,然后把所有引用一起写进去。因为「分配」和「写引用」是同一次操作的两半,所以不会出现「引用是老的、编号是新的」这种情况。
手工改包之所以危险,就是因为它把这两半拆开了:你改了文件(相当于改了要分配的东西),但没有重写引用(另一半没做)。两边不同步,错位就产生了。
安卓修改大师智改工坊的做法是:你只表达「要改成什么」,它把你的意图落到具体文件上,然后走完整的编译流程重新出包。也就是说,「分配编号」和「写引用」这两半,永远在同一次操作里完成,中间没有让人手工介入的缝隙。
这就是为什么用工具改包比手工改包稳:不是因为工具更聪明,是因为它不允许「只做一半」这种状态存在。
要点:一个判断标准:如果一个流程允许你「改完文件直接打包」,那它就有错位的风险;如果它要求你「改完必须重新编译」,那它就是安全的。区别只在于有没有重算引用这一步。
二十二、多语言和多密度,让这件事更复杂
一个只支持中文、只有一套图的简单应用,编号问题很少见。但只要加上多语言和多密度,复杂度就上来了。
多语言意味着同一个字符串资源有多份内容,分属不同语言。它们的编号是同一个,内容按语言选。所以「改一句文案」实际是「改这个编号下的一组内容」,你改了其中一份,其他语言的还是旧的。
多密度意味着同一张图有多份文件,分属不同密度目录。编号也是同一个。所以「换一张图」实际是「换这个编号下的一组文件」,你换了其中一份,其他密度的还是旧的。
这两件事叠加起来,就是「改了没生效」的最常见原因。而它们的根源是同一个:一个编号对应多份内容,你只改了其中一份。理解这一点,你在改文案和换图时就会习惯性地问一句:这个资源有几份?
二十三、资源名被混淆过的包,怎么处理
有些应用会把资源名混淆成 a、b、c 这样的短名,目的是减小体积、增加逆向难度。这类包改起来更麻烦,但不是不能改。
麻烦在于:你没法靠名字找东西了。原来搜 welcome_text 就能找到,现在只能靠编号或者靠内容。所以处理这类包,第一步是「建立名字到编号的映射」——把资源表导出来,看看每个编号对应什么内容。
有了映射之后,改法和普通包一样:找到要改的那一条,改内容,重新出包。要注意的是:不要试图把名字改回有意义的名字,那会动结构,风险远大于收益。
这类包还有一个特点:它的编号往往比普通包更「紧凑」,因为混淆过程会重排。所以它的编号稳定性更差,你改一处,牵连的范围可能更大。处理这类包,验证要比平时更仔细。
二十四、为什么有的包编号看起来很乱
你可能会遇到编号不连续、跳号的包。这不一定是坏了。
原因有几种。第一种:这个包被裁剪过,删掉了一些资源,编号留下了空洞。第二种:它是由多个模块合并而成,每个模块各占一段。第三种:它做过资源重排优化,为了把常用的资源排在前面。
这几种情况都正常。判断「有没有坏」的标准不是「编号连不连续」,而是「引用和编号对不对得上」。前者是外观,后者是实质。
所以看到跳号不要慌,去做一次「引用检查」:随便挑几个布局,看它引用的编号在资源表里存不存在、指向的是不是那个东西。都对得上,就说明这个包是健康的。
二十四之二、一次改动该验几个页面
编号错位的特点是「在你没看的地方出问题」,所以验证范围比验证深度更重要。
一个可用的规则是:改完之后,除了改的那一页,至少再走三个页面——首页、一个列表页、一个详情页。这三类页面覆盖了大部分「引用密集」的场景:首页通常引用最多的图和文案,列表页引用条目布局,详情页引用动态内容。
如果应用有「设置」页,也走一遍。设置页往往引用很多零散的字符串和小图标,是最容易被错位波及的地方。
这个规则不是万能的,但它把「只验证改动处」这个坏习惯,改成了「顺手多走三页」。多花两分钟,能挡住大部分静默错位。
二十五、五个常见误解
这一节列的说法,都是在实际交流里反复出现的。
误解一:编号是资源的一部分,改内容就得改编号
正好相反。编号是内容的地址,内容变了地址不用变。换一句文案,编号还是那个编号,只是它指向的内容换了。只有「增删条目」才会动编号,改「值」不会。
误解二:手改编号只要改全就行
「改全」这件事在实际操作里几乎做不到。编号会出现在代码常量、布局引用、资源表交叉引用、甚至某些缓存文件里。你以为改全了,其实总有一处漏掉。而漏掉的那一处,会在某个你想不到的界面上出问题。
误解三:编号撞了会立刻报错
大多数情况下不会。位移类的错位完全静默,只表现为「内容变成了另一个内容」。等你发现时,可能已经交付了。这就是为什么这类问题需要「主动比对编号」而不是「等它报错」。
误解四:只要不用代码就不会碰到编号
布局文件里全是编号。你在界面上看到的一句文案、一个颜色、一张图,在编译之后都是编号引用。所以「只改界面不动代码」照样会碰到它——这也是前面案例一的情形。
误解五:编号错了重启应用就好
不可能。编号是编译时写死在包里的,运行时不重新分配。重启、清缓存、重装同一个包,结果都一样。唯一的修法是重新出包。
二十六、给新手的四条
如果只记四句话,记这四句。
1
只改值,不改条目
换图、换文案、换颜色、改字号,都是改值,安全。增删改名会动编号,要小心。
2
改完要重新编译出包
不要手工塞文件、不要用压缩软件改包。重算引用这一步不能省。
3
验证要看老页面
新加的东西通常没问题,出问题的是引用老编号的老页面。
4
删之前先搜编号
整个包里搜一遍,包括资源表。搜不到再删,搜到就先处理引用。
二十七、一个十分钟就能做的实验
想亲手验证「编号会位移」这件事,有一个很简单的做法。
找一个你自己能改的包,先导出它的资源列表,记下某一句文案的编号。然后在这个类型的资源里插一个新条目(随便加一句没用的文案),重新出包。
再导一次列表,对比两次的编号。你会看到:你插入位置之后的那些条目,编号全部后移了一位。而引用它们的布局文件里,写的还是老编号。
这时候把包装上,去看那个引用了后移条目的页面。大概率你会发现它显示的是另一句话——就是你新插进去的那句。这个现象,就是「错位」最直观的样子。做完把包删掉,别留着。
提示:做这个实验的时候,一定要在副本上做。而且做完之后,用原始包重出一遍,确认自己理解了「位移」是怎么发生的。理解一次,比读十遍解释有用。
二十八、它和对齐、签名是什么关系
三件事看起来无关,其实是一条链上的。
资源表不能压(要能随机访问)→ 不能压就必须原样存 → 原样存才能被直接映射 → 映射要求起点对齐 → 对齐会改文件布局 → 布局一变签名就失效 → 所以对齐必须在签名之前。
这条链的起点是「资源要能被快速找到」,而「编号」正是那个「快速找到」的机制。所以编号体系、压缩方式、对齐要求、签名顺序,四件事其实在服务同一个目标:让资源在运行时能被瞬间取到。
理解这条链的好处是:你不再是记四条规矩,而是理解一个目标。以后遇到新的规矩,你能自己判断它是不是在服务这个目标,而不是死记。
二十九、三层结构,一句话记住
把这篇压缩成一句话:资源有三层——名字、编号、内容;名字给人看,编号给机器用,内容是最终结果。
三层之间是「翻译」关系,不是「等同」关系。改名字不影响编号(在标准流程里会重新分配,但那是重算,不是手改);改编号会破坏引用;改内容最安全。
所以改包时的正确姿势是:在「名字」这一层表达意图(把欢迎语改成这句),让工具去处理「编号」这一层,最后得到新的「内容」。你只碰第一层,中间那层交给流程。这就是「只需说话」在技术上的含义。
三十、为什么这个前缀值得记住
0x7f 这四位数,本身没什么神秘的。但它是一个入口:从这个入口进去,你能看到资源是怎么被组织、被引用、被定位的。
而「资源怎么被组织」这件事,几乎决定了改包的所有风险点:改文案为什么要看语言目录、换图为什么要看密度目录、加资源为什么会串页面、删资源为什么会闪退。这些问题的答案,全在编号体系里。
安卓修改大师智改工坊把这些都收进了流程:你说「把这句改成那句」,它去找对应的条目、处理所有语言副本、重算引用、重新出包。你不必知道 0x7f 是什么,也不会因为不知道而做错。
而当你哪天想弄明白「为什么改了没生效」,这篇里的三层结构就是答案:你可能只改了名字那一层看到的一份内容,而机器读的是编号那一层指向的另一份。只需说话,就能让应用变成你想要的样子——前提是那句话被正确地翻译成了编号和内容。官网 www.apkeditor.cn,产品介绍页 https://www.apkeditor.cn/ai-version.aspx。
资源 ID 不是一串随机数字,它是一个地址:0x7f 说明这是应用自己的资源,中间一段说明是哪一类,最后一段说明排第几。因为编号是「排位」,所以增删资源会让后面的编号整体位移;因为引用是编译时写死的,所以位移会让引用和内容对不上。这就是「加一张图,另一个页面变了」的全部原因。改值安全,改条目要小心——这条判断能挡掉大部分改包事故。
加图标把首页轮播搞乱那次,我查了两天。原来是编号位移。
—— 小郑 · 前端转移动
「改值还是改条目」这个判断太好用了,现在动手前先问自己一句。
—— 林工 · 应用二开
删资源前先搜编号,这步我以前从来不做,现在成了固定动作。
—— 陈默 · 客户端开发
十进制那串数原来是编号,这个我以前一直当它是乱码。
—— 阿泰 · 独立开发者
三层结构那句话我抄下来了:名字给人看,编号给机器用,内容是结果。
—— 王倩 · 外包团队
终于明白为什么改一句文案要改五个地方了,一个编号对应多份内容。
—— 老吴 · 技术负责人
www.apkeditor.cn
写技术文章最难的地方,是把「看起来无关的两件事」连起来。加图和组织页面,在直觉上是两件事;在编号体系里,它们是一件事。而把这种连接讲清楚,比多给十个结论有用。
所以这篇真正想留下的,不是 0x7f 这个数字,而是那个提问的习惯:这个规定在保护什么?答案找到之后,规矩就变成了道理。
合规提醒:本文所述操作仅适用于你拥有或已获得授权的应用。代他人修改应用前请取得书面授权,不得用于去除授权校验、绕过付费限制、冒充官方发布等用途;相关行为可能违反《著作权法》《计算机软件保护条例》与《网络安全法》。
名字给人看,编号给机器用。
安卓修改大师智改工坊把改包之后那一串动作收在同一个界面里:说一句话,改完自动回编、对齐、签名,还能装回手机看一眼再交付。官网是 www.apkeditor.cn,产品介绍页 https://www.apkeditor.cn/ai-version.aspx。
安卓修改大师智能修改 · 安卓版下载
安卓修改大师智改工坊 · 安卓版 · 引用关系自动重算,一句话就改
自动回编 · 对齐签名 · 真机预览 · 每处改动可追溯
立即下载智改工坊(AI 版)
手机 / 平板 / Windows 均可 · https://www.apkeditor.cn/ai-version.aspx