Android shrinkResources true 引发的血案

Android shrinkResources true 引发的血案


  1. 今天在众测我的App,发现我在代码里面动态调去取之前的图片资源时 
    一直报 Resources$NotFoundException: Resource ID #0x4 异常 
    。 
    但是我在正常debug情况下却没有这个问题
    STEPS TO REPRODUCE:
1. Create a dummy app that uses appcompat (so there are resources to be removed)
2. In build.grade set 'minifyEnabled true' and 'shrinkResource true' 
3. Create the APK where unused resources are removed

EXPECTED RESULTS:
Application should start normally.

OBSERVED RESULTS:
Application crashes with following stacktrace:
android.content.res.Resources$NotFoundException: File res/drawable-xxhdpi-v4/abc_list_pressed_holo_light.9.png from drawable resource ID #0x7f020020
    at android.content.res.Resources$CRunnable_openmp.doOpenMP(Resources.java:1111)
    at android.content.res.Resources$__ompClass0.__doWork(Resources.java:1043)
    at com.samsung.javaomp.runtime.__OMPThread.run(Unknown Source)
Caused by: java.io.FileNotFoundException: res/drawable-xxhdpi-v4/abc_list_pressed_holo_light.9.png
    at android.content.res.AssetManager.openNonAssetNative(Native Method)
    at android.content.res.AssetManager.openNonAsset(AssetManager.java:408)
    at android.content.res.Resources$CRunnable_openmp.doOpenMP(Resources.java:1106)
    ... 2 more
