极致缩小APK体积(不去除V4,V7包)
我们都知道,现在的安卓APK体积是越来越大,一方面是安卓的碎片化严重,为了适配各大厂商而新增很多业务逻辑,(然而并不可能这么大),另一方面是SDK的v4,v7包占了一些体积, 还有一方面就是我们开发者的原因了,很多开发者并未优化体积,匆匆交差.今天就说说我是如何优化体积的,欢迎大神指正,留给小盆友学习.
碎片化严重
这个呢? 我是没办法咯!
v4 v7包的占用
这两个包是SDK的包 , 有部分控件会用到, 总大小占2.9MB左右 经压缩打包后占1.2MB,如果项目中没有用到的话可以去除他们 ,免得占地方.
去除v4 ,v7
-
在bind.gradle里去除他们的compile .
-
去掉之后会报错 ,在Activity里继承Activity 消除错误
-
在style里去除对v7包的引用
就这样v4,v7包就去除了, 未用到v4 v7包的apk新建也就200KB左右.
开发途中优化过程
1.删除无用资源
-
使用studio检测无用资源
用android lint中Unused Resource
操作方法:
完成之后就可以看到你没用到的资源了
- 打包时开启删除无用资源
build.gradle中设置:
android{
…
buildTypes{
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile(‘proguard-android.txt’), ‘proguard-rules.pro’
}
}
}
该设置会在打包时自动将未使用的资源排除掉。
2.多业务线资源去重
如果app中包含多个业务线难免会有不同名的资源重复,推荐一个扫描重复资源的工具: Duplicate Cleaner Pro
3.资源压缩处理
利用工具对图片和音频进行压缩推荐两个工具
图片压缩工具:
音频压缩工具:
http://trac.ffmpeg.org/wiki/CompilationGuide/MacOSX
4.微信混淆工具
微信混淆工具可以提高apk安全性,也能大大的减少apk大小强烈推荐 以下是关于这个工具的介绍和使用书名 资源混淆方案之微信vs美团
注意:如果你有读取包中文件的操作不能用这个工具,因为把资源名混淆后无法找到对应文件
5. 7zip压缩
http://www.7-zip.org/download.html
-
将APK包解压到文件夹
-
全选所有文件,右键“添加到压缩包”
-
“压缩格式”必须“zip”
-
“压缩等级”选择“极限压缩”
-
“压缩方法”必须“Deflate”(试了Deflate64,BZip2,LZMA,PPMd都无法正常安装)
-
“单词大小”选择“256”
-
将后缀改为APK即可
原APK大小:1,039,193 B
不同“单词大小”压缩能力比对:
128:963,793 B(极限压缩默认)
192:963,787 B
256:963,785 B(推荐)
258:963,911 B
最佳参数256,能将原APK文件 再压小 73.64KB(7.25%)!
有大神特此开发了小工具, 对APK极限压缩并对齐的工具
开源地址
说明:“运行”之后会在原APK所在文件夹生成两个APK,分别为:
1.原APK名字_NEW.APK:这是7zip重新进行极限压缩后的新APK文件,默认没有对齐(此APK可删除)
2.原APK名字_Aligned.APK:这是对NEW.APK进行对齐后产生的最终APK包文件。(最终发布此APK即可)
6 . 最后奉上我的bind.gradle日常配置 (调整后使用)
apply plugin: 'com.android.application'
static def releaseTime() {
return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
}
android {
compileSdkVersion 26
buildToolsVersion "26.0.1"
defaultConfig {
applicationId "com.townwang.town"
resConfigs "zh","en"//仅支持中文和英文
minSdkVersion 14
targetSdkVersion 27
versionCode 6
versionName "2.1"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
//混淆
minifyEnabled true
shrinkResources true//打开资源压缩
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
zipAlignEnabled true //是否使用zipalign工具压缩
}
debug {
//混淆
minifyEnabled true
shrinkResources true//打开资源压缩
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
zipAlignEnabled true //是否使用zipalign工具压缩
}
}
lintOptions {
checkReleaseBuilds false
abortOnError false
}
android.applicationVariants.all { variant ->
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
def fileName = "Town" + "_V${defaultConfig.versionName}_${releaseTime()}.apk"
output.outputFile = new File(outputFile.parent, fileName)
}
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
testCompile 'junit:junit:4.12'
//注解框架
compile 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
//网络请求库 OKhttp 3.8.1
compile 'com.squareup.okhttp3:okhttp:3.8.1'
//Gson 2.8.0
compile 'com.google.code.gson:gson:2.8.0'
}
7.混淆
上面说的微信混淆工具只是对资源的混淆 , 混淆一是为了提高安全性 , 尽可能不易被人查看源代码 , 二是缩减体积 .下面附上 我自用的混淆代码;
#-------------------------------------------定制化区域----------------------------------------------
#---------------------------------1.实体类---------------------------------
#-keep class 你的实体类所在的包.** { *; }
-keep class com.townwang.town.model.javabean.** { *; }
#-------------------------------------------------------------------------
#---------------------------------2.第三方包-------------------------------
#okhttp
-dontwarn okhttp3.**
-keep class okhttp3.**{*;}
#okio
-dontwarn okio.**
-keep class okio.**{*;}
#butterknife:8.5.1
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; }
-keepclasseswithmembernames class * {
@butterknife.* <fields>;
}
-keepclasseswithmembernames class * {
@butterknife.* <methods>;
}
##--------------- Gson ----------
-keep public class com.google.gson.**
-keep public class com.google.gson.** {public private protected *;}
-keepattributes Signature
-keepattributes *Annotation*
-keep public class www.zhihusan.agentscan.Model.Bean.LoginResultBean { private *; }
##---------------End: proguard configuration for Gson ----------
#picasso
#-dontwarn com.squareup.okhttp.**
#GrrenDao3.2.2
#-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
#public static java.lang.String TABLENAME;
#}
#-keep class **$Properties
# If you do not use SQLCipher:
#-dontwarn org.greenrobot.greendao.database.**
# If you do not use Rx:
#-dontwarn rx.**
# Loading
#-keep class com.wang.avi.** { *; }
# -keep class com.wang.avi.indicators.** { *; }
#-------------------------------------------------------------------------
#---------------------------------3.与js互相调用的类------------------------
#---------------------------------内部类------------------------
#-keepclasseswithmembers class 你的类所在的包.父类$子类 { <methods>; }
#-------------------------------------------------------------------------
#---------------------------------4.反射相关的类和方法-----------------------
#----------------------------------------------------------------------------
#---------------------------------------------------------------------------------------------------
#-------------------------------------------基本不用动区域--------------------------------------------
#---------------------------------基本指令区----------------------------------
-optimizationpasses 5
-dontskipnonpubliclibraryclassmembers
-printmapping proguardMapping.txt
-optimizations !code/simplification/cast,!field/*,!class/merging/*
-keepattributes *Annotation*,InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
#----------------------------------------------------------------------------
#---------------------------------默认保留区---------------------------------
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep public class com.android.vending.licensing.ILicensingService
-keep class android.support.** {*;}
-keep public class * extends android.support.v4.app.Fragment
-keep public class * extends android.view.View{
*** get*();
void set*(***);
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
-keep class **.R$* {
*;
}
-keepclassmembers class * {
void *(**On*Event);
}
#----------------------------------------------------------------------------
#---------------------------------webview------------------------------------
-keepclassmembers class fqcn.of.javascript.interface.for.Webview {
public *;
}
-keepclassmembers class * extends android.webkit.WebViewClient {
public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembers class * extends android.webkit.WebViewClient {
public void *(android.webkit.WebView, jav.lang.String);
}
#----------------------------------------------------------------------------
#---------------------------------------------------------------------------------------------------
8.优化字节码
ReDex是Facebook开源一个减小安卓app大小以提高性能的工具,内嵌以及清除僵尸代码这样的优化来减小字节码,主要是对Dex进行了优化,能让APK 运行更快,不过需要多测试是否会崩溃。
开源地址 : 适用于Android应用的字节码优化器
中文说明 (英文好的直接去看开源说明): 适用于Android应用的字节码优化器
这就是我目前所知道的优化了.也是我做一个APP所用到的.做个记录.有什么不对或者需要补充请留言.