App瘦身和混淆

App瘦身和混淆

一、背景
在开发中我们经常遇到一个问题,那就是app包过大,有时候依赖一些第三方moudle 或者第三方sdk ,或者本身app 放了很多图片所导致app过大,那么怎么解决问题呢,不要急往下看。

二、需求
1.我们要利用混淆让我们的代码尽可能减少。
2.布局文件不要过多,太多了会乱,而且不方便整理.
3.图片不要太多。
4.对于无用资源,利用as能自动删除。

三、实现

分析app组成结构
首先利用2.2自带工具分析app,并有针对性的进行优化。
这里写图片描述
我们都知道apk是由:
asserts
lib
res
dex
META-INF
androidManifest
这几部分构成的
我们利用as分析工具,以我自己的新打包的工具进行讲述。
这里写图片描述

lib

lib目录下,会放各种so文件。利用分析工具去掉无用的so库
这里写图片描述

dex

dex文件是java代码打包后的字节码,一个dex文件最多只支持65535个方法,这也是我们为什么需要分包的原因。
这里写图片描述
因为dex 是分包不均的,可以理解为装箱,一个箱子的大小事固定的。但是你的代码量去不足。

res

res目录下存放很多资源,图片,字符串 、音频文件、各种xml文件等等。这是自己的的资源文件,没有做资源文件混淆,所以可读性很高。
这里写图片描述
例如微信的资源图片 都做了混淆所以都不可读。

以上就是就是分析工具 ,大家看到了我在说明结构时候很多,但是为什么,我只说这几点呢,其实很简单,例如asserts 目录下,我们会存放很多文件,但是这些文件就需要开发者手动的去优化了。

下面来说一说优化吧
res
res我们都熟知 ,我们图片文件 布局文件,还有一些配置文件都放在这。
1.布局优化
布局 优化其实不难,减少重复的布局文件提成一个xml 利用include 导入,这样很好的优化了页面,页面复用 ,我们有时候一个主页的其中一个模块和其他页面模块相同,同样的方法,这就是 include 的好处
2.图片优化
我们美工提供给我们png 图片 ,其实一个不大。但是都放在一起你在打包看看就很大,这样造成apk 超大。其实美工妹子也做了压缩的。
1.利用svg 替换少数图片。
2.利用压缩工具 减少png 图片大小,压缩有时候也会造成png图片失真。还有png 转换成webp 格式,可以用这个工具isparta
3.Lint工具可以检测项目中没有用到的资源文件,但是对于通过反射调用的图片无法过滤,需要我们手动排除
这里写图片描述
不要勾选id ,如果否选id 会影响打他databinding使用
这里写图片描述

其实去除无用资源还有一个 那就是在我们build.gradle里面配置
这里写图片描述
没错 就是这个 shrinkResources true ,

lib
lib 优化我们只需要搞定里面的so文件就差不多了,当然你如果引用了第三方jar ,需要注意奥。
so 文件优化 也需要在build.gradle里面配置
这里写图片描述
嘿嘿 没错就是他,设置支持的so库,去掉无用的so文件,同样还有另一种方法,就是根据手机cup支持的需要的库去引用 。那种方法我就不立出来了。

string.xml 说下这个
大部分应用其实并不需要支持几十种语言的,作为国内应用,我们可以只支持中文。推荐在项目的build.gradle中进行如下配置:
android {

//...

defaultConfig {
    resConfigs "zh"
}

}
大概就是这样 ,下面我们来说一下混淆吧 。混淆是件麻烦的事。
前几天 手快 更新了一波as 到2.3 了,在之前没发现问题,更新到2.3 之后,我只能说一句哎呀我去。

在编写这里面时候先逐条介绍下基本指令区指令的含义

-optimizationpasses 5
代码混淆的压缩比例,值在0-7之间

-dontusemixedcaseclassnames
混淆后类名都为小写

-dontskipnonpubliclibraryclasses
指定不去忽略非公共的库的类

-dontskipnonpubliclibraryclassmembers
指定不去忽略非公共的库的类的成员

-dontpreverify
不做预校验的操作

-verbose
-printmapping proguardMapping.txt
生成原类名和混淆后的类名的映射文件

-optimizations !code/simplification/cast,!field/,!class/merging/
指定混淆是采用的算法

-keepattributes Annotation,InnerClasses
不混淆Annotation

-keepattributes Signature
不混淆泛型

-keepattributes SourceFile,LineNumberTable
抛出异常时保留代码行号

-keep class XXXX
保留类名不变,也就是类名不混淆,而类中的成员名不保证。当然也可以是继承XXX类的所有类名不混淆,具体代码不贴了,重在理解。