java.io.FileNotFoundException: res/drawable-xxhdpi-v4/abc_list_pressed_holo_light.9.png
    at android.content.res.AssetManager.openNonAssetNative(Native Method)
    at android.content.res.AssetManager.openNonAsset(AssetManager.java:408)
    at android.content.res.Resources$CRunnable_openmp.doOpenMP(Resources.java:1106)
    at android.content.res.Resources$__ompClass0.__doWork(Resources.java:1043)
    at com.samsung.javaomp.runtime.__OMPThread.run(Unknown Source)
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  1. 后来我反编译我的apk,找到资源文件夹发现,我需要的图片资源被移除了。我想到我在代码里开启了shrinkResources


         buildTypes {
        release {
            // 不显示Log
            buildConfigField "boolean", "LOG_DEBUG", "false"
            shrinkResources true
            minifyEnabled true
            zipAlignEnabled true
            // 移除无用的resource文件
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

            applicationVariants.all { variant ->
                variant.outputs.each { output ->
                    def outputFile = output.outputFile
                    if (outputFile != null && outputFile.name.endsWith('.apk')) {
                        // 输出apk名称为boohee_v1.0_2015-01-15_wandoujia.apk
                        def fileName = "${variant.productFlavors[0].name}${defaultConfig.versionName}.apk"
                        output.outputFile = new File(outputFile.parent, fileName)
                    }
                }
            }
        }


 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

google 翻墙找了一堆答案:https://code.google.com/p/android/issues/detail?id=79325

写在最后:

  • 现在依然无法解决这个问题:因为我的资源需要在服务端返回后动态绑定,现在不需要,我不可能在代码里预定义这个资源引用
  • 发现关闭之后,程序打包出来增加了1M多,显然这不是我想要的结果,但面对崩溃,我只能先忍受解决崩溃带来的程序包体积增加。
<think>我们正在讨论Android Gradle插件中的资源缩减(resource shrinking)功能。根据用户的问题,他们想了解如何使用Gradle插件来缩减资源,这通常是为了减少APK的大小。 资源缩减(resource shrinking)通常与代码混淆(通过ProGuard或R8)一起使用,它会在构建过程中移除未使用的资源。在Android Gradle插件中,可以通过设置`shrinkResources`为`true`来启用。 步骤: 1. 在build.gradle文件中,为相应的构建类型(如release)启用资源缩减。 2. 通常需要同时启用代码混淆(minifyEnabled),因为资源缩减依赖代码混淆的结果来确定哪些资源未被使用。 示例配置(在build.gradle的android块中): ```groovy android { buildTypes { release { minifyEnabled true // 启用代码混淆 shrinkResources true // 启用资源缩减 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } ``` 此外,还可以通过保留某些资源来避免被移除。例如,如果想保留某些资源,可以在res/raw/下创建一个名为`keep.xml`的文件(通常放在res/raw/keep.xml,但也可以放在其他资源目录,如res/xml/)。在这个文件中,可以使用`<resources>`标签指定要保留的资源。 示例keep.xml: ```xml <?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*" tools:discard="@layout/unused2" /> ``` 注意: - `tools:keep`:指定要保留的资源,可以使用通配符。 - `tools:discard`:指定要移除的资源,同样可以使用通配符。这通常在资源被代码引用但实际未使用(或者有动态获取资源的情况)时使用。 资源缩减在构建过程中会分析资源的使用情况,并移除那些没有在代码中引用的资源。但是,有些资源可能是通过动态方式引用的(例如通过`Resources.getIdentifier()`),这时可能会被错误地移除。为了避免这种情况,可以在`keep.xml`中明确指定保留这些资源。 另外,资源缩减功能还可以移除资源库(比如support库)中未使用的资源。例如,如果使用了AppCompat库,但只使用了其中一部分资源,那么其他资源会被移除。 引用说明: [^1] 提供了Android项目的一个典型目录结构,其中build.gradle文件是配置构建的关键,包括资源缩减的配置就是在build.gradle中完成的。 [^2] 提到了Gradle仓库的概念,但资源缩减并不直接涉及仓库,而是构建过程中的一个步骤。 因此,我们主要参考[^1]中的项目结构,在build.gradle文件中进行配置。 相关问题: 1. 资源缩减和代码混淆(ProGuard/R8)有什么关系? 2. 如何保留特定的资源不被移除? 3. 资源缩减对多语言资源(如不同分辨率的图片)如何处理? 4. 资源缩减是否会影响运行时性能? 5. 如何检查资源缩减后移除了哪些资源? 下面,我们将详细回答用户的问题。</think>### Android Gradle 插件资源缩减(Resource Shrinking) 资源缩减是 Android Gradle 插件的一项优化功能,用于自动移除 APK/AAB 中未使用的资源(如图片、布局、字符串等),从而显著减小应用体积。其核心原理是结合代码混淆工具(R8/ProGuard)分析资源引用关系。 #### 🔧 启用方式 在模块级 `build.gradle` 中配置: ```groovy android { buildTypes { release { minifyEnabled true // 必须启用代码压缩 shrinkResources true // 启用资源缩减 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } ``` #### ⚙️ 保留特定资源 创建 `res/raw/keep.xml` 定义保留规则: ```xml <resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@layout/activity_main, @drawable/logo_*" // 通配符保留 tools:discard="@layout/unused_*" /> // 强制移除 ``` #### 🔍 工作原理 1. **引用分析** 通过 R8/ProGuard 生成的资源映射表(`resources.txt`)识别未被代码引用的资源 2. **资源移除** 删除未引用资源(如未使用的图片、布局) 3. **资源合并** 合并重复资源(如不同分辨率下的相同图片) 4. **资源优化** 压缩 PNG/JPG 等资源(需额外启用 `cruncherEnabled`) #### ⚠️ 注意事项 1. 必须同时启用 `minifyEnabled`(代码混淆) 2. 动态引用的资源(如 `getIdentifier()`)需手动保留 3. 使用 Lint 检查潜在问题: ```bash ./gradlew lintRelease ``` 4. 查看移除报告: ```bash ./gradlew assembleRelease --info | grep "Removed unused resources" ``` #### 📦 多模块项目优化 在根项目 `build.gradle` 中全局配置: ```groovy subprojects { afterEvaluate { project -> if (project.plugins.hasPlugin('com.android.application') || project.plugins.hasPlugin('com.android.library')) { android.buildTypes.release.shrinkResources = true } } } ``` > **最佳实践**:结合 `resConfigs` 移除多余语言资源: > ```groovy > android { > defaultConfig { > resConfigs "en", "zh-rCN" // 只保留英文和简体中文 > } > } > ``` [^1] --- ### 相关问题 1. **资源缩减与代码混淆(R8/ProGuard)如何协同工作?** 2. **如何处理通过 `Resources.getIdentifier()` 动态加载的资源?** 3. **资源缩减对应用启动性能有何影响?** 4. **如何验证资源缩减后应用功能的正确性?** 5. **资源缩减与 Android App Bundle 的资源动态分发有何关联?** [^1]: 项目结构参考:`build.gradle` 配置位置
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值