创建多个具有多个维度的 APK

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

若要开发 Android 应用以在 Google Play 上利用多个 APK,您需要从一开始就采取一些好的做法,以免在开发过程的后期遇到不必要的麻烦。本课将介绍如何为 应用,每个应用涵盖不同大小的屏幕尺寸。您还将获得 使维护多 APK 代码库尽可能轻松。

确认您需要多个 APK

当您尝试创建可在各种可用的 Android 系统中运行的应用时 您自然希望自己的应用在每台设备上都达到最佳显示效果。您希望能够利用大屏幕的空间,同时仍能适应小屏幕,希望能够利用最新设备上提供的新 Android API 功能或视觉纹理,同时又不放弃旧设备。乍一看,支持多 APK 似乎就是最佳解决方案,但事实往往并非如此。使用 多 APK 指南的部分改为单个 APK,其中包含有关如何 通过单个 APK 即可完成所有这些操作,包括使用我们的支持库、 以及 Android 开发者指南中的资源链接。

如果您可以将应用限制为单个 APK,则这种做法有以下几点优势:

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

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

制作您的需求图表

首先,创建一个简单的图表来快速确定您需要多少个 APK 以及在什么屏幕上使用 每个 APK 涵盖的大小幸运的是,你可以轻松快捷地绘制出需求图表 以便日后轻松参考假设您想要将 APK 拆分为两个维度,即 API 和屏幕尺寸创建一个表格,其中行和列分别对应每个可能的值对和颜色 在某些“blob”中,每种颜色表示一个 APK。

3 4 5 6 7 8 9 10 11 12 +
small
normal
large
xlarge

以上示例中包含 4 个 APK。蓝色适用于所有小屏幕/标准屏幕设备,绿色适用于大屏幕设备 屏幕设备,红色表示超大屏幕设备,所有 API 范围均为 3-10。紫色是 因为这适用于所有屏幕尺寸,但仅适用于 API 11 及更高版本。更重要的是,通过 看一眼这个图表,就能立即知道哪个 APK 支持任何给定的 API/屏幕尺寸组合。接收者 因为“我们有没有测试过红色的 ?”很多 比起问问小伙伴“我们有没有针对 Xoom 测试 3 到 10 的特大 APK?”打印 并把它发给处理代码库的每个人。这样工作就轻松多了。

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

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

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

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

另一方面,如果您要从头开始创建应用,请尝试 在库项目中编写代码,然后再只将其移至 (如果需要)。从长远来看,比起将 Blob 逐个添加到各个 APK 中,然后过几个月再查看能否在不造成任何问题的前提下将该 Blob 移到库中,这种做法更易于管理。

创建新的 APK 项目

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

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

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

调整清单

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

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

我们以上文所述的一组多 APK 为例,假设每个 APK 已设置为支持所有大于其“目标”的屏幕尺寸屏幕尺寸我们来看一下之前的示例图表:

3 4 5 6 7 8 9 10 11 12 +
small
normal
large
特大

由于支持范围可以重叠,因此我们可以这样描述每个 APK 支持的范围:

  • 蓝色 APK 支持所有屏幕,minSDK 为 3。
  • 绿色 APK 支持大屏幕及更大的屏幕,minSDK 为 3。
  • 红色 APK 支持特大屏幕(通常为平板电脑),minSDK 为 9。
  • 紫色 APK 支持所有屏幕,minSDK 为 11。

请注意,这些规则有很多重叠。例如, 可以想象,搭载 API 11 的特大设备可以运行 4 个指定 APK 中的任意一个。 不过,如果使用“版本最高的一个”,那么我们可以设置一个 偏好设置如下:

紫色 ≥ 红色 ≥ 绿色 ≥ 蓝色

为什么允许所有重叠?假设紫色 APK 对 其他两个则没有。Google Play 上的过滤器页面 的 Android 开发者指南中列出了所有可能的问题根源。举例来说, 我们假设 Purple 需要前置摄像头。事实上,Purple 的意义就在于 用前置摄像头拍出精彩娱乐内容!但事实是,有些 API 11+ 设备根本没有前置摄像头!这太糟糕了!

