认识 Android App Bundle

一、背景和目的

从 2021 年下半年开始,Google 要求新应用需要使用 Android App Bundle 才能在 Google Play 中发布。使用aab格式进行发布是一个不得不面对的问题。

那什么是 Android App Bundle呢?
Android App Bundle 是一种发布格式,其中包含应用的所有经过编译的代码和资源,它会将 APK 生成及签名交由 Google Play 来完成。

AAB 并不是一个插件化框架,它利用的是 Android Framework 提供的 split apks 技术来完成的,而所有安装 split apk 工作均是通过 IPC 交由 google play 完成,而不是国内插件化技术的反射代理 hook

总结起来就是:
1)Google官方插件化技术
2)通过aab格式进行动态分发
3)借助 Split Apk 完成动态加载

二、APP Bundle 与 APK 有什么不同

.aab文件 和 apk一样也是一个zip的文件, 不一样的是apk可以直接安装到手机,而.aab文件不能直接安装,需要通过Google Play 或者 bundletool 工具 生成优化后的apk才能安装到手机

Google Play 会根据.aab文件生成优化的 APK 并将其提供给设备进行安装,这也就是为什么Google需要开发者上传签名信息的原因。

三、APP Bundle包的结构

image.png

base/:应用程序的基本模块始终包含在base应用程序包的目录中
res/,lib/和assets/:这些目录与典型APK中的目录相同。
dex/:与APK不同,app bundle 将每个模块的DEX文件存储在这个单独的目录中。
root/:应用程序包的目录可能包含应用程序加载的基于Java的资源 Class.getResource(),这些文件稍后会重新定位到应用基础APK的根目录以及Google Play生成的每个多APK。

resources.pb:描述每个模块中的代码和资源,这在针对不同设备配置优化APK时非常有用。
BundleConfig.pb:提供有关包本身的信息,例如用于构建应用程序包的构建工具的版本。

四、如何使用APP Bundle

1.所需要的工具

1).Android Studio,确保Android Studio版本大于3.2,且gradle版本不小于3.2.1
2).bundletool,用来格式转换,需要到github上下载
bundletool工具参考文档:(https://developer.android.com/studio/command-line/bundletool?hl=zh-cn)

2.在app中的build.gradle文件中的android闭包中添加如下代码
android {
    ......
    bundle {
        density {
                 enableSplit true
        }
        abi {
                 enableSplit true
        }
        language {
                enableSplit true
        }
    }
}

可以看出splits就是对各个moudle的在资源维度,ABI维度和Language维度的拆分。可以通过配置,来配置是否启用
构建多APK官方参考文档

3.生成aab格式

通过Build->Generate Signed Bundle/Apk->Android App Bundle,然后设置签名,以及要build的版本,等待一会就可以生成一个xxx.aab文件,它是一个压缩包,但还不能直接安装,要转为apk形式

4.用bundletool转为apks压缩包:
java -jar bundletool-all-1.8.0.jar build-apks  --bundle=demo.aab --output=demo.apks

如何根据aab文件生成一个全量apk?
bundletool 只生成一个包含应用的所有代码和资源的 APK,以使该 APK 与应用支持的所有设备配置兼容,使用 universal 参数。

java -jar bundletool-all-0.10.3.jar build-apks --bundle=app.aab --output=all.apks  --mode=universal
5.可以通过install-apks命令来安装apks

java -jar bundletool-all-0.10.3.jar install-apks --apks=my_app.apks

6.bundletool注意事项
feature模块被整合到base中

<dist:removable value="true | false" />
Android Gradle 插件 4.2开始支持此属性

bundletool v1.0 开始,如果是安装时分发的应用,bundletool 会在根据"dist:removable "决定是否将安装模块整合到base模块中。

出现 base_master_2.apk

构建 Android App Bundle 时,由以 Android 6.0(API 级别 23)或更高版本为目标平台的 App Bundle 生成的 APK 现在默认包含原生库的未压缩版本。这项优化无需设备创建库的副本,因此减少了应用占用的存储空间。如果您想要停用此优化,请在 gradle.properties 文件中添加以下代码。只有当您想要针对某个功能模块停用整合功能时,才需要在清单中设置此值。
android.bundle.enableUncompressedNativeLibs = false

如果显示错误,可能需要你打开实验特性开关
android.experimental.enableNewResourceShrinker = true

如果动态化模块上传没有没检测可能是动态化模块中manifest文件中没有添加application模块

五、APP Bundle 应用模块化

Android App Bundle 支持模块化,通过Dynamic Delivery with split APKs,将一个apk拆分成多个apk,按需加载(包括加载C/C++ libraries)

1.Bundle的 应用模块化有什么优点和缺点

优点:
1)并行开发:将应用拆分不同的模块,各个团队开发自己负责的模块。
2)加快编译时间:Gradle 的并行项目执行优化,编译系统就能够并行地编译多个模块,从而显著减少编译时间。
3)动态模块按需加载减少apk大小。

