配置基本模块

对于大多数应用项目而言,支持 Dynamic Delivery 并不费力。这是因为包含应用的基本 APK 所含的代码和资源的模块是标准应用模块,当您在 Android Studio 中创建新的应用项目时,默认会获得该模块。也就是说,将下面的应用插件应用到其 build.gradle 文件的模块,会提供应用的基本功能的代码和资源。

// The standard application plugin creates your app's base module.
    apply plugin: 'com.android.application'
    

如果您想减小应用的初始下载大小,请一定要注意,此模块中包含的所有代码和资源都包含在应用的基本 APK 中。

基本模块除了为应用提供核心功能,还提供许多影响整个应用项目的编译配置和清单条目。例如,app bundle 的签名由您为基本模块提供的信息决定,而所有应用的 APK 版本则通过基本模块清单中的 versionCode 属性指定。下面将介绍基本模块的其他重要方面。

基本模块清单

应用的基本模块的清单与其他任何应用模块的清单类似。请注意,Google Play 在生成应用的基本 APK 时,会将所有模块的清单合并到基本 APK 的清单中。因此,如果您想要在应用项目中添加动态功能模块,则需要注意关于基本 APK 清单的一些方面:

  • 由于始终会先安装基本 APK,因此基本 APK 应该为应用提供主入口点,也就是说,它应该使用以下 intent 过滤器声明一个 Activity:

    <intent-filter>
             <action android:name="android.intent.action.MAIN" />
             <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        
  • 当按需下载动态功能模块时,搭载 Android 6.0 (API 级别 23)及更低版本的设备需要先重新启动应用,然后才能完成新模块的安装。但是,如果您希望在下载模块后能够立即访问相应模块的代码和资源,则应该在清单中包含对 SplitCompat 库的支持。要了解详情,请参阅访问已下载模块中的代码和资源

  • 同样,在搭载 Android 6.0(API 级别 23)或更低版本的设备上,也需要先重新启动应用,然后平台才能应用新的清单条目。因此,如果在下载动态功能模块后立即需要某些权限或服务,请考虑将它们包含在基本模块的清单中。

  • Android App Bundle 支持未压缩的原生库。因此,如果您在应用中包含原生库,并希望减少磁盘空间占用,请在基本模块清单中包含以下内容:

    <application
            android:extractNativeLibs="false"
            ... >
        

基本模块编译配置

对于大多数现有的应用项目,您无需更改基本模块编译配置中的任何内容。但是,如果您想要在应用项目中添加动态功能模块,则需要注意关于基本模块编译配置的一些方面:

  • 应用签名:您无需在编译配置文件中包含签名信息,除非您想从命令行编译 app bundle。但是,如果包含了签名信息,则应仅将其包含在基本模块的编译配置文件中。如需了解详情,请参阅配置 Gradle 来签署您的应用
  • 代码压缩:如果要为整个应用项目(包括其动态功能模块)启用代码压缩,您必须从基本模块的 build.gradle 文件实现。也就是说,您可以在动态功能模块中包含自定义的 ProGuard 规则,但是动态功能模块编译配置中的 minifyEnabled 属性将被忽略。
  • 忽略 splits:编译 app bundle 时,Gradle 会忽略 android.splits 块中的属性。如果您想控制 app bundle 所支持的配置 APK 的类型,请改为使用 android.bundle停用配置 APK 的类型
  • 应用版本控制:基本模块将确定整个应用项目的版本代码和版本名称。如需了解详情,请转到介绍如何管理应用更新的部分。

重新启用或停用配置 APK 的类型

默认情况下,在您编译 app bundle 时,支持为每一组语言资源、屏幕密度资源和 ABI 库生成配置 APK。如下所示,在基本模块的 build.gradle 文件中使用 android.bundle 块,可以停用对一种或多种配置 APK 类型的支持:

android {
        // When building Android App Bundles, the splits block is ignored.
        splits {...}

        // Instead, use the bundle block to control which types of configuration APKs
        // you want your app bundle to support.
        bundle {
            language {
                // Specifies that the app bundle should not support
                // configuration APKs for language resources. These
                // resources are instead packaged with each base and
                // dynamic feature APK.
                enableSplit = false
            }
            density {
                // This property is set to true by default.
                enableSplit = true
            }
            abi {
                // This property is set to true by default.
                enableSplit = true
            }
        }
    }
    

管理应用更新

借助 Android App Bundle 和 Dynamic Delivery,您可以不必再为上传到 Google Play 的多个 APK 管理版本代码,而只需在应用的基本模块中管理一个版本代码,如下所示:

// In your base module build.gradle file
    android {
        defaultConfig {
            …
            // You specify your app’s version code only in the base module.
            versionCode 5
            versionName "1.0"
        }
    }
    

在您上传 app bundle 后,Google Play 会将您的基本模块中的版本代码分配给它从该 bundle 生成的所有 APK。也就是说,当设备下载并安装您的应用时,该应用的所有拆分 APK 会共用同一版本代码。

如果您想用新的代码或资源更新应用,则必须更新应用的基本模块中的版本代码,并重新编译整个 app bundle。在您将新 app bundle 上传到 Google Play 后,Google Play 会根据基本模块指定的版本代码生成一组新的 APK。随后,当用户更新应用时,Google Play 会向他们提供当前安装在设备上的所有 APK 的更新版本。也就是说,所有已安装的 APK 都会更新为新版本代码。

下载其他配置 APK

上述更新流程存在一种例外情况,即当已安装的应用需要额外的配置 APK 时。设想有用户在下载您的应用之后需要更改其默认系统语言,如果您的应用支持这种语言,设备就会从 Google Play 中请求并下载这些语言资源的额外配置 APK。但是,这种类型的应用更新不会更改应用的版本代码,因此设备只会下载并安装需要的配置 APK。