-keepclasseswithmembers class XXXX
保留类名和成员名。当然也可以是类中特定方法,代码不贴了,理由同上

首先开启混淆 在build.gradle中进行如下配置:

1.这里写图片描述

minifyEnabled true 这句话就是开启混淆 true 为开启。

开启了之后sync new 一下

2.proguard-rules.pro 文件打开配置混淆指令
在这个混淆 文件中 有一些命令书不需要改变的

——————————————-基本不用动区域——————————————–

———————————基本指令区———————————-

-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontpreverify
-verbose
-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.* {;}
# 保持native方法不被混淆
-keepclasseswithmembernames class * {
native ;
}

-keepclassmembers class * extends android.app.Activity{
public void *(android.view.View);
}

保持枚举enum类不被混淆

-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep public class * extends android.view.View{
* get*();
void set*(*);
public (android.content.Context);
public (android.content.Context, android.util.AttributeSet);
public (android.content.Context, android.util.AttributeSet, int);
}
# 保持自定义控件不被混淆
-keepclasseswithmembers class * {
public (android.content.Context, android.util.AttributeSet);
public (android.content.Context, android.util.AttributeSet, int);
}

保持Parcelable不被混淆

-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-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);
}

—————————————————————————-

例如上面这些都是不需要动 的 同样 如果 你项目中
下面我把一下常用的第三方混淆立出来
# OkHttp3
-dontwarn okhttp3.logging.**
-keep class okhttp3.internal.*{;}
-dontwarn okio.**

Retrofit

-dontwarn retrofit2.**
-keep class retrofit2.* { ; }

fastjson

-dontwarn com.alibaba.fastjson.**
-keep class com.alibaba.fastjson.*{; }

rxjava

-dontwarn rx.**
-keep class rx.* { ; }
-dontwarn sun.misc.**
-keepclassmembers class rx.internal.util.unsafe.ArrayQueue*Field {
long producerIndex;
long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
rx.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
rx.internal.util.atomic.LinkedQueueNode consumerNode;
}

butterknife

-keep class butterknife.* { ; }
-dontwarn butterknife.internal.**
-keep class *$$ViewBinder { ; }

-keepclasseswithmembernames class * {
@butterknife.* ;
}

-keepclasseswithmembernames class * {
@butterknife.* ;
}

eventBus

-keepattributes Annotation
-keepclassmembers class ** {
@org.greenrobot.eventbus.Subscribe ;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
(java.lang.Throwable);
}

glide

-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser** {  
  **[]
VALUES;
public *;
}

好了混淆就到这了 说一下为什么要混淆,首先我们看下面这个图片
这里写图片描述
这是为开启混淆状态下 我在很多地方都做了处理所以大概比混淆完的对了1-2m左右 ,再看混淆之后的
这里写图片描述

这样大概就有所比较了 这就是为什么要开启混淆的原因之一 ,开启混淆之后对反编译 也是一种压力 。具体的就不一一介绍了,网上反编译很多。

资源混淆方案 美团的 和微信的都不错 。我个人使用的是微信的地址也放在下面了
微信混淆方案

好了就写到这了,由于第一写博客 ,别取笑,谢谢大家看到这里。
QQ 群:547839514

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
在Kotlin中进行App瘦身可以采取以下几种方法: 1. 使用ProGuard进行代码混淆和优化。ProGuard是一个Java字节码优化器,可以删除未使用的代码和资源,减小应用的体积。在Kotlin项目中,可以通过在build.gradle文件中配置ProGuard规则来启用它。例如: ```kotlin android { buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } } ``` 2. 使用R8进行代码压缩。R8是Google推出的一种代码压缩工具,可以在编译时删除未使用的代码和资源,减小应用的体积。在Kotlin项目中,默认情况下,R8已经启用,无需额外配置。 3. 优化资源文件。可以通过使用WebP格式替换PNG格式的图片,使用Vector Drawable替换多个分辨率的位图,以及压缩和优化其他资源文件来减小应用的体积。 4. 使用动态特性模块化。将应用的功能模块化,只在需要的时候下载和安装相应的模块,可以减小应用的初始安装包体积。 5. 使用APK分包。将应用的代码和资源分成多个APK文件,按需下载和安装,可以减小应用的初始安装包体积。 6. 使用资源压缩工具。可以使用工具如AndResGuard对资源文件进行压缩和优化,减小应用的体积。 7. 使用动态加载技术。将一部分代码和资源放在服务器上,通过动态加载的方式在运行时下载和加载,可以减小应用的初始安装包体积。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值