Android APK瘦身、混淆、分包

前言
APK的瘦身,即是让我们最终打包出的apk体积更小。这次主要结合我目前的项目,系统整理一下瘦身、混淆相关的知识。
正文
开始进入正题吧!为什么瘦身、混淆和分包放在一起聊呢?因为这三者之间有着重要的联系。
官网developer.android在介绍代码压缩时,提及代码压缩,是对Android项目中出现的65536问题的一种变通的解决方式,所以我们就先了解一下这个65536方法数限制(64k引用限制)问题。
一、65536(64k引用限制)
随着我们项目内容代码量的不断增加,包括引用的一些三方库越来越多,最终,就会项目就会报出以下错误:

Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536

或者使用较新版本构建系统时

trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.

这两种error都有个明显的数字65536,这个数字

代表的是单个 Dalvik Executable (DEX) 字节码文件内的代码可调用的引用总数

关于这个65536产生的根本原因,可以看一下这篇文章关于65536方法限制引发的思考,仅供参考。
如果我们项目的minSdkVersion 为21(Android 5.0)以下,所用的虚拟机为Dalvik,Dalvik 限制应用的每个 APK 只能使用单个 classes.dex 字节码文件,这时的APK瘦身就显得尤为重要了,如果通过压缩代码减少引用方法数,就可以暂时性解决这个问题。
为什么说是暂时性呢?这种解决办法,治标不治本啊,项目代码还是会不断增加,总有一天还是会报这个错误的。这时候,我们就需要执行分包了,执行分包之后生成的apk解压之后可以发现,包含了不止一个dex文件:
在这里插入图片描述

那么,如何执行分包呢?
(1)如果项目 minSdkVersion 设置为 21 或更高值,只需在模块级 build.gradle 文件中将 multiDexEnabled 设置为 true:

android {
    defaultConfig {
        ...
        minSdkVersion 21 
        targetSdkVersion 28
        multiDexEnabled true
    }
    ...
}

(2)如果minSdkVersion 的值为21以下,则需要引入Dalvik可执行文件分包支持库,修改模块级build.gradle,并且添加依赖,如下:

android {
    defaultConfig {
        ...
        minSdkVersion 15 
        targetSdkVersion 28
        multiDexEnabled true
    }
    ...
}

dependencies {
  compile 'com.android.support:multidex:1.0.3'
}

修改完成后,还需要设置清单文件中 标记中的 android:name:属性,这里又存在3种修改方式:
1.如果项目中没有替换过Application类,可以直接将android:name属性的值用MultiDexApplication替换,如下

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">
    <application
            android:name="android.support.multidex.MultiDexApplication" >
        ...
    </application>
</manifest>

2.如果项目中用的是自己重新定义的Application,则将其直接继承MultiDexApplication(如果可行),如下:

public class MyApplication extends MultiDexApplication { ... }

3.如果用的是自己重新定义的Application,但又无法更改基本类,则可以改为替换 attachBaseContext() 方法并调用 MultiDex.install(this) 来启用可执行文件分包操作:

public class MyApplication extends SomeOtherApplication {
  @Override
  protected void attachBaseContext(Context base) {
     super.attachBaseContext(base);
     MultiDex.install(this);
  }
}

二、代码压缩
到这里,才算是真正开始介绍到瘦身的核心部分,代码压缩和后面的资源压缩。
如果项目挺大的话,相信很多同学可能会见过这样的代码:

dexOptions {
        javaMaxHeapSize "4g"
    }

javaMaxHeapSize设置堆内存大小,就是因为编译的java代码过多,通常是方法数超过65535后使用了分包的机制,gradle在编译的时候由于编译的内存需要不能满足,所以会报错,进而需要设置提高分配的最大堆内存。
代码压缩、混淆,通过Proguard工具实现。ProGuard 会检测和移除封装应用中未使用的类、字段、方法和属性,包括自带代码库中的未使用项,ProGuard 还可优化字节码,移除未使用的代码指令,以及用短名称混淆其余的类、字段和方法。
可见,Proguard工具的功能不仅仅是压缩代码,还有一个重要的功能,是保障我们APP的代码不会被轻易反编译,即混淆功能。下面,我们就介绍Proguard的用法。
代码先行:

android {
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                    'proguard-rules.pro'
        }
    }
    ...
}

配置build.gradle 如上,首先设置minifyEnabled 为true,getDefaultProguardFile是获取默认设置,就是后面proguard-android.txt文件中的设置,此文件的位置如下:

在这里插入图片描述

在SDK的tools文件夹下的proguard下,要想做进一步的代码压缩,可以使用位于同一位置的 proguard-android-optimize.txt 文件。它包括相同的 ProGuard 规则,但还包括其他在字节码一级(方法内和方法间)执行分析的优化,以进一步减小 APK 大小和帮助提高其运行速度。
然而,一般我们不会去使用proguard-android-optimize.txt 文件,用默认的设置就够了。原因我们来看一下,下面是proguard-android-optimize.txt 文件内容的截图
在这里插入图片描述
proguard-android-optimize.txt与默认的proguard-android.txt的区别主要在于它使用了optimize(优化)功能,上面描述说,优化可能会造成一些潜在风险,不能保证在所有版本的Dalvik上都正常运行,所以我们一般用默认的就可以了。
下面,就是另一个文件的配置了,十分重要,proguard-rules.pro
在这里插入图片描述
对于这个文件配置的详细信息,网上有好多,因为编译过程中有些方法或者类名需要通过字段名去找,如果改变了,就会找不到,所以才会有保留这个做法,这里推荐两篇blog,里面有一些通用的混淆配置,比如四大组件、本地native方法、注解等等,除此之外,就是我们自己项目导入的三方配置,如果没有针对性的做保留处理,就会cant resolve method了。
Android安全攻防战,反编译与混淆技术完全解析
Android混淆
里面关于配置文件中常用的通配符的意义,常用的类保留都有详细的解释。做好这些配置后,打出的包,再去反编译,就会发现类名方法名都会被改变。

三、压缩资源
(1)

android {
    ...
    buildTypes {
        release {
            shrinkResources true
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                    'proguard-rules.pro'
        }
    }
}

在minifyEnabled 的旁边,设置了shrinkResources true。注意,资源压缩只与代码压缩协同工作。代码压缩器移除所有未使用的代码后,资源压缩器便可确定应用仍然使用的资源。这在您添加包含资源的代码库时体现得尤为明显 - 您必须移除未使用的库代码,使库资源变为未引用资源,才能通过资源压缩器将它们移除。
如果没有设置minifyEnabled ,就会报如下错误。Removing unused resources requires unused code shrinking to be turned on
在这里插入图片描述
为了我们的项目不那么臃肿,方便coding,可以通过一些工具随时删除一些我们迭代时遗留的无用资源,图片,layout等。
在这里插入图片描述
在这里插入图片描述
这里介绍一个Android Studio自带的Android Lint工具,输入Unused resources后,下方会列出一些未被使用的资源文件,我们可以及时删除。虽然这些未被使用的资源,在前面设置了代码压缩资源压缩之后,不会被打包进我们的apk,但我们平时也要养成整理代码的习惯,使我们的代码结构更清晰。
这个Android Lint工具是不会扫描assets目录下的文件的,注意一下。我平时在用假数据的时候,会把json文件放到assets目录下。
(2)有些比较大的图片资源,比如启动图之类的大图,我们可以在使用之前进行压缩。这里介绍一个网站TinyPng,非常好用,可以将图片大小压缩一倍以上,而视觉上不会损失太大,几乎一样。
在这里插入图片描述
在这里插入图片描述
(3)使用webp格式
WebP格式,谷歌(google)开发的一种旨在加快图片加载速度的图片格式。图片压缩体积大约只有JPEG的2/3,并能节省大量的服务器宽带资源和数据空间
相对于jpg、png,webp作为一种新的图片格式,限于android的支持情况暂时还没用在手机端广泛应用起来。从Android 4.0+开始原生支持,但是不支持包含透明度,直到Android 4.2.1+才支持显示含透明度的webp,使用的时候要特别注意)
点击图片右键生成,用谷歌浏览器才能打开。用的太少,作为一个了解扩展吧。
在这里插入图片描述

全部内容结束。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值