恐怕我要么误解了 Proguard/R8 的行为,要么它不适合我的需求。如果有任何 Proguard 专家,我将不胜感激。
这是我的背景。我正在构建一个 Android 库,主要是为了以闭源方式分发给外部各方。话虽这么说,我还在构建一个 Android 应用程序,它也依赖于这个库。我有一个 Proguard 配置,用于混淆我的库,以便我分发的
.aar
被混淆。我还引用了 consumer-rules.pro
Proguard 文件,该文件指示要保留哪些类,以便在消费者也使用 Proguard 时不破坏库。这部分在这里似乎工作正常。在发布模式下构建 gradle 后输出的 .aar
文件对我来说看起来足够了。
我还做了让我的 Android 应用程序依赖于我生成的
.aar
的实验,并且在 Android 应用程序中添加我的库所需的缺少的依赖项后(因为 .aar
没有附带 .module
文件) gradle)它似乎正在工作。
现在,当我的应用程序通过更传统和更合适的方式依赖于我的库时,问题就会发生:
implementation project(':my-lib')
。在我看来,Proguard 实际上并不是先应用到我的库,然后才应用到我的应用程序。它看起来更像是库和应用程序的源代码被聚合,然后 Proguard 在整个源代码上运行。结果肯定是不同的,一些原本应该在我的库中混淆的部分不再存在,一些代码在应该保留的同时被缩小了,而且我的自定义映射不适用。
这是我的文件树重要部分的可视化:
my-project/
├─ my-app/
│ ├─ ...
│ ├─ build.gradle
│ ├─ proguard-rules.pro
├─ my-lib/
│ ├─ ...
│ ├─ build.gradle
│ ├─ custom-mapping.txt
│ ├─ consumer-rules.pro
│ ├─ proguard-rules.pro
my-app
的build.gradle
:
android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
...
dependencies {
...
implementation project(':my-lib')
}
my-lib
的build.gradle
:
android {
defaultConfig {
...
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
my-lib
的proguard-rules.pro
:
-applymapping "custom-mapping.txt"
# Place every obfuscated class in a single package
-flattenpackagehierarchy 'com.mycompany.mylib.obfuscated'
# Do not attempt to shrink the code when building this library as a standalone, otherwise all of
# the code will get stripped, ending up with an empty aar file
-dontshrink
# Here are my keep rules
...
my-lib
的consumer-rules.pro
:
# Some keep rules related to Android internal classes that I rely on in my library
# Field that shouldn't be stripped if the class is present
-keepclassmembers class com.mycompany.mylib.obfuscated.z.z { # <-- the z.z comes from the custom mapping I'm applying to ensure it's always obfuscated the same way
# Fields that I want to keep and that would be shrunk without specifying it
...
}
是的,我想我已经详细介绍了与我的上下文相关的所有内容。 我想我的问题可以改写为:如何根据我的库获得与外部应用程序相同的结果,但仍然取决于我的本地库?
当然,我知道我可以依赖已发布的库,但这会让开发变得痛苦,因为我必须不断发布测试二进制文件,而我不想这样做。