android gradle build resources.arsc文件未压缩问题解决

原创 2015年11月18日 13:23:24

随着google如火如荼的推出android studio IDE和gradle buld工具,很多公司要对build系统做从ant到gradle的升级,不幸的是我被分配负责该任务。


发现一个问题,gralde编译后的apk比ant要大大约1M左右,对于老大之前严格要求控制apk在10M左右的需求,只能说造化弄人。压缩包打开发现gradle build之后的apk resources.arsc没有压缩,导致apk增大很多。

于是乎,设置resource shrink 为true,结果如下:


图一:ant打包之后的详单:


图二:gradle shrinkResources false的详单


图三:gradle shrinkResources true的详单


结果发现:ant打包后的resources.arsc,从1.1M压缩到267K,还是比较狠的。

至于是否shrinkResources,没有什么效果

aapt l -v Client-release-unsigned-ant.apk ,查看apk明细:

发现ant包和gradle包的差异:

 Length   Method    Size  Ratio   Offset      Date  Time  CRC-32    Name
1158688  Deflate  273481  76%   9835381  11-17-15 15:18  04aecb3e  resources.arsc -------- <span style="color:#ff0000;">ant build apk</span>
1158508  Stored  1158508   0%   2899860  11-17-15 15:21  9222ccf9  resources.arsc   -------- <span style="color:#ff0000;">gradle build apk</span>

ant build resources.arsc是deflate method,而gradle build 的是stored method,而且size相差很大。

于是乎,寻找gradle设置deflate模式的配置开关,未果,似乎是硬编码方式,不支持dsl配置,只能从最后的apk包下手,对resources做二次压缩。下面代码:

apply plugin: 'android'


dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')
    compile project(':MyProj')
}


android {
    compileSdkVersion 19
    buildToolsVersion '21.1.2'


    lintOptions {
        abortOnError false
    }


    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
            jniLibs.srcDirs = ['libs']
        }


        // Move the tests to tests/java, tests/res, etc...
        instrumentTest.setRoot('tests')


        // Move the build types to build-types/<type>
        // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
        // This moves them out of them default location under src/<type>/... which would
        // conflict with src/ being used by the main source set.
        // Adding new build types or product flavors should be accompanied
        // by a similar customization.
        debug.setRoot('build-types/debug')
        release.setRoot('build-types/release')
    }


    defaultConfig {
        multiDexEnabled true
    }


    dexOptions {
        javaMaxHeapSize "2g"
        jumboMode true
    }


    buildTypes {
        debug {
            minifyEnabled false
            proguardFile('proguard.cfg')
        }
        release {
            minifyEnabled true
            proguardFile('proguard.cfg')
        }
    }


    packagingOptions {
        exclude('META-INF/DEPENDENCIES')
        exclude('META-INF/NOTICE')
        exclude('META-INF/LICENSE')
    }


    lintOptions {
        // Or, if you prefer, you can continue to check for errors in release builds,
        checkReleaseBuilds false
        // but continue the build even when errors are found:
        abortOnError false
    }
}


import java.util.zip.ZipEntry
import java.util.zip.ZipFile
import java.util.zip.ZipOutputStream


// 打包过程中很多手工zip过程:
// 1,为了压缩resources.arsc文件而对标准产出包重新压缩
// 2,以及各子apk的纯手打apk包
// 但对于音频等文件,压缩会导致资源加载报异常
// 重新打包方法,使用STORED过滤掉不应该压缩的文件们
// 后缀名列表来自于android源码
def repackApk(originApk, targetApk){
    def noCompressExt = [".jpg", ".jpeg", ".png", ".gif",
                         ".wav", ".mp2", ".mp3", ".ogg", ".aac",
                         ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet",
                         ".rtttl", ".imy", ".xmf", ".mp4", ".m4a",
                         ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2",
                         ".amr", ".awb", ".wma", ".wmv"]


    ZipFile zipFile = new ZipFile(originApk)
    ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(targetApk)))
    zipFile.entries().each{ entryIn ->
        if(entryIn.directory){
            println "${entryIn.name} is a directory"
        }
        else{
            def entryOut = new ZipEntry(entryIn.name)
            def dotPos = entryIn.name.lastIndexOf('.')
            def ext = (dotPos >= 0) ? entryIn.name.substring(dotPos) : ""
            def isRes = entryIn.name.startsWith('res/')
            if(isRes && ext in noCompressExt){
                entryOut.method = ZipEntry.STORED
                entryOut.size = entryIn.size
                entryOut.compressedSize = entryIn.size
                entryOut.crc = entryIn.crc
            }
            else{
                entryOut.method = ZipEntry.DEFLATED
            }
            zos.putNextEntry(entryOut)
            zos << zipFile.getInputStream(entryIn)
            zos.closeEntry()
        }
    }
    zos.finish()
    zos.close()
    zipFile.close()
}