缺点:
目前市场上,App Bundles方案依托与Google Play应该才能做到业务模块的按需加载,其他的应用商店还没出现类似的功能。

2.Apks中的Apk分类:
13632959-0171e4504d1e023e.webp.jpg

1.Base Apk:
首次安装的apk,公共代码和资源,所以其他的模块都基于Base Apk;

2.Configuration APKs:
native libraries 和适配当前手机屏幕分辨率的资源;

3.Dynamic feature APKs:
不需要在首次安装就加载的模块。

3.如何创建动态模块

可参考官方文档[https://developer.android.google.cn/guide/app-bundle/at-install-delivery?hl=zh-cn]

  1. 从菜单栏中依次选择 File > New > New Module
  2. Create New Module 对话框中,选择 Dynamic Feature Module,然后点击 Next
  3. Configure your new module 部分中,完成以下操作:
    1. 从下拉菜单中选择应用项目的 Base application module
    2. 指定 Module name。IDE 会使用此名称在 Gradle 设置文件中将该模块标识为 Gradle 子项目。当您构建 app bundle 时,Gradle 会使用子项目名称的最后一个元素在功能模块的清单中注入 <manifest split> 属性。
    3. 指定该模块的 package name。默认情况下,Android Studio 会建议一个软件包名称,该名称由基本模块的根目录软件包名称和您在上一步中指定的模块名称组合而成。
    4. 选择您希望该模块支持的 Minimum API level。此值应与基本模块的值一致。
  4. 点击 Next
  5. 在 Module Download Options 部分中,配置选项。
  6. 点击 Finish
4.Dynamic Feature moudle相关配置

gradle相关:

android{
   dynamicFeatures = [':dynamicfeature']
}

//dynamicfeature/build.gradle
//plugins 在这里等同与apply plugin: 'com.android.dynamic-feature'
plugins {
    //  申明说我时一个Dynamic Feature Module
    id 'com.android.dynamic-feature'
}
android{
   defaultConfig {
      // 这里是你的模块应用id,跟清单文件中的package对应,dynamicfeature为模块名
      applicationId "com.example.dynamicfeature"
   }
}
dependencies {
    // 自动新增此依赖,因为所有的Dynamic Feature Module都是基于base module的
    implementation project(":app")
}

Manifest文件: 官方文档[https://developer.android.com/guide/app-bundle/dynamic-delivery?hl=zh-cn]
需要Manifest 声明是安装时还是使用时进行部署

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:dist="http://schemas.android.com/apk/distribution"
    package="com.example.dynamicfeature">  <!-- 我们的applicationId -->
        
    <!-- dist:instant 是否免安装 -->
    <!-- dist:title 模块名标识 -->
  
    <dist:module
        dist:instant="false"
        dist:title="@string/title_dynamicfeature">
  <!-- dist:delivery 层级用于包裹 -->
        <dist:delivery>
            <!-- dist:on-demand 指定模块按需下载 -->
            <dist:on-demand />
            <dist:install-time>
              <!-- dist:conditions 用于包裹条件 -->
                  <dist:conditions>
                <!-- 指定中国和香港地区不能下载该模块 -->
                <dist:user-countries dist:exclude="true">
                  <dist:country dist:code="CN"/>
                  <dist:country dist:code="HK"/>
                </dist:user-countries>
                <!-- 指定华为手机才支持该模块 -->
                    <dist:device-feature dist:name="android.hardware.camera.ar"/>
                <!-- 指定最小sdk21,最大sdk30 -->
                <dist:min-sdk dist:value="21"/>
                            <dist:max-sdk dist:value="30"/>
                    </dist:conditions>
            </dist:install-time>
        </dist:delivery>
        <dist:fusing dist:include="true" />
    </dist:module>
</manifest>
5.如何根据App bundle 重构项目
5.1 App bundles项目依赖结构
image.png

从上图可以看出,使用AAB,项目的依赖结构发生了变化。有base和feature模块,在base中无法直接引用feature模块的类,feature模块可以直接依赖base模块。

5.2.基于动态化模块进行组件拆分原则
image.png

我们可以按照组件职责划分
Base-App:作为支撑业务组件、业务基础组件,依赖Common库和其他常用依赖,为feature-module提供需要的基本功能。
bridge:为module间提供通信接口。
Feature Module:这个是进行拆分的功能组件。
Common库:为Base-App提供相应的功能。和feature module不存在依赖关系,业务基础组件也不存在依赖关系。

5.3.依赖关系
image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容