App包Size优化

一、概述

有研究表明当Apk大小超过100M的时候,有20%用户选择取消应用的下载;大小超过100M的Apk被卸载的几率是大小为10M的Apk的8倍。

Apk瘦身的主要作用有两个:

  • 提高App的下载率和存留率
  • 减少资源检索时间,提高App运行效率

Apk是一种压缩格式,其内部主要组成文件有:res、assets、dex、lib以及AndroidManifest.xml和META-INF等。其中res、assets、dex和lib是主要优化对象。

下面会一一讲解优化方案。


 

二、Apk包size分析

AndroidStudio提供了专门的Apk包size分析工具——Analyze APK。

通过AndroidStudio->build->Analyze APK...打开,选择要分析的APK文件,如下:

Analyze APK

因为项目比较大,远远突破了65535限制,所以配置了multiDexEnabled 为true,dex被拆分为多个文件。

上面Apk的大小已经超过了100M,这里的大小分两种情况:

  • APK size 安装后大小,即安装包解压后实际占用的最小磁盘空间大小。
  • Download size 下载大小,即从应用商店下载所需的流量大小。

 

三、Apk包size优化

删除无用资源

res是包size优化大户,通过Analyze APK分析,res已经占到了Apk大小的80%,优化res的最直接方法就是删除无用资源。

点击Analyze -> Inspect Code...,选择要检测的文件,结果如下:

Inspect Code

Inspect Code检测项非常多,与Apk瘦身相关的主要有“Unused resources” 和 “Unused code”。

更简单的方法是使用Run Inspect by Name,直接指定检测项。点击Analyze -> Run Inspect by Name...,输入Unused resources。

Run Inspect by Name

如果仅仅是删除Unused resources,还有更更简单的方法,直接点击Refactor -> Remove Unused Resources...,所有的无用资源将被清理。

减少打包资源

实际开发中,有些资源即使暂时没有引用,后续可能还会用到,所以不能直接删除,但是打包无用资源又会造成Apk增大。

能否即保留资源,又不打包进Apk呢?答案是肯定的,只需要在build中配置相关项即可。

(1)shrinkResources

通过配置shrinkResources,可以不打包未使用的资源。

buildTypes {
        release {
            multiDexEnabled true
            shrinkResources true
        }
}

注意事项:shrinkResources不是彻底删除无用资源,而是保留文件名,但是没有内容。需要注意的是,如果某个资源只被反射引用(没有直接引用),该资源也会被认为是无用资源,不会保留内容。这样在运行时就会出错甚至崩溃。

(2)resConfigs

通过配置resConfig,可以指定业务需要的语言资源,去除无用语言资源

    defaultConfig {
        applicationId "org.xlgzs.app"
        minSdkVersion 28
        targetSdkVersion 30
        versionCode 1
        versionName '1.0.0'
        resConfigs 'zh-rCN','zh-rHK','zh-rTW'
    }

混淆

混淆可以简化资源路径,比如将res/drawable/activity_settings_lock_icon变为r/d/a,同时让Apk包size减小。

(1)代码混淆

    buildTypes {
        release {
            multiDexEnabled true
            minifyEnabled true //代码混淆
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' //混淆文件
        }
    }

(2)资源混淆(AndResGuard)

 AndResGuard不涉及编译过程,只需输入一个apk,就可以得到一个资源混淆的apk。同时,通过配置签名信息,可自动重新签名并对齐。

首先在build.gradle中引用插件:

apply plugin: 'com.android.application'
apply plugin: 'AndResGuard' //应用AndResGuard插件
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.2.18' //添加AndResGuard依赖
    }
}

在build.gradle(app)中配置AndResGuard:

//-----------------------------配置 AndResGuard-----------------------------
andResGuard {
    mappingFile = null // = file("./resource_mapping.txt") //用于keep住资源的路径的mapping文件所在路径
    use7zip = true    //启用压缩。为true时,useSign必须为true
    useSign = true    // 启用签名。为true时,需要配置signConfig
    keepRoot = false // 为true时,会keep住所有资源的原始路径,只混淆资源的名字
    whiteList = [ //白名单,使用getIdentifier访问的资源需要加入白名单,支持通配符,【+】代表1个或多个,【?】代表0个或1个,【*】代表0个或多个
        "R.mipmap.ic_launcher", "R.drawable.icon",// for your icon
        "R.string.com.crashlytics.*",// for fabric,详见https://docs.fabric.io/android/crashlytics/build-tools.html
        "R.string.google_app_id",// for google-services
        "R.id.*",//任意id
    ]
    compressFilePattern = [ //需要压缩的文件的匹配规则,一般这里不需要动。支持 ? + * 通配符
        "*.png",
        "*.jpg",
        "*.jpeg",
        "*.gif",
        "resources.arsc" //如果不是对APK size有极致要求,不建议压缩此文件
    ]
    sevenzip { //配置7Zip,只需设置 artifact 或 path;支持同时设置,但此时以 path 的值为优先
        artifact = 'com.tencent.mm:SevenZip:1.2.18' 
        //path = "/usr/local/bin/7za"  //path指本地安装的7za(7zip命令行工具)
    }

    // finalApkBackupPath = "${project.rootDir}/final.apk" //可选,指定生成的apk的保存路径
    // digestalg = "SHA-256" //可选: 指定v1签名时生成jar文件的摘要算法,默认值为“SHA-1”
}

编译完后在右侧gradle菜单中多了resguradDebug等task,双击执行即可得到资源混淆的Apk。

 

资源压缩

资源压缩也可以对Apk瘦身起到立竿见影的效果。包括图片压缩,字体压缩,音视频压缩等。

(1)图片压缩

  • 使用TinyPNG等工具压缩图片大小
  • 纯色类Icon使用SVG
  • 两种以上颜色使用WebP,达不到效果再使用PNG
  • 无alpha通道考虑使用JPG代替PNG

(2)音视频压缩

  • 以有损格式代替无损格式
  • 推荐使用ogg

(3)字体压缩

利用FontZip等工具对字体文件优化,删除无用字体。

 

posted @ 2021-01-22 17:21  西贝雪  阅读(483)  评论(0编辑  收藏  举报