针对不同的 API 级别创建多个 APK

如果您将应用发布到 Google Play,您应构建并上传 Android App Bundle 文件。当您执行此操作时,Google Play 会针对每个用户的设备配置自动生成并提供经过优化的 APK,以便他们仅下载运行您的应用所需的代码和资源。如果您不将应用发布到 Google Play,那么发布多个 APK 很有用,但您必须自行构建和管理每个 APK 并为其签名。

如果您要开发 Android 应用,以便充分利用 Google Play 上的多个 APK, 一定要从一开始就采取一些良好的做法, 进行深入的分析本课将介绍如何为 不同的应用,每个应用的 API 级别范围略有不同。您还将获得一些工具 来尽可能轻松地维护多 APK 代码库。

确认您需要多个 APK

尝试创建可在多代 Android 您自然希望自己的应用能够利用新设备、 同时又不会牺牲向后兼容性。乍一看,这似乎像是多个 APK 支持团队是最好的解决方案,但事实往往并非如此。使用单个 APK 而是提供了多 APK 开发者指南的一些实用信息, 只需使用单个 APK 即可完成此操作,包括使用我们的支持库。您还可以了解如何 在单个 APK 中编写仅在某些 API 级别运行的代码,而无需借助于 计算开销非常大的技术,如来自 的反射 这篇文章

如果您可以管理的话,将应用限制在单个 APK 中会有多个 优势,包括:

  • 发布和测试更加轻松
  • 只需要维护一个代码库
  • 您的应用可以适应设备配置的变化
  • 可以跨设备执行应用恢复
  • 您不必担心市场偏好和“升级”带来的行为从一个 APK 复制到 或者哪个 APK 与哪类设备搭配使用

本课程的其余部分假定您已经了解了相关主题,并认真学习了 并且确定多 APK 是适合您的应用的正确途径 应用。

制作您的需求图表

首先,创建一个简单的图表来快速确定您需要多少个 APK 以及使用哪种 API 如需便利参考,请参阅 API 文档中的平台版本页面, Android 开发者网站提供有关运行给定目标的活跃设备的相对数量数据 Android 平台版本。此外,虽然一开始听起来很简单,但可以留意下系列中的哪个元素 每个 APK 目标的 API 级别数量会很快变得困难,尤其是 存在一些重叠(通常会出现)。幸运的是,你可以轻松快速地绘制出需求图表 并且方便以后参考

要创建多 APK 图表,请先创建一行单元格,用于表示 不同 API 级别。在末尾添加一个额外的单元格来表示将来的 Android 版本。

3 4 5 6 7 8 9 10 11 12 13 +

现在只需在图表中着色,使每种颜色代表一个 APK。这里的示例说明了 您可以将每个 APK 应用于特定范围的 API 级别。

3 4 5 6 7 8 9 10 11 12 13 +

创建此图表后,将其分发给您的团队。团队就您的项目进行沟通 比方说,您不用问“API 级别 3 到 6 的 APK 怎么样了?” Android 1.x1进展如何?”此类复杂的问题,您可以说“蓝色 APK 将在 一路跟来?”

将所有通用代码和资源放在一个库项目中

无论您是修改现有 Android 应用,还是从头开始构建应用, 你应该对代码库做的第一件事,也是迄今为止最重要的。全部 放入库项目中的字符串只需更新一次(想想已本地化的字符串, 颜色主题、在共享代码中修复的 bug),从而缩短开发时间并减少 出现原本可以很容易避免的错误的可能性。

注意:尽管有关如何创建 “添加库项目”不在本课程的讨论范围之内,您可以 阅读创建 Android 库

如果您要将现有应用转换为使用多个 APK 支持, 在您的代码库中搜索每个本地化的字符串文件、值列表、主题 在不同 APK 之间保持不变的颜色、菜单图标和布局, 全部都在库项目中不会发生太大变化的代码应该 也会显示在库项目中您很可能会发现 类将一两个方法从 APK 添加到 APK。

另一方面,如果您要从头开始创建应用,请尝试 在库项目中编写代码,然后再只将其移至 (如果需要)。从长远来看,这比添加到 又在几个月后,试图弄清楚这个 blob 能否上移 无需调整任何东西

创建新的 APK 项目

您应该为要发布的每个 APK 单独创建一个 Android 项目。简单 请将库项目和所有相关的 APK 项目放在同一个父文件夹下。 另请注意,每个 APK 必须具有相同的软件包名称,尽管它们不一定 需要与库共享软件包名称如果您有 3 个遵循 scheme 的 APK 则您的根目录可能如下所示:

alexlucas:~/code/multi-apks-root$ ls
foo-blue
foo-green
foo-lib
foo-red

项目创建完毕后,请将库项目作为引用添加到各个 APK 项目中。如果 在库项目中定义启动 Activity,并在 APK 中扩展该 Activity 项目。在库项目中定义启动 activity 后,您便可以将所有 并在一个位置集中进行应用初始化 重新实施“通用”例如初始化 Google Analytics、运行许可检查,以及 在不同 APK 之间变化不大的初始化过程。

调整清单

当用户通过 Google Play 下载使用多个 APK 的应用时,正确的 使用两条简单的规则来选择要使用的 APK:

  • 清单必须显示特定的 APK 符合条件
  • 在符合条件的 APK 中,选择版本最高的一个

我们以上文所述的一组多 APK 为例,假设我们 为任何 APK 设置最高 API 级别。单独看,每个 APK 的可能范围为 如下所示:

3 4 5 6 7 8 9 10 11 12 13 +
3 4 5 6 7 8 9 10 11 12 13 +
3 4 5 6 7 8 9 10 11 12 13 +

因为要求具有更高 minSdkVersion 的 APK 还必须具有 就可以看到,就 versionCode 值而言,红色 ≥ 绿色 ≥ 蓝色。因此,我们实际上可以将该图表简化为下表:

3 4 5 6 7 8 9 10 11 12 13 +

现在,我们进一步假设红色 APK 有一些另外 2 种颜色的 APK 所没有的要求。 Google Play 上的过滤器页 Android 开发者指南中列出了可能的问题根源。对于 我们假设红色 APK 需要使用前置摄像头。事实上, 红色 APK 将前置摄像头与 API 中添加的实用新功能结合在一起 11.但事实是,有些 API 11+ 设备根本没有前置摄像头!通过 太可怕了!

幸运的是,如果用户在此类设备上浏览 Google Play,Google Play 会查看 看到红色的“前置摄像头”列为一项要求,然后静默地忽略它, 后来判定红色和该设备在数字天堂中是不匹配的。然后,系统就会显示 绿色不仅向前兼容采用 API 11 的设备(因为未定义 maxSdkVersion), 也不在乎是否有前置摄像头!应用仍可下载 因为尽管发生了前置摄像头的小意外,但仍然有 支持该特定 API 级别的 APK。

为了便于区分各个 APK,请务必提供有效的版本代码 架构。您可以在 我们的开发者指南由于这组示例 APK 只处理 3 个可能的 将每个 APK 分隔开 1000,将前几位数字设为 minSdkVersion 的值,然后再递增。相应版本代码可能类似如下:

蓝色:03001, 03002, 03003, 03004...
绿色:07001, 07002, 07003, 07004...
红色:11001, 11002, 11003, 11004...

综上所述,您的 Android 清单内容可能类似于这样:

蓝色:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="03001" android:versionName="1.0" package="com.example.foo">
    <uses-sdk android:minSdkVersion="3" />
    ...

绿色:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="07001" android:versionName="1.0" package="com.example.foo">
    <uses-sdk android:minSdkVersion="7" />
    ...

红色:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="11001" android:versionName="1.0" package="com.example.foo">
    <uses-sdk android:minSdkVersion="11" />
    ...

检查发布前核对清单

在上传到 Google Play 之前,请仔细检查以下各项内容。请注意,这些内容都是与多个 APK 相关的,并不能代表上传到 Google Play 的所有应用的完整核对清单。

  • 所有 APK 必须具有相同的软件包名称
  • 所有 APK 必须使用相同的证书签名
  • 如果 APK 在平台版本上出现重叠,则 minSdkVersion 较高的 APK 应具有更高的版本号
  • 仔细检查您的清单过滤器是否有冲突的信息(仅在特大屏幕上支持 Cupcake 的 APK 不会被任何人看到)
  • 每个 APK 的清单必须至少在一个受支持的屏幕、OpenGL 纹理或平台版本中是唯一的
  • 尝试在至少一个设备上测试所有 APK。除此之外,您的开发计算机上还有业内自定义程度最高的设备模拟器之一,您可以尽情地测试!

此外,还应在将经过编译的 APK 推送到市场之前对其进行检查,以确保 以防您的应用在 Google Play 上无法展示。这其实很简单,只需使用 “aapt”工具。Aapt(Android 资源打包工具)是用于创建和 打包 Android 应用,这也是检查它们的便捷工具。

>aapt dump badging
package: name='com.example.hello' versionCode='1' versionName='1.0'
sdkVersion:'11'
uses-permission:'android.permission.SEND_SMS'
application-label:'Hello'
application-icon-120:'res/drawable-ldpi/icon.png'
application-icon-160:'res/drawable-mdpi/icon.png'
application-icon-240:'res/drawable-hdpi/icon.png'
application: label='Hello' icon='res/drawable-mdpi/icon.png'
launchable-activity: name='com.example.hello.HelloActivity'  label='Hello' icon=''
uses-feature:'android.hardware.telephony'
uses-feature:'android.hardware.touchscreen'
main
supports-screens: 'small' 'normal' 'large' 'xlarge'
supports-any-density: 'true'
locales: '--_--'
densities: '120' '160' '240'

检查 aapt 输出时,请务必检查并确保 Support-screens 和 compatible-screens,并且没有意外的“uses-feature”价值 因您在清单中设置的权限而添加的。在上面的示例中,APK 在很多设备上无法显示。

为什么?添加必要的 SEND_SMS 权限时,就隐式添加了 android.hardware.telephony 功能要求。由于 API 11 是 Honeycomb(专为平板电脑优化的 Android 版本),并且 Honeycomb 设备均没有电话硬件,因此 Google Play 会在所有情况下过滤掉此 APK,直到未来出现 API 级别更高且拥有电话硬件的设备。

幸运的是,通过将以下内容添加到清单可轻松解决此问题:

<uses-feature android:name="android.hardware.telephony" android:required="false" />

此外,还隐式添加了 android.hardware.touchscreen 要求。如果您希望在不属于触摸屏设备的电视上看到您的 APK,则应将以下内容添加到清单中:

<uses-feature android:name="android.hardware.touchscreen" android:required="false" />

完成发布前核对清单后,就可以将您的 APK 上传到 Google Play。您的应用可能需要一段时间才会在 Google Play 中显示,但在它显示后,您还需执行最后一项检查。将应用下载到您可能拥有的任何测试设备上,确保 APK 定位到正确的设备。恭喜您大功告成了!