task repack(){


	doLast{
		print "root dir is : $rootDir"
		println "release打包之后,重新压缩一遍,以压缩resources.arsc"


		def oldApkFile = file("$rootDir/projectPath/build/outputs/apk/Client-release-unsigned.apk")


		assert oldApkFile != null : "没有找到release包!"


		def newApkFile = new File("$rootDir/projectPath/build/outputs/apk/Client-release-unsigned-repack.apk")
		print oldApkFile.absolutePath
		print newApkFile.absolutePath
		//重新打包
		repackApk(oldApkFile.absolutePath, newApkFile.absolutePath)


		assert newApkFile.exists() : "没有找到重新压缩的release包!"
	}
}

其实也可以通过java或者python程序终结对apk进行二次处理达到效果,但是不如gradle处理的自然。


done, perfect !

Android build.gradle文件详解

Android build.gradle详解 什么是gradle? gradle是一个项目构建工具,java开发中有两个大名鼎鼎的项目构建Maven,Ant,其中maven简单易控深受开发者喜爱。...
  • Small_Mouse0
  • Small_Mouse0
  • 2017年02月28日 14:40
  • 2566

Android gradle build 修改文件名称及目录

Android gradle build 修改文件名称及目录
  • a13069730106
  • a13069730106
  • 2016年08月15日 22:31
  • 1526

【gradle】 使用 gradle 在控制台输出中文乱码解决

1. 环境 (idea + gradle + junit 测试)       ★ idea  关于 encoding 的编码已经设置完成(直接打开 settings  → 搜索 encoding ...
  • lihuapiao
  • lihuapiao
  • 2016年06月16日 17:54
  • 3363

android studio 一直卡在Gradle:Build Running的解决办法

在使用AS开发安卓应用程序的时候经常会遇到Gradle build running一直在运行甚至卡死的情况,本文列出了几种解决方法以供参考。...
  • a549742320
  • a549742320
  • 2016年09月13日 13:52
  • 35986

Android Studio 项目中,哪些文件应该忽略而不提交

Android Studio 中建议过滤的文件: - .idea 文件夹 - .gradle 文件夹 - 所有的 build 文件夹 - 所有的 .iml 文件 - local.proper...
  • Alien__Chao
  • Alien__Chao
  • 2016年06月29日 16:00
  • 6137

Android逆向之旅---解析编译之后的Resource.arsc文件格式

一、前言快过年了,先提前祝贺大家新年快乐,这篇文章也是今年最后一篇了。今天我们继续来看逆向的相关知识,前篇文章中我们介绍了如何解析Android中编译之后的AndroidManifest.xml文件格...
  • jiangwei0910410003
  • jiangwei0910410003
  • 2016年02月03日 15:42
  • 36229

android开发中build文件删除不了的问题

遇到的bug如下: Information:Gradle tasks [clean, :app:generateDebugSources, :app:generateDebugAndroidTestS...
  • professionIT
  • professionIT
  • 2016年05月23日 13:04
  • 3630

Android_androidstudio_Gradle Build Running特别慢问题

方法一:开启gradle单独的守护进程 在下面的目录下面创建gradle.properties文件: /home//.gradle/ (Linux) /Users//.gra...
  • u013035016
  • u013035016
  • 2016年08月19日 12:58
  • 1256

Android Studio 一直卡在Gradle:Build Running的解决办法

网上方法 一 : 我的没找到这一项 需要在android studio 中配置gradle的代理,当然是用goagent了。 打开setting->gradle->Gradle VM Opt...
  • taoerit
  • taoerit
  • 2017年03月04日 11:05
  • 3058

Gradle for Android-高级Build和自定义

既然你已了解Gradle是如何工作、如何创建task和plugin、如何建立持续集成,你可以称自己为专家了。本章包含了一些我们之前没有提到过的提示和技巧,可以使得使用Gradle构建、开发和部署And...
  • zhongshujunqia
  • zhongshujunqia
  • 2016年12月26日 09:18
  • 1933
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:android gradle build resources.arsc文件未压缩问题解决
举报原因:
原因补充:

(最多只允许输入30个字)