最近做完项目打包成apk后感觉项目有点大,于是在网上找了一些APK的瘦身方法,使用这些方法后APK果然减小了,现在对这些方法经验进行总结:
技术列表
lint检查
tiny图片处理
proguard
微信资源压缩
lint检查清除冗余
实践方式:
Android Studio
Analyze -> Run Inspection by Name
在对话框中分别输入
unusedResources
unused declaration
结果:
可以发现多余的冗余文件如多余的图片,多余的代码等等,将这些多余的删除可以减少一点apk的体积。
tiny图片处理:
https://tinypng.com/
目前所知图片压缩效果最好的网站。压缩后的图片体积会减少好多非常不错。
在日常的开发中,如果去此网站挨个处理图片其实也是有困扰的。其实我们可以利用tiny提供的jar包做了个批量处理本地图片的tinyPIC gradle plugin。然后在build 中插入一个新的tinyPicPlugin task.遍历寻找项目res中以drawable开头的文件夹中的图片资源,调用tiny API进行压缩工作并替换原来的文件。
tinyPIC插件适用于各个Android项目,下面的链接是一个开源了的tiny 插件,接入方法请参考:
https://github.com/mogujie/TinyPIC_Gradle_Plugin
Proguard
Proguard是编译时对java代码进行压缩,混淆,优化,预编译等操作的集成化工具。达到删除冗余,增加安全防护,减小大小的功效。在Android studio中的app的gradle可以以下配置:
buildTypes {
release {
// 不显示Log
buildConfigField "boolean", "LOG_DEBUG", "false"
//混淆
minifyEnabled true
//Zipalign优化
zipAlignEnabled true
//去除无效资源
shrinkResources true
//前一部分代表系统默认的android程序的混淆文件,该文件已经包含了基本的混淆声明
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
开启混淆后有可能会报错,因此还要保持一些代码不能被混淆
#指定代码的压缩级别
-optimizationpasses 5
#包明不混合大小写
-dontusemixedcaseclassnames
#不去忽略非公共的库类
-dontskipnonpubliclibraryclasses
#优化 不优化输入的类文件
-dontoptimize
#预校验
-dontpreverify
#混淆时是否记录日志
-verbose
# 混淆时所采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#保护注解
-keepattributes *Annotation*
# 保持哪些类不被混淆
-keep public class * extends android.app.Fragment
-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 com.android.vending.licensing.ILicensingService
#如果有引用v4包可以添加下面这行
-keep public class * extends android.support.v4.app.Fragment
#####################记录生成的日志数据,gradle build时在本项目根目录输出################
#apk 包内所有 class 的内部结构
-dump class_files.txt
#未混淆的类和成员
-printseeds seeds.txt
#列出从 apk 中删除的代码
-printusage unused.txt
#混淆前后的映射
-printmapping mapping.txt
################混淆保护自己项目的部分代码以及引用的第三方jar包library#########################
##-keep class com.zhy.autolayout.** { *; }
-keep class com.mifly.audio.base.BaseActivity{*;}
############混淆保护自己项目的部分代码以及引用的第三方jar包library-end##################
-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
#保持 native 方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
#保持自定义控件类不被混淆
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
#保持自定义控件类不被混淆
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
#保持自定义控件类不被混淆
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
#保持 Parcelable 不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
#保持 Serializable 不被混淆
-keepnames class * implements java.io.Serializable
#保持 Serializable 不被混淆并且enum 类也不被混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
!private <fields>;
!private <methods>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
#不混淆资源类
-keepclassmembers class **.R$* {
public static <fields>;
}
-keep class **.R$*
-keep class org.apache.http.**
-keep class android.support.v7.widget.**{*;}
-keep class android.support.design.**{*;}
-keep public class android.support.v7.widget.LinearLayoutManager
-keep public class * extends android.support.v7.widget.CardView$LayoutManager {
public <init>(...);
}
# support-v4
-dontwarn android.support.v4.**
-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
# support-v7
-dontwarn android.support.v7.**
-keep class android.support.v7.internal.** { *; }
-keep interface android.support.v7.internal.** { *; }
自己的项目那个类报错就保持那个类不混淆。
微信资源压缩
apk代码运行时,是通过 code ->R ->res找到对应资源的。
而R ->res的映射关系是打包时写在resources.arsc里的。
所以对生成的apk进行的操作如下:
1.先解压缩包
2.然后对res目录下的文件夹和文件进行名称替换
3.同时修改resources.arsc里对应的R与资源的映射关系
4.然后再打包签名生成新的apk
微信资源压缩工具与业务代码无关,我们已经把这部分技术处理整合到打包系统里,推荐大家在发布你们的apk时加入微信资源压缩,效果杠杠的。
微信Android资源混淆打包工具原理:
http://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=208135658&idx=1&sn=ac9bd6b4927e9e82f9fa14e396183a8f#rd
github地址:
https://github.com/shwenzhang/AndResGuard/blob/master/README.zh-cn.md
github中已经告诉微信资源压缩的使用方法,感觉在Android stduio中使用最简单了,如果看不懂如何使用可以在它提供的源码中的例子有配置。
使用以上方法还是很不错的,apk的体积确实小了很多。