幸运的是,如果用户在此类设备上浏览 Google Play,Google Play 会查看 看到“紫色”将前置摄像头列为一项要求,然后静默地忽略它, 已经确定 Purple 和该设备不匹配。然后 可以看到,红色不仅兼容特大设备,而且不关心 还有前置摄像头!用户仍可从 Google Play 下载该应用。 因为尽管前置摄像头发生了所有的故障,但仍然有 APK 可以支持 API 级别。

为了便于区分各个 APK,请务必提供有效的版本代码 架构。您可以在 我们的开发者指南整个部分都值得一读,但基本要点是 APK,则用两位数表示 minSDK,两位数表示最小/最大屏幕尺寸,3 位数 来表示 build 号。这样一来,当设备升级到新版 Android 时 (例如,从 10 到 11),现在符合条件且优先于当前安装的 APK 将被视为“升级”如果将该版本号方案应用于这组示例 APK,结果可能如下所示:

蓝色:0304001, 0304002, 0304003...
绿色:0334001, 0334002, 0334003
红色:0344001, 0344002, 0344003...
紫色:1104001, 1104002, 1104003...

综上所述,您的 Android 清单可能类似于 以下:

蓝色:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="0304001" android:versionName="1.0" package="com.example.foo">
    <uses-sdk android:minSdkVersion="3" />
    <supports-screens android:smallScreens="true"
        android:normalScreens="true"
        android:largeScreens="true"
        android:xlargeScreens="true" />
    ...

绿色:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="0334001" android:versionName="1.0" package="com.example.foo">
    <uses-sdk android:minSdkVersion="3" />
    <supports-screens android:smallScreens="false"
        android:normalScreens="false"
        android:largeScreens="true"
        android:xlargeScreens="true" />
    ...

红色:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="0344001" android:versionName="1.0" package="com.example.foo">
    <uses-sdk android:minSdkVersion="3" />
    <supports-screens android:smallScreens="false"
        android:normalScreens="false"
        android:largeScreens="false"
        android:xlargeScreens="true" />
    ...

紫色:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="1104001" android:versionName="1.0" package="com.example.foo">
    <uses-sdk android:minSdkVersion="11" />
    <supports-screens android:smallScreens="true"
        android:normalScreens="true"
        android:largeScreens="true"
        android:xlargeScreens="true" />
    ...

请注意,从技术上讲,多个 APK 将与 supported-screens 标记或 “compatible-screens”标记。通常首选 supports-screens 同时使用这两种方法的想法。这会不必要地增加复杂性,并增大出错的几率。 另请注意,请不要使用默认值(“small”和“normal”始终为 true) 则清单中会明确设置每种屏幕尺寸的值。这可以为您节省 接下来是让人头痛 - 举个例子,目标 SDK <9 个将具有特大 自动设置为 false,因为该尺寸尚不存在。因此请明确设置值!

检查发布前核对清单

在上传到 Google Play 之前,请仔细检查以下各项内容。请注意 并非适用于所有 APK 的详尽核对清单 正在上传到 Google Play 的应用。

  • 所有 APK 必须具有相同的软件包名称。
  • 所有 APK 必须使用相同的证书签名。
  • 如果 APK 在平台版本中重叠,则 minSdkVersion 较高的 APK 必须具有 更高的版本代码。
  • 您希望 APK 支持的每种屏幕尺寸都在清单中被设为 true,各种屏幕尺寸 请设置为 false。
  • 请仔细检查您的清单过滤器是否存在冲突信息(仅支持 超大屏幕上的纸杯蛋糕不会被任何人看到)
  • 每个 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: 'xlarge'
supports-any-density: 'true'
locales: '--_--'
densities: '120' '160' '240'

检查 aapt 输出时,请务必检查 supports-screens 和 compatible-screens 的值是否存在冲突,以及是否存在因您在清单中设置的权限而添加的意外“uses-feature”值。在上面的示例中,APK 对大多数设备(如果不是所有设备)都不可见。

为什么?添加必要的 SEND_SMS 权限时,就隐式添加了 android.hardware.telephony 功能要求。由于大多数(如果不是所有)特大设备都是没有电话硬件的平板电脑,因此 Google Play 会在这些情况下过滤掉此 APK,直到未来出现既能报告为特大屏幕尺寸又拥有电话硬件的设备。

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

<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 定位到正确的设备。恭喜您大功告成了!