从Play Services整体中筛选资源,使您的APK更小



关于Google Play服务的整体性以及为什么应该将其拆分为更多的库,已经写了很多文章。目前,保持APK较小的解决方法是使用proguard删除未使用的引用。这对于classes.dex非常有效,但对于包含的资源则不然。

我获得了大约1MB的额外未使用资源,使用捆绑的Android Wear应用程序,这一开销会翻倍。所以我的APK比需要的大2MB。

我想知道Gradle中是否有一些简单的方法可以将来自依赖项AAR的一些资源从生成的APK中排除。

Gradle Android插件中的AAPT选项似乎只允许过滤资产。

我想挂接一些自定义的aapt脚本,在签署APK以发布之前,该脚本会使用aapt调用remove来获取资源列表。

其他人有更简单的解决方案吗?

经过一些研究,我发现了以下次优解。我不得不手动列出所有不需要的资源(幸运的是,模式是适用的(,并确保删除所有引用它们的文件。下面是一个例子,它使我的Wear应用程序APK从1.5 MB到300kb,APK工作正常,没有问题。

我必须创建自己的任务stripResources,并将其挂接在标准的Android插件任务之间:mergeReleaseResourcesprocessReleaseResources

task stripResources << {
    println "Custom resource stripping in: $buildDir"
    delete fileTree(dir: "$buildDir", include: "**/layout/confirmation_activity_layout.xml")
    delete fileTree(dir: "$buildDir", include: "**/layout/watch_card_content.xml")
    delete fileTree(dir: "$buildDir", include: "**/common_signin*.png")
    delete fileTree(dir: "$buildDir", include: "**/drawable/common_signin*.xml")
    delete fileTree(dir: "$buildDir", include: "**/generic_confirmation*.png")
    delete fileTree(dir: "$buildDir", include: "**/drawable/confirmation_*.xml")
    delete fileTree(dir: "$buildDir", include: "**/drawable/card_background.xml")
    delete fileTree(dir: "$buildDir", include: "**/card_frame*.png")
    delete fileTree(dir: "$buildDir", include: "**/go_to*.png")
    delete fileTree(dir: "$buildDir", include: "**/drawable/go_to_*.xml")
    delete fileTree(dir: "$buildDir", include: "**/ic_plusone*.png")
    delete fileTree(dir: "$buildDir", include: "**/powered_by_google*.png")
    // if you only have English you can teh following to filter out some GPS texts wich also take few hundreds of kb
    // delete fileTree(dir: "$buildDir", include: "**/values-*/values.xml")
}
    tasks.whenTaskAdded { task ->
        if (task.name == 'processReleaseManifest') {
            task.dependsOn stripResources
        }
    }

你可以为普通的安卓APK做类似的任务。

从Android Gradle插件的0.14版本开始,这可以自动完成,如本文所述:

android {
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
        }
    }
}

shrinkResources是一个标志,它告诉编译器跳过任何未被引用的资源。minifyEnabledrunProguard的新名称,必须启用该名称才能使shrinkResources工作。

感谢Petr Nalevka富有洞察力的回答,我提出了以下解决方案(又称丑陋的破解(。

此代码删除hdpi、xhdpi、xxhdpi等下的所有PNG可绘制文件,只保留mdpi下的可绘制文件(文件大小最小的(。只有当可绘制项在mdpi下有一个同级项时,也就是说,如果可以安全地删除它们,才删除可绘制项。谷歌播放服务应保持完全功能。

每个应用程序变体都会注册一个任务,因此此代码适用于多种产品风格。

applicationVariants.all { variant ->
    def variantCamelName = variant.name.substring(0, 1).toUpperCase() + variant.name.substring(1)
    def stripResourcesTask = task("strip${variantCamelName}Resources") {
        doFirst {
            def resDir = "$buildDir/intermediates/res/merged/$variant.dirName"
            def gpsDir = "$buildDir/intermediates/exploded-aar/com.google.android.gms"
            fileTree(dir: "$gpsDir", include: "**/drawable-*/*.png").each { resFile ->
                if (!resFile.parentFile.name.endsWith("-mdpi")) {
                    def resName = resFile.name
                    def resDirName = resFile.parentFile.name
                    def mdpiFile = "$resFile.parentFile.parentFile/drawable-mdpi/$resName"
                    if (file(mdpiFile).file) {
                        def files = fileTree(dir: "$resDir", include: "**/${resDirName}/${resName}")
                        // files.each { f -> println "Deleting $f..." }
                        delete files
                    }
                }
            }
        }
    }
    tasks["merge${variantCamelName}Resources"].finalizedBy stripResourcesTask
}

使用Android Studio 1.3.0、Gradle插件1.3.0版本、构建工具22.0.1版本和GPS 7.5.0版本进行测试。

我有点喜欢Groovy,所以这可能不是最优雅的解决方案。

最新更新