Skip to content

Latest commit

 

History

History
292 lines (215 loc) · 14.2 KB

File metadata and controls

292 lines (215 loc) · 14.2 KB

好的,我们来彻底讲清楚 AAB 是什么,以及它为什么重要。

一、AAB 是什么?

AAB 的全称是 Android App Bundle。你可以把它理解为一个**“发布格式”** 或者一个**“数字盒子”**。

  • 传统方式:你开发完应用后,打包成一个 APK 文件,然后把这个完整的 APK 上传到应用商店。
  • AAB 方式:你开发完应用后,打包成一个 AAB 文件,然后把这个“盒子”上传到应用商店。

这个“盒子”里包含了你应用的所有编译好的代码、资源、库文件等,但它不是一个可以直接安装的文件。

二、AAB 的核心工作原理:动态分发

当用户从 Google Play 商店(或其他支持 AAB 的商店)下载你的应用时,商店会打开你这个 AAB“盒子”,然后根据用户的具体设备,动态地组装并生成一个最优化的 APK,再下发给用户。

这个“动态组装”主要基于以下几点:

  1. 语言资源:如果你的应用支持中文、英文、日文,一个法国用户下载时,商店只会打包法语相关的字符串和资源给他,而不会包含他永远用不到的中文和日文资源。
  2. 屏幕密度资源:如果你的应用为不同分辨率的屏幕(如 hdpi, xhdpi, xxhdpi)准备了不同的图片,一个 xxhdpi 屏幕的手机用户下载时,商店只会打包 xxhdpi 的图片给他,而不会包含 hdpi 和 xhdpi 的图片。
  3. CPU 架构库:如果你的应用使用了原生 C/C++ 库(如 armeabi-v7a, arm64-v8a, x86),一个 arm64-v8a 架构的手机用户下载时,商店只会打包 arm64-v8a 版本的库给他,而不会包含 x86 的库。

简单比喻:

  • APK 就像一件“均码”的 T 恤,无论高矮胖瘦,所有人都拿到同一件。
  • AAB 就像一家“高级定制裁缝店”,你把自己的身材数据(设备信息)给店家(Google Play),店家从布料、线团(AAB 文件)中为你量身定制一件最合身的 T 恤(优化后的 APK)。

三、AAB 有什么用处?(带来的好处)

这种“动态分发”机制带来了巨大的好处:

1. 显著减小应用体积(对用户最直观的好处)

这是 AAB 最大的优势。根据 Google 的数据,平均可以比通用 APK 减小 15% 的体积,对于大型应用,减少 50% 以上也很常见。

  • 用户节省了手机存储空间和流量。
  • 转化率提升:应用体积越小,下载意愿越高,安装转化率也越高。

2. 简化开发者的发布流程

  • 不再需要构建多个 APK:在过去,为了减小体积,开发者可能需要为不同屏幕密度或 CPU 架构构建多个 APK。现在,只需要上传一个 AAB 文件,Google Play 会为你处理所有复杂的分发逻辑。
  • 支持动态功能模块(Dynamic Feature Module):这是 AAB 架构下的一个强大功能。你可以将应用的某些非核心功能(如高级支付、AR 特效)做成独立的模块。用户可以在主应用安装后,按需下载这些模块(称为 "On-Demand Delivery")。这进一步减小了应用的初始安装包大小。

3. 更灵活的交付方式

除了按需交付功能模块,还支持:

  • 条件交付:根据用户所在国家/地区或设备特性来交付特定内容。
  • 即时体验:用户可以通过 Google Play Instant 无需安装即可试玩部分应用功能。

四、AAB 与 APK 的关系

这是一个非常重要的概念:

  • AAB 是给商店的“发布包”。
  • APK 是给用户的“安装包”。
  • AAB 是“因”,APK 是“果”。商店用 AAB 生成 APK。

开发者打交道的是 AAB,用户安装的永远是 APK。

五、现状与要求

  • Google Play 强制要求:自 2021 年 8 月起,新发布的应用必须使用 AAB 格式。现有的 APK 应用更新时不受影响,但鼓励迁移。
  • 其他应用商店:许多主流的第三方安卓应用商店(如三星 Galaxy Store、华为 AppGallery、小米应用商店等)也开始支持 AAB 格式的上传和分发。

总结

特性 APK AAB
全称 Android Package Android App Bundle
本质 安装包 发布包/构建包
分发方式 通用,一个包适应所有设备 动态,为每个设备生成定制包
文件大小 较大(包含所有资源) 较小(按需分发,平均减小15%)
开发者工作 可能需要管理多个APK 只需上传一个AAB文件
支持动态功能 不支持 支持

