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

来源:互联网 发布:英雄联盟账号淘宝 编辑:程序博客网 时间:2024/06/11 06:32

随着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    Name1158688  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.ZipEntryimport java.util.zip.ZipFileimport 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.absolutePathprint newApkFile.absolutePath//重新打包repackApk(oldApkFile.absolutePath, newApkFile.absolutePath)assert newApkFile.exists() : "没有找到重新压缩的release包!"}}

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


done, perfect !

0 0
原创粉丝点击