XmlClassGuard
- 混淆 xml 文件中用到的系统类,如 TextView/Button 等,用自定义 View 替代
XmlClassGuard 简介
XmlClassGuard
是一个可混淆 Android 4 大组件、自定义 View 等任意类的插件XmlClassGuard
可以看作是ProGuard
的一个补充,跟ProGuard
没有任何关系,也不会有任何冲突可快速更改
manifest
文件里的package
属性,并同步到其他文件中可快速移动 n 个目录到其他目录中,并同步到其他文件中
可查找
constraint_referenced_ids
属性的值,并自动添加到AabResGuard
的白名单中可查找
constraint_referenced_ids
属性的值,并自动添加到AndResGuard
的白名单中XmlClassGuard
最主要的功能是混淆 xml 文件用到的类,故取名为XmlClassGuard
,与AndResGuard、AabResGuard对应
有什么用?
弥补
ProGuard
不混淆 4 大组件等类问题增加 aab、apk 反编译的难度
极大降低 aab 包查重率,避免上架
Google Play
因查重率过高,导致下架或封号问题
关于第三点,有过上架Google Play
商店的同学应该知道,如果之前的包被下架或封号,想要同套代码再次上架,那 99%概率是再次封号,很大一部分原因就是以上说到的类未被混淆,很容易被 Google 断定为包重复,从而导致再次封号,因此,如果想要再次上架,就必须要更改四大组件、自定义 View 等的包名+类名
以降低查重率,然而,如果手动去完成这项任务,估计会累死一个程序员,于是乎,就有了XmlClassGuard
,通过插件去完成手工的活,一个任务便可搞定
原理
XmlClassGuard
不同于AndResGuard(apk 资源混淆)、AadResGuard(aab 资源混淆)
侵入打包流程的方案,XmlClassGuard
需要在打包前执行xmlClassGuard
任务,该任务会检索AndroidManifest.xml
及navigation、layout、xml
文件夹下的 xml 文件,找出 xml 文件中引用的类,如 4 大组件及自定义 View 等,更改其包名+类名
,并将更改后的内容同步到其他文件中,说直白点,就是在打包前,在本地更改包名+类名
警告警告⚠️
由于是在本地操作,任务执行是不可逆的,故务必做好代码备份,否则代码将很难还原
上手
1、在build.gradle(root project)
中配置
buildscript {
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
classpath "com.github.liujingxing:XmlClassGuard:1.2.6"
}
}
2、在 build.gradle(application)
中配置
apply plugin: "xml-class-guard"
//以下均为非必须
xmlClassGuard {
/*
* 是否查找约束布局的 constraint_referenced_ids 属性的值,并添加到 AabResGuard 的白名单中,
* 是的话,要求你在 XmlClassGuard 前依赖 AabResGuard 插件,默认 false
*/
findAabConstraintReferencedIds = false
/*
* 是否查找约束布局的 constraint_referenced_ids 属性的值,并添加到 AndResGuard 的白名单中,
* 是的话,要求你在 XmlClassGuard 前依赖 AndResGuard 插件,默认 false
*/
findAndConstraintReferencedIds = false
//用于增量混淆的 mapping 文件
mappingFile = file("xml-class-mapping.txt")
//更改 manifest 文件的 package 属性,即包名
packageChange = ["com.ljx.example": "ab.cd"]
//移动目录
moveDir = ["com.ljx.example": "ef.gh"]
}
此时就可以在Gradle
栏中,找到以下 4 个任务
任务介绍
XmlClassGuard
插件共有 5 个任务,分别是findAabConstraintReferencedIds
、findAndConstraintReferencedIds
、moveDir
、packageChange
及xmlClassGuard
,这 5 个任务之间没有任何关系,下面将一一介绍
1、findAabConstraintReferencedIds/findAndConstraintReferencedIds
findAabConstraintReferencedIds
需配合AabResGuard插件使用,如果你未使用 AabResGuard 插件,可忽略。
findAndConstraintReferencedIds
需配合AndResGuard插件使用,如果你未使用 AndResGuard 插件,可忽略。
下面仅介绍findAabConstraintReferencedIds
任务,findAndConstraintReferencedIds
任务同理
由于约束布局constraint_referenced_ids
属性的值,内部是通过 getIdentifier 方法获取具体的 id,这就要求我们把constraint_referenced_ids
属性的值添加进AabResGuard
的白名单中,否则打包时,id 会被混淆,打包后,constraint_referenced_ids
属性会失效,UI 将出现异常。
然而,项目中可能很多地方都用到constraint_referenced_ids
属性,并且值非常多,要一个个找出来并手动添加到AabResGuard
的白名单中,无疑是一项繁琐的工作,于是乎,findAabConstraintReferencedIds
任务就派上用场了,它是在打包时,自动查找constraint_referenced_ids
属性并添加进AabResGuard
的白名单中,非常实用的功能,你仅需要在XmlClassGurad
的配置findAabConstraintReferencedIds
为 true 即可,如下:
//以下均为非必须
xmlClassGuard {
/*
* 是否查找约束布局的 constraint_referenced_ids 属性的值,并添加到 AabResGuard 的白名单中,
* true 的话,要求你在 XmlClassGuard 前依赖 AabResGuard 插件,默认 false
*/
findAabConstraintReferencedIds = true
}
findConstraintReferencedIds
任务不需要手动执行,打包(aab)时会自动执行
2、moveDir
moveDir
是一个移动目录的任务,它支持同时移动任意个目录,它会将原目录下的所有文件(包括子目录)移动到另外一个文件夹下,并将移动的结果,同步到其他文件中,配置如下:
xmlClassGuard {
//移动目录
moveDir = ["com.ljx.example": "ef.gh",
"com.ljx.example.test": "ff.gg"]
}
上面代码中moveDir
是一个 Map 对象,其中 key 代表要移动的目录,value 代表目标目录; 上面任务会把com.ljx.example
目录下的所有文件,移动到ef.gh
目录下,将com.ljx.example.test
目录下的所有文件移动到ff.gg
目录下
3、packageChange
packageChange
是一个更改manifest
文件里package
属性的任务,也就是更改 app 包名的任务(不会更改 applicationId)
,改完后,会将更改结果,同步到其他文件中(不会更改项目结构),配置如下:
xmlClassGuard {
//更改 manifest 文件的 package 属性,即包名
packageChange = ["com.ljx.example": "ab.cd"]
}
以上packageChange
是一个 Map 对象,key 为原始 package 属性,value 为要更改的 package 属性,原始 package 属性不匹配,将更改失败
4、xmlClassGuard
xmlClassGuard
是一个混淆类的任务,该任务会检索AndroidManifest.xml
及navigation、layout
文件夹下的 xml 文件,找出 xml 文件中引用到的类,如 4 大组件及自定义 View 等,更改其包名+类名
,并将更改的结果,同步到其他文件中,最后会将混淆映射写出到 mapping 文件中,配置如下:
xmlClassGuard {
//用于增量混淆的 mapping 文件
mappingFile = file("xml-class-mapping.txt")
}
上面配置的mappingFile
可以是一个不存在的文件,混淆结束后,会将混淆映射写出到该文件中,如下:
dir mapping:
com.ljx.example -> e
com.ljx.example.activity -> dh
class mapping:
com.ljx.example.AppHolder -> e.B
com.ljx.example.activity.MainActivity -> dh.C
dir mapping
是混淆的目录列表,class mapping
是具体类的混淆列表
5、混淆任意类
xmlClassGuard
任务是支持增量混淆的,如果你需要混淆指定的类com.ljx.example.test.Test
,便可以在dir mapping
下写入com.ljx.example.test -> h
,
此时再次执行xmlClassGuard
任务,便会将com.ljx.example.test
目录下的所有类(不包含子目录下的类)
移动到h
文件夹中,并将所有类名混淆,再次混淆的后 mapping 文件如下:
dir mapping:
com.ljx.example -> e
com.ljx.example.activity -> dh
com.ljx.example.test -> h
class mapping:
com.ljx.example.AppHolder -> e.B
com.ljx.example.activity.MainActivity -> dh.C
com.ljx.example.test.Test -> h.D
手动输入混淆规则,需要注意以下几条规则
6、每次混淆产生不一样的结果
默认情况下,每次混淆,都将产生一样的结果,混淆的包名根据哈希算法得出,混淆的类名,从大写字母 A 开启,依次递增,如:A B C ... Y Z BA BB .. ZY ZZ BAA...
如果你需要每次混淆产生不一样的结果,只需做两步
对于包名,需要你配置每一个
对于类名,可以每一个都去配置,但类太多时,配置每一个,就显得繁琐,此时仅需要配置一个即可
如我们修改一下上面的mapping
文件,如下
dir mapping:
com.ljx.example -> hh
com.ljx.example.activity -> jk
com.ljx.example.test -> et
class mapping:
com.ljx.example.AppHolder -> hh.Z
此时执行xmlClassGuard
任务,就会产生不一样的结果,如下:
dir mapping:
com.ljx.example -> hh
com.ljx.example.activity -> jk
com.ljx.example.test -> et
class mapping:
com.ljx.example.AppHolder -> hh.Z
com.ljx.example.activity.MainActivity -> jk.BA
com.ljx.example.test.Test -> et.BC
可以看到,包名完全是根据自定义生成的结果,而类名便从Z
开始,依次递增Z BA BC ...
, 这里可以把类名看成 26 进制的字符串依次递增
注意事项⚠️
要混淆的类,要避免与其他类同名,否则类名替换时,会出现误杀情况
类混淆后,类的包名(路径)也会被混淆,所以,如果你用到一些三方库,有配置包名的地方,记得手动更改
XmlClassGuard
不会更改proguard-rules.pro
文件的内容,所以,类混淆后,如果该文件内容有混淆前的类或目录,也记得手动更改XmlClassGuard
只会帮你更改包名+类名
,并同步到其它文件中,不会更改你的任何代码逻辑,如混淆后,出现部分功能不正常问题,需要你自己查找原因,如果是XmlClassGuard
的问题,欢迎提issue或PR
Donations
如果它对你帮助很大,并且你很想支持库的后续开发和维护,那么你可以扫下方二维码随意打赏我,就当是请我喝杯咖啡或是啤酒,开源不易,感激不尽