一句话总结:AAB 是 Google 推出的新一代 Android 应用发布格式,它通过“动态分发”机制,显著减小了用户下载的应用体积,同时简化了开发者的构建和发布流程。

好的,实现多渠道打包是 Android 开发中非常常见的需求,主要用于将同一套代码发布到不同的应用市场(渠道),并能够追踪每个渠道的数据(如下载量、用户行为等)。

下面我将从原理、主流方法到具体实现,为你详细讲解如何实现多渠道打包。

一、核心原理

无论使用哪种方法,其核心原理都是一致的:

在 APK/AAB 文件中放入一个唯一的、可识别的标识符(渠道号),应用在运行时读取这个标识符,并在上报数据时将其一并上传。

在 Android 中,最方便的位置就是在 AndroidManifest.xml 的 <application> 标签下定义一个 <meta-data>。

二、主流方法详解

随着 Android 开发工具的演进,多渠道打包的方法也发生了变化。以下是目前最主流和推荐的方法:

方法一:使用 Android Gradle Plugin 的 Product Flavors(最经典、最灵活)

这是官方支持的方式,功能强大,不仅可以设置渠道,还可以用来编译不同代码、资源、配置的版本(如免费版/付费版)。

实现步骤:

  1. 在 app/build.gradle 中配置 productFlavors

    android {
        compileSdkVersion 33 // 使用你的编译SDK版本
        defaultConfig {
            ...
            // 这里可以定义所有 Flavor 共享的配置
        }
    
        // 配置产品风味维度(Flavor Dimensions)
        // 如果你的多渠道没有太大差异,一个维度就够了。
        flavorDimensions "channel"
        productFlavors {
            huawei {
                dimension "channel"
                // 你可以为不同渠道设置不同的应用ID(可选)
                // applicationIdSuffix ".huawei"
                // 或者设置不同的版本名(可选)
                // versionNameSuffix "-huawei"
            }
            xiaomi {
                dimension "channel"
            }
            oppo {
                dimension "channel"
            }
            vivo {
                dimension "channel"
            }
            // 如果需要,可以一次定义很多个
            // 使用循环批量创建(适用于渠道非常多,且配置简单的情况)
            // ["huawei", "xiaomi", "oppo", "vivo", "tencent", "baidu", "ali"].each { name ->
            //     create(name) {
            //         dimension "channel"
            //     }
            // }
        }
    }
  2. 在 AndroidManifest.xml 中定义占位符

    在 application 节点下,添加一个 meta-data,其 value 使用 Gradle 的占位符。

    <manifest ...>
        <application ...>
            ...
            <!-- 渠道信息 -->
            <meta-data
                android:name="CHANNEL"
                android:value="${CHANNEL_VALUE}" />
        </application>
    </manifest>
  3. 在 productFlavors 中为占位符赋值

    回到 app/build.gradle 文件,为每个 flavor 指定 CHANNEL_VALUE 的值。

    android {
        ...
        productFlavors {
            huawei {
                dimension "channel"
                // 将 "huawei" 这个字符串赋给清单文件中的 CHANNEL_VALUE 占位符
                manifestPlaceholders = [CHANNEL_VALUE: "huawei"]
            }
            xiaomi {
                dimension "channel"
                manifestPlaceholders = [CHANNEL_VALUE: "xiaomi"]
            }
            oppo {
                dimension "channel"
                manifestPlaceholders = [CHANNEL_VALUE: "oppo"]
            }
            vivo {
                dimension "channel"
                manifestPlaceholders = [CHANNEL_VALUE: "vivo"]
            }
        }
    }
  4. 在 Java/Kotlin 代码中读取渠道信息

    public static String getChannel(Context context) {
        try {
            PackageManager pm = context.getPackageManager();
            ApplicationInfo appInfo = pm.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
            return appInfo.metaData.getString("CHANNEL");
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return "unknown"; // 默认值
    }
    fun getChannel(context: Context): String {
        return try {
            val appInfo = context.packageManager.getApplicationInfo(context.packageName, PackageManager.GET_META_DATA)
            appInfo.metaData.getString("CHANNEL") ?: "unknown"
        } catch (e: PackageManager.NameNotFoundException) {
            e.printStackTrace()
            "unknown"
        }
    }
  5. 打包

    • 在 Android Studio 中:点击 Build -> Select Build Variants,在侧边栏选择你想要构建的渠道和构建类型(如 huaweiDebug, xiaomiRelease)。
    • 使用命令行:./gradlew assembleHuaweiRelease 会打包华为渠道的 Release 版。./gradlew assembleRelease 会打包所有渠道的 Release 版。

优点:

  • 官方支持,稳定可靠。
  • 功能强大,不仅可以改渠道,还能定制代码、资源、配置。
  • 与构建系统完美集成。

缺点:

  • 渠道非常多时(如上百个),Gradle 配置会略显冗长(但可以用循环解决),且每次构建都会遍历所有渠道,速度较慢。

方法二:使用 Walle(瓦力)或 Packer-Ng(针对 APK,已过时但可了解)

这类工具的原理是:先打出一个通用的 APK(不包含渠道信息),然后通过工具向 APK 的特定位置(如 ZIP Comment)写入渠道信息。这是一个“后处理”的过程。

注意:由于 Google Play 要求上传 AAB(Android App Bundle)格式,APK 的很多后处理方案已经不再主流,但对于国内其他市场仍有意义。Walle 也支持 AAB。

以 Walle 为例:

  1. 添加依赖:在项目的 build.gradle 中添加 walle 插件依赖。
  2. 应用插件:在 app/build.gradle 中应用 walle 插件。
  3. 配置渠道:创建一个 channel.txt 文件,里面每行一个渠道名。
  4. 打包:执行 ./gradlew clean assembleReleaseChannels,它会生成一个通用 APK,然后自动为 channel.txt 里的每个渠道生成一个对应的渠道包,速度极快。

优点:

  • 速度极快:无论多少渠道,都只需要构建一次 APK。
  • 非常适合渠道极多(成百上千)的场景。

缺点:

  • 需要引入第三方插件。
  • 随着 AAB 的普及,其重要性在下降。

方法三:针对 AAB 的官方方案 — 使用 bundletool 和 base 模块的 Manifest 占位符

这是目前面向 Google Play 和其他支持 AAB 的市场最推荐的方案。

实现步骤:

  1. 在 app/build.gradle 中配置 productFlavors(同方法一) 但这次我们不需要在 AndroidManifest.xml 中写占位符。

  2. 在 build.gradle 中为每个 flavor 设置 manifestPlaceholders(同方法一)

  3. 使用 bundletool 构建 APKs bundletool 是 Google 官方用于构建和操作 AAB 文件的命令行工具。

    • 首先,使用 Android Studio 生成一个通用的 AAB 文件(Build -> Build Bundle(s) / APK(s) -> Build Bundle(s))。
    • 然后,使用 bundletool 从这个 AAB 文件生成针对不同渠道的 APK 集合(APK Set)。
    bundletool build-apks --bundle=/path/to/myapp.aab --output=/path/to/myapp.apks --connected-device --ks=/path/to/keystore.jks --ks-pass=pass:your_password --ks-key-alias=your_alias --key-pass=pass:your_key_password
    • 要为特定渠道生成 APK,可以使用 --device-spec 来指定设备配置,但更常见的做法是直接安装到设备,bundletool 会自动选择最优的 APK。
  4. 安装到设备

    bundletool install-apks --apks=/path/to/myapp.apks --device-id=your_device_id

核心思想:AAB 是上传到商店的“原材料”,商店会根据你的 productFlavors 配置和用户设备,动态生成最优的 APK。渠道信息在构建 AAB 时就已经被包含在 base 模块的 Manifest 中了。

三、最佳实践与建议

  1. 新项目首选 productFlavors + AAB:这是未来的方向,尤其如果你要上架 Google Play。
  2. 国内市场:很多国内市场也开始支持 AAB。如果仍需 APK,可以继续使用方法一(productFlavors),如果渠道数量爆炸式增长,可以考虑 Walle。
  3. 渠道统计:在 Application 的 onCreate() 方法中读取渠道号,并初始化你的统计 SDK(如友盟、Firebase Analytics),将渠道号作为参数传入。
  4. 自动化:将打包脚本集成到你的 CI/CD 流程中(如 Jenkins、GitLab CI),实现一键打包所有渠道。

总结对比

方法 原理 适用格式 优点 缺点
Product Flavors 编译时通过Gradle生成不同包 APK, AAB 官方支持,功能灵活强大 渠道极多时构建慢
Walle/Packer-Ng 对APK进行后处理,写入渠道 APK 速度极快,适合海量渠道 第三方插件,AAB时代作用减弱
AAB + bundletool 通过AAB的配置动态生成APK AAB 官方未来方案,面向Google Play 流程相对复杂,依赖商店支持

希望这份详细的指南能帮助你顺利实现多渠道打包!