Android Gradle 经常使用配置

Android Gradle 提供了大量的 DSL 给咱们,以方便咱们根据本身的需求定义相应的配置。html

在这里记录一些经常使用的配置,以方便使用的时候查询。老话说 好记性不如烂笔头。java

关于 Android 项目的配置几乎所有在 android{} 里了,我这里记录的也全是 android 扩展里的配置。android

最上面的两个配置git

//编译的SDK 版本
compileSdkVersion 29
//构建工具版本
buildToolsVersion "29.0.2"
复制代码

defaultConfig 默认配置

defaultConfig{} 是一个配置块,负责定义全部的默认配置。github

若是一个变体没有定义本身的配置,就会默认使用 defaultConfig{} 里的配置。安全

例如 应用 ID ,版本号,版本名等。微信

//默认配置
defaultConfig {
    //应用程序ID,建立时的包名,能够更改。
    applicationId "com.skymxc.example"
    //最小支持的SDK 版本
    minSdkVersion 19
    //目标 SDK 版本
    targetSdkVersion 29
    //应用版本代码,通常用于控制APP的升级。
    versionCode 1
    //应用版本名称,用户能够看到。
    versionName "1.0"

    //配置单元测试使用的 runner
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
复制代码

若是是 library 项目,是没有 applicatoinId 的,可是有一个 consumerProguardFiles 配置markdown

defaultConfig {
    minSdkVersion 19
    targetSdkVersion 29
    versionCode 1
    versionName "1.0"

    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    //配置库本身的 混淆规则,打包时会被打包进 AAR 包里,在 使用这个库的项目里会自动应用库里的混淆规则。
    consumerProguardFiles 'consumer-rules.pro'
}
复制代码

构建类型

构建类型是 Gradle 在构建和打包 APK 时使用的某些配置,一般是为开发生命周期的不一样阶段作配置。app

例如 debug 构建类型 是在开发调试阶段使用的,Gradle 会使用 调试密钥库为其签名; release 构建类型是正式发布打包阶段使用的,会缩减 APK,对 APK 进行混淆处理并使用特定的加密密钥库。dom

Android studio 在建立项目时就会自动建立两个构建类型:debug 和 release 。

虽然没有把 debug 显示在配置脚本上,但会有 debuggable true 配置它。

//构建类型
buildTypes {
    //发布类型
    release {
        //是否启用混淆
        minifyEnabled false
        //proguard 规则文件;
        //getDefaultProguardFile 是 Android 扩展的一个方法,能够获取你的 Android SDK 目录下默认的 proguard 配置文件。
        //在 android-sdk/tools/proguard/目录下,文件名就是传入的 proguard-android-optimize.txt
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}
复制代码

若是你有其余别的配置要在 debug 构建类型上配置,直接定义便可。

例如 我想让 调试版和发布版本都能在一个手机上安装,就能够为 debug 构建类型 增长一个配置,更改它的应用ID

//构建类型
buildTypes {
    //正式发布阶段使用
    release {
        //是否启用混淆
        minifyEnabled false
        //proguard 规则文件;
        //getDefaultProguardFile 是 Android 扩展的一个方法,能够获取你的 Android SDK 目录下默认的 proguard 配置文件。
        //在 android-sdk/tools/proguard/目录下,文件名就是传入的 proguard-android-optimize.txt
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
    //调试阶段使用
    debug {
        applicationIdSuffix ".debug"
    }
}
复制代码

若是你有其余需求是这两个类型不能知足的,也能够添加一个构建类型,自定义其中的配置。

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

        debug {
            applicationIdSuffix ".debug"
            debuggable true
        }

        staging {
            initWith debug
            manifestPlaceholders = [hostName:"internal.example.com"]
            applicationIdSuffix ".debugStaging"
        }
    }
复制代码

关于构建类型可使用的配置,我把经常使用的在这里列一下,方便之后查阅

  • applicationIdSuffix 基于默认 applicationId 追加后缀。(注意也要符合 applicationId 的定义规则) 接受 String 类型的值。
  • debuggable 是否生成一个可调式的 APK。接受 Boolean 类型的值。
  • jniDebuggable 是否生成一个可供调试 Jni(C/C++) 代码的 APK。接受 Boolean 类型的值。
  • minifyEnabled 是否进行代码缩减、启用 Proguard 混淆。接受 Boolean 类型的值。
  • proguardFiles 配置 Proguard 使用的规则文件,能够接受多个文件。
  • shrinkResources 是否清理未使用的资源,默认是 false 。
  • signingConfig 配置使用的签名

更多更详细的属性和方法查看文档吧,传送门

产品变种

产品变种能够理解为应用的不一样版本。例如,农村版和非农版。

能够自定义变种以使用不一样的代码和资源,同时共享和重复利用全部应用版本共用的部分。

产品变种是配置出来的,默认是没有的,有须要则须要本身配置。

产品变种的配置和构建类型的差很少。

  1. 首先要添加一个产品维度,能够理解为一个分组,全部的变种都必须指定一个维度
//变种维度
flavorDimensions "domicile"
复制代码
  1. 添加变种
//变种维度
flavorDimensions "domicile"
//产品变种
productFlavors{
    //农村 变种
    countryside {
        //指定所属维度
        dimension "domicile"
        versionNameSuffix '-countryside'
    }
    //城市 变种
    city {
        dimension "domicile"
        versionNameSuffix '-city'
    }
}
复制代码

defaultConfig{} 中的配置在变种里均可以用,他们两个都是属于 ProductFlavor 类

好比,想给不一样变种设置不一样的版本就能够像上面那样设置。

若是没有在变种中配置任何自定义属性,将使用 defaultConfig 中的配置。

在添加产品变种并同步后, Gradle 就会生成不少任务,基本上都是基于 构建类型+产品变种的方式生成的。

好比 assembleCity、assembleRelease 、assembleCityRelease 等。

assemble 开头的负责生成 APK,好比 assembleCity 运行以后就会生成 City 变种的 release 和 debug 包;

assembleRelease 运行以后就会生成全部变种的的 release 包;

而 assembleCityRelease 运行后只会生成 city 的 release 包。

除了 assemble 系列,还有 compile系列,install系列等等,能够经过命令 gradle tasks 查看。

除了生成任务以外,每一个产品变种和构建类型还能够有本身的 源集、依赖。

这就意味着能够为每一个变种和构建类型定义他们本身的资源、代码以及依赖的第三方库。

关于怎么为构建类型,产品变种定义本身的资源、代码和依赖下面和变体一块儿看。

产品变种也是多渠道构建的基础,一般多渠道构建就是配置多个变种。

构建变体

构建变体是 Gradle 使用一组特定规则将构建类型和产品变种中配置的设置、代码和资源组合在一块儿的结果。

它是构建类型和产品变种的交叉产物,也是 Gradle 用来构建应用的配置。

例如,“city” 产品变种能够定义不一样的功能和设备要求(如自定义源代码、资源和最低 API 级别),而 “debug” 构建类型则会应用不一样的构建和打包设置(如调试选项和签名密钥)。

生成的构建变体是应用的“cityDebug”版本,它由“city”产品变种、“debug”构建类型和 main/ 源代码集中包含的配置和资源组合而成。

你没法直接建立和更改变体,只能经过更改构建类型和产品变种的方式建立和配置变体。

在脚本中添加产品变种后,点击 “Sync Now” 。

同步完成后,Gradle 会根据构建类型和产品变种自动建立构建变体,并按照 <product-flavor><Build-Type> 为其命名。

例如,若是建立了“countryside”和“city”产品变种,并保留了默认的“debug”和“release”构建类型,则 Gradle 会建立如下构建变体:

  • cityDebug
  • cityRelease
  • countrysideDebug
  • countrysideRelease

变体同步出来以后,你能够任意选择要构建运行的变体,只须要在 Android studio 的 Build Variant 窗口选择便可: buildVariants

源代码集

想知道怎么为构建变体配置特定资源,就须要先了解源代码集的概念。

源代码集俗称源集,是 Android studio 按照逻辑关系将每一个模块的源代码和资源进行的分组。

模块的 main 源集包含全部构建变体共用的代码和资源。

其余的源集都是可选的,在添加构建类型,产品变种或者配置构建变体后,Android studio 并不会自动的建立对应的源集。

咱们可根据实际需求自行建立:

  • src/main/ 此源代码集包含全部构建变体共用的代码和资源。

  • src/buildType/ 建立此源代码集可加入特定构建类型专用的代码和资源。

  • src/productFlavor/ 建立此源代码集可加入特定产品变种专用的代码和资源。 注意:若是配置构建以组合多个产品变种,则能够为变种维度之间的每一个产品变种组合建立源代码集目录:src/productFlavor1ProductFlavor2/

  • src/productFlavorBuildType/ 建立此源代码集可加入特定构建变体专用的代码和资源。

例如,若是要生成 “cityDebug” 版本,Android Gradle 须要合并来自如下源集的代码、资源和配置:

  • src/cityDebug (构建变体源集)
  • src/debug (构建类型源集)
  • src/city (产品变种源集)
  • src/main (主源集)

若是不一样源集包含同一资源的不一样版本,Gradle 将按照如下优先顺序决定使用哪个(左侧源集替换右侧源集的文件和设置)

构建变体 > 构建类型 > 产品变种 > 主源代码集 > 库依赖项
复制代码

这样一来,Gradle 在你构建某个变体时就会专门使用对应的源集,同时重复利用与应用的其余版本共用的 Activity、应用逻辑和资源。

在合并多个清单时,Gradle 会使用相同的优先顺序,这样每一个构建变体都能在最终清单中定义不一样的组件或权限。

前面说到为构建类型,产品变种和构建变体建立本身专用的代码和资源就是经过建立各自的源集实现的。

例如,要为 debug 构建类型建立源集,只须要在 src目录下建立一个 debug 目录就行了。

其目录结构也和 main 源集同样就好,java 代码 放在 java 目录里,资源文件文件放在 res 目录里。 debugSourceSet

为产品变种和构建变体建立源集都是同样的,根据名称建立在 src 下建立对应的目录便可。 目录里对资源和代码的组织和 main 源集同样便可。 buildVariant-sourceSet

Android Gradle 提供了一个任务 :sourceSets .

这个任务的输出展现了如何组织每一个构建类型、产品变种和构建变体的文件。 sourceSet

固然这些都不是说定死了, 只不过约定俗成的都这么用,若是你恰恰不想这么用,非想特立独行的改变源集的组织方式也是能够的。自行查阅吧,关键词: “更改默认源代码集配置”

单独配置资源和代码整完了,接着看怎么单独配置依赖,使用第三方库。

在关键字 implementation 前边加上源集的名称就能够了,咱们建立一个应用模块时就能看到这样的例子

// main 源集的依赖
implementation 'androidx.constraintlayout:constraintlayout:1.1.3’
//test 源集的依赖
testImplementation 'junit:junit:4.12’
//androidTest 源集的依赖
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
复制代码

为 debug 构建类型添加依赖

debugImplementation project(":library")
复制代码

为 city 构建变种添加依赖

cityImplementation project(":library")
复制代码

为 cityDebug 构建变体添加依赖

cityDebugImplementation project(":library")
复制代码

配置签名信息

APP 只有在签名以后才能被发布,安装,使用,签名是保护 APP 的一种方式,标记该 APP 的惟一性。

若是签名被恶意篡改,签名就不同了,就没法安装升级了,必定程度上也保护了咱们的 APP。

要对 APP 签名 就须要一个签名证书文件,这个文件怎么建立下面会有。

通常状况下咱们有两种构建类型,debug 和 release ,对应的是开发生命周期中的两个阶段,一般也是只给发布类型的 APP 配置签名信息。

开发调试时,Android studio 已经为咱们提供了一个默认的 debug 签名证书,能够直接使用,无需单独配置,通常位于 $HOME/.android/debug.keystore ;密码为 android 。

Android Gradle 提供了 signingConfigs{} 以便咱们配置签名信息,只须要将签名信息添加在这个代码块里就能够了。

//签名密钥库配置

signingConfigs {
    //配置一个签名信息,名称为 release 
    release {
        storeFile file("myreleasekey.keystore")
        storePassword "password"
        keyAlias "MyReleaseKey"
        keyPassword "password"
    }
}
复制代码

signingConfigs{} 代码块里配置实际是属于 SigningConfig 类型的,一个SigningConfig 就是一个签名配置,能够添加多个签名信息。

其中 release 就是签名配置的名字,代码块里就是对当前签名的配置。

其中经常使用的配置属性以下

  • storeFile 签名证书文件
  • storePassword 签名证书文件密码
  • keyAlias 密钥别名
  • keyPassword 密钥密码

更详细的配置看这里 SigningConfig

一个签名证书里能够有多个 密钥,每一个密钥 都有本身的密码。

Android studio 目前是提供了图形窗口供咱们使用的,在窗口里填好信息就自动配置脚本。 配置签名信息

配置完成 签名后,就能够直接在构建类型或者产品变种的配置中引用了

//城市 变种
city {
    dimension "domicile"
    versionNameSuffix '-city'
    signingConfig signingConfigs.city
}
复制代码

建立签名证书

1.在上方工具条的 build 菜单里选择 Generate Signed Builde /APK 建立签名证书

  1. 选择 APK,点击 next

建立签名证书

  1. 选择 Create New… 进入建立窗口

建立签名证书

  1. 而后就是建立签名证书文件,选择存储路径,设置密码,建立密钥,设置密钥密码,有效期默认就好,其余的信息视本身状况配置。填写完成后,点击 OK 就能够了。

建立签名证书

5.在建立完签名证书后,会自动赋值到以前的窗口,到这里签名证书文件就建立完成了,若是不继续生成 APK 就能够关闭了。

建立签名证书

压缩 APK

在配置了 minifyEnabled true 以后系统默认就会启用 R8 代码压缩,优化,混淆功能。

混淆规则是配置在 proguard-rules.pro 文件里,可经过 proguardFiles 配置更改。

//发布类型
release {
    //是否启用混淆
    minifyEnabled false
    //proguard 规则文件;
    //getDefaultProguardFile 是 Android 扩展的一个方法,能够获取你的 Android SDK 目录下默认的 proguard 配置文件。
    //在 android-sdk/tools/proguard/目录下,文件名就是传入的 proguard-android-optimize.txt
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
复制代码

文件里默认是没有任何规则的,须要自行配置。

Android Gradle 在 3.4.0 以及以后的版本已经默认不使用 Proguard 了,改为 R8 编译器了。

目前 R8 编译器是 支持全部现有的 Proguard 规则文件,因此即便如今不使用 Proguard 了,仍然不须要作什么改变。

关于 Proguard 的规则我在另外一篇文章里详细的解释了一下 Proguard 经常使用规则

R8 编译器几乎和 Proguard 编译过程差很少,在编译时会处理如下任务

  • 代码缩减(即摇树优化):从代码中检测没有使用到的类、字段、方法和属性而后进行安全的移除。这里若是你用到了反射并无直接引用就须要配置保留入口点了。
  • 资源缩减:移除不使用的资源,包括依赖的库中的资源。若是你有动态引用的资源就须要配置哪些资源不能被清除
  • 混淆处理:缩短或者重命名类和成员的名称,从而减少 DEX 文件的大小。
  • 优化:检查并重写代码,进一步缩小 DEX 的大小。例如,若是 R8 检测到 if/else 语句中的 else {} 分之没有采用过,就会把 else {} 移除

在设置了 minifyEnabled true 以后,R8 会从多个地方读取 Proguard 规则文件,这里把 R8 使用的文件来源列一下,了解一下编译器都是从哪里读取配置文件。

来源 位置 说明
Android studio <module-dir>/proguard-rules.pro 在使用 IDE 建立新模块时,IDE 会在该模块的根目录建立 proguard-rules.pro 文件默认是没有任何规则的,须要自行配置。
Android Gradle 插件 由 Android Gradle 插件在编译时生成 Android Gradle 插件会生成 proguard-android-optimize.txt(其中包含了对大多数 Android 项目都有用的规则),并启用 @Keep* 注释。
默认状况下,使用 Android Studio 建立新模块时,模块级 build.gradle 文件会配置此文件。
库依赖项 AAR 库:<library-dir>/proguard.txt
JAR 库:<library-dir>/META-INF/proguard/
若是某个 AAR 库是使用它本身的 ProGuard 规则文件发布的,而且将该 AAR 库做为编译时依赖项归入到项目中,那么 R8 在编译项目时会自动应用其规则。(library 项目里的 consumerProguardFiles 配置)

若是 AAR 库须要某些保留规则才能正常运行,那么使用该库随附的规则文件将很是有用。
也就是说,库开发者已经为你配置好了规则。不过,请注意,因为 ProGuard 规则是累加的,所以 AAR 库依赖项包含的某些规则没法移除,而且可能会影响对应用其余部分的编译。
例如,若是某个库包含停用代码优化功能的规则,该规则会针对整个项目停用优化功能。
Android 资源打包工具 2 (AAPT2) 使用 minifyEnabled true 构建项目后:<module-dir>/build/intermediates/proguard-rules/debug/aapt_rules.txt AAPT2 会根据对应用清单中的类、布局及其余应用资源的引用,生成保留规则。
例如,AAPT2 会为您在应用清单中注册为入口点的每一个 Activity 添加一个保留规则。
自定义配置文件 默认状况下,当使用 Android Studio 建立新模块时,IDE 会建立 <module-dir>/proguard-rules.pro,以便添加本身的规则。 咱们能够添加自定义的配置,R8编译器在编译时会应用这些配置

在配置了 minifyEnabled true 以后, R8 会未来自上述全部可用来源的配置文件组合到一块儿。

若是须要查看 R8 在构建项目时应用的全部规则的完整报告,能够将如下代码加入到模块的 proguard-rules.pro 文件中 路径和名字能够随意更改

-printconfiguration ~/tmp/full-r8-config.txt
复制代码

自动清理未使用的资源

在配置 minifyEnabled true 后 R8 编译器会将代码进行优化缩减混淆,那么资源呢,如何优化呢?

答案是经过配置 shrinkResources 属性

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

经过 shrinkResources true 配置 资源缩减,可将没有使用到的资源自动移除。

配置资源缩减的前提是配置了代码缩减,资源缩减只有在与代码缩减配合才能发挥做用。

在代码缩减器移除掉全部不使用代码后,资源缩减器即可以肯定哪些资源没有被引用,从而安全的移除。

一般咱们在实际开发中会有一些资源是未被直接引用的,存在动态引用或者反射引用的可能,这时就须要配置一些规则,告诉资源缩减器规则内的资源不能被移除。

这就和配置 Proguard 规则保留入口点的道理同样。

配置要保留的资源

若是须要自定义保留或者舍弃特定资源,须要在项目中建立一个包含 <resources> 标记的 XML 文件。

能够在 tools:keep 属性中指定要保留的资源,在 tools:discard 属性中指定要舍弃的资源。

这两个属性都接受以逗号分隔的资源名称列表,也可使用 * 做为通配符。

例如

<resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@mipmap/more,@mipmap/saw" tools:discard="@mipmap/*_2" tools:shrinkMode="strict">
<!--保留 more saw文件-->
<!-- 舍弃 share_2 文件-->
<!-- 严格模式-->
</resources>
复制代码

一般将文件保存在 /res/raw/keeps.xml 。Android Gradle 不会将其打包进 APK,除非你在代码中使用了 R.raw.keeps

上面的三个属性都是可选项,其中 shrinkMode 是配置自动清理资源的模式,有两个可选项

  • strict 严格模式
  • safe 安全模式,默认值

默认值的状况下,对于代码中动态引用资源,资源缩减会自行模糊判断一些资源,看成已使用资源。

例如,下面这个代码,就会把 img_ 为前缀的资源都算已引用资源。

String name = String.format("img_%1d", angle + 1);

res = getResources().getIdentifier(name, "drawable", getPackageName());
复制代码

若是设置了 strict 模式,就必须手动保留了,例如这样

<resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@drawable/img_*" tools:shrinkMode="strict">
</resources>
复制代码

配置生成的 APK 名称

// 配置 APK 名称
android.applicationVariants.all { variant ->
     variant.outputs.all {
        outputFileName = "Example_${variant.flavorName}_${variant.versionCode}_${variant.versionName}.apk"
     }
}
复制代码

动态配置 AndroidManifest 文件

动态配置 AndroidManifest 文件就是在构建过程当中,动态修改 AndroidManifest 文件中的一些内容。

其本质是将构建变量注入到清单文件中。

在清单文件中是可使用 占位符 的,格式是 ${variable} 。

例如经常使用的渠道编号

<!-- 渠道商编号 -->
<meta-data android:name="BaiduMobAd_CHANNEL" android:value="${CHANNEL_NAME}" />
复制代码

定义好占位符以后在 build.gradle 脚本里就能够经过 ProductFlavor 的 manifestPlaceholders 属性进行配置,它接受 Map 类型的参数。

//默认配置,它是一个 ProductFlavor
defaultConfig {
   ······
    manifestPlaceholders = [
            CHANNEL_NAME:"default"
    ]
}
复制代码

实际开发中一般是在产品变种配置渠道,方便往后运营统计查看

//变种维度
 flavorDimensions "channel"

 //产品变种
 productFlavors{

// 为了实践动态配置 AndroidManifest 文件
     huawei {
         dimension "channel"
         manifestPlaceholders = [
                 "CHANNEL_NAME":"华为"
         ]
     }
     mi {
         dimension "channel"
         manifestPlaceholders = [
                 CHANNEL_NAME:"小米"
         ]
     }
}
复制代码

默认状况下是有一个 ${applicationId} 占位符的,它会提供程序的应用ID。

例如

<intent-filter ... >
    <action android:name="${applicationId}.TRANSMOGRIFY" />
    ...
</intent-filter>
复制代码

自定义 BuildConfig

对于 BuildConfig 这个类,应该都很熟悉,这是一个由 构建工具生成的类。 BuildConfig

其中有一个 DEBUG 字段是咱们经常使用的,用于标记是否在开发调试阶段,一般能够用做是否开启日志的开关,剩下的几个字段也都很熟悉,都是 build.gradle 中的配置。

除了构建工具自动生成的字段,也能够经过 ProductFlavor.buildConfigField(String type, String name, String value) 方法自定义 BuildConfig 的字段。

  • 第一个参数是 要生成的字段的类型
  • 第二个参数是 要生成的字段的名字
  • 第三个参数是 要生成的字段的常量值,若是是 String 类型类型的要带上引号。

例如,在 脚本里定义一个字段后

defaultConfig {

    buildConfigField "String" "WEBURL" "\"https://github.com/skymxc\""

}
复制代码

Sync now 以后就会在 BuildConfig 类中看到对应的字段了 自定义BuildConfig

这个配置在构建类型和产品变种里都是能够配置的,利用这个特性,就能够针对不一样的构建类型,不一样的产品变种配置不一样的字段。

例如,分别配置开发和生产环境

defaultConfig {
    buildConfigField "String" "WEBURL" "\"https://github.com/skymxc\""
}

//构建类型
buildTypes {
    //发布类型
    release {
      ·······
        buildConfigField "String","WEBURL","\"https://www.cnblogs.com/skymxc/\""
    }
}
复制代码

也能够针对不一样变种配置

//产品变种
productFlavors{

    //农村 变种
    countryside {
        dimension "domicile"
        buildConfigField "int","type","2"
    }
    
    //城市 变种
    city {
        dimension "domicile"
        buildConfigField "int","type","1"
    }

}
复制代码

Java 编译选项

Android Gradle 提供了一个 compileOptions{} 对 Java 编译进行配置

//Java 编译选项配置
compileOptions {
    // Java 源代码的编码
    encoding = 'utf-8'
    //Java 源代码编译级别
    sourceCompatibility JavaVersion.VERSION_1_8
    //生成的 Java 字节码版本
    targetCompatibility JavaVersion.VERSION_1_8
}
复制代码

经常使用的配置有三个

  • encoding Java源代码的编码
  • sourceCompatibility Java 源代码编译级别
  • targetCompatibility 生成的 Java 字节码版本

关于 64 K 限制

在打包 APK 文件时,Java 源代码被打包成了一个 DEX 文件,这个文件就是优化过的、Dalvik 虚拟机可执行的文件。

Dalvik 虚拟机在执行 DEX 文件的时候,它使用了 short 这个类型来索引 DEX 文件中的方法,这就意味着单个 DEX 文件最多只能是 65535 个,当方法数超过这个数量就会出现编译错误。

由于 1024 * 64 = 65535 也称 64K 限制。

解决办法就是生成多个 DEX 文件,让单个 DEX 文件内的方法数不超过 64K .

在 Android 5.0 及以后的版本使用 ART 了运行时,自己支持从 APK 中加载多个 DEX 文件。

ART 在应用安装时执行预编译,扫描 class[N].dex 文件,并将他们合成一个 .oat 文件,以供 Android 设备执行。

所以,若是你的 minSdkVersion 是 21 或者更高的版本,默认就会启用 MultiDex ,在打包时构建工具会自动生成多个 DEX 文件。

若是 miniSdkVersion 在 20或者更低,就须要在 build.gradle 脚本添加配置 multiDexEnabled true 启用 MultiDex,并添加 MultiDex 支持库。

android {

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

}
dependencies {
  implementation 'com.android.support:multidex:1.0.3’ } 复制代码

若是使用了 androidx ,则使用如下依赖

def multidex_version = "2.0.1"
implementation 'androidx.multidex:multidex:$multidex_version'
复制代码

添加完依赖库以后,还须要替换 Application 类

<?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>
复制代码

若是你有本身的 Application 类,只需继承 MultiDexApplication 便可

public class MyApplication extends MultiDexApplication { ... }
复制代码

若是你不能继承此类,也可在本身的 Application 类的 attachBaseContext() 方法里调用 MultiDex.install(this) 以启用 MultiDex

public class MyApplication extends SomeOtherApplication {

  @Override
  protected void attachBaseContext(Context base) {
     super.attachBaseContext(base);
     MultiDex.install(this);
  }
}
复制代码

注意:在 MultiDex.install() 完成以前,不要经过反射或 JNI 执行 MultiDex.install() 或其余任何代码。MultiDex 跟踪功能不会追踪这些调用,从而致使出现 ClassNotFoundException,或因 DEX 文件之间的类分区错误而致使验证错误。

关于更多 64K 限制的文档能够看这里:启用 MultiDex

学习资料

End

最后把 Android Gradle 的 DSL 查询地址留一下Android Plugin DSL Reference 方便你们随用随查。

我把这些配置和注释都放在了 GitHub 上的一个仓库里,须要时查阅便可 AndroidGradleExample

微信扫一扫,关注个人公众号

佛系编码

相关文章
相关标签/搜索