APK 扩展文件APK Expansion Files

某些应用程序(例如一些游戏)需要的资源和资产超出了 Google Play 规定的最大 Android 应用大小限制。Some applications (some games, for instance) require more resources and assets than can be provided in the maximum Android app size limit imposed by Google Play. 此限制取决于 APK 所适用的 Android 版本:This limit depends on the version of Android that your APK is targeted for:

  • 适用于 Android 4.0 或更高版本(API 级别 14 或更高)的 APK 的限制为 100MB。100MB for APKs that target Android 4.0 or higher (API level 14 or higher).
  • 适用于 Android 3.2 或更低版本(API 级别 13 或更高)的 APK 的限制为 50MB。50MB for APKs that target Android 3.2 or lower (API level 13 or higher).

若要克服此限制,Google Play 将承载和分发 APK 随附的两个扩展文件 ,使应用程序可直接超过此限制。To overcome this limitation, Google Play will host and distribute two expansion files to go along with an APK, allowing an application to indirectly exceed this limit.

大多数设备上,下载应用程序后,扩展文件会随 APK 一并下载,并保存到设备上的共享存储位置(SD 卡或可安装 USB 的分区)。On most devices, when an application is installed, expansion files will be downloaded along with the APK and will be saved to the shared storage location (the SD card or the USB-mountable partition) on the device. 在少数旧版设备上,扩展文件可能不会随 APK 一并自动安装。On a few older devices, the expansion files may not automatically install with the APK. 这些情况下,应用程序有必要包含用户首次运行应用程序时要下载扩展文件的代码。In these situations, it is necessary for the application to contain code that will download the expansion files when the user first runs the applications.

扩展文件会被视为不透明二进制 blob (obb) ,其大小最大为 2GB。Expansion files are treated as opaque binary blobs (obb) and may be up to 2GB in size. 这些文件下载后,Android 不会对其执行任何特殊处理 – 这些文件可以采用适合相应应用程序的任何格式。Android does not perform any special processing on these files after they are downloaded – the files can be in any format that is appropriate for the application. 从概念上讲,推荐的扩展文件方式应如下所示:Conceptually, the recommended approach to expansion files is as follows:

  • 主扩展 – 此文件是不适合 APK 大小限制的资源和资产的主扩展文件。Main expansion – This file is the primary expansion file for resources and assets that will not fit in the APK size limit. 主扩展文件应包含应用程序所需的主资产,并且应很少进行更新。The main expansion file should contain the primary assets that an application needs and should rarely be updated.
  • 修补扩展 – 这适用于对主扩展文件进行少量更新。Patch expansion – This is intended for small updates to the main expansion file. 此文件可更新。This file can be updated. 应用程序负责从此文件执行任何必要的修补或更新。It is the responsibility of the application to perform any necessary patches or updates from this file.

上传 APK 的同时必须上传相应扩展文件。The expansion files must be uploaded at the same time as the APK is uploaded. Google Play 不允许向现有 APK 上传扩展文件或者不允许上传现有 APK。Google play does not allow an expansion file to be uploaded to an existing APK or for existing APKs to be updated. 如果有必要更新扩展文件,则必须上传新的 APK,同时更新 versionCodeIf it is necessary to update an expansion file, then a new APK must be uploaded with the versionCode updated.

扩展文件存储Expansion File Storage

文件下载到设备后,会存储在 shared-store/Android/obb/package-name 中 :When the files are downloaded to a device, they will be stored in shared-store/Android/obb/package-name:

  • shared-store – 这是 Android.OS.Environment.ExternalStorageDirectory 指定的目录。shared-store – This is the directory specified by Android.OS.Environment.ExternalStorageDirectory .
  • package-name – 这是应用程序 Java 样式的包名称。package-name – This is the application's Java-style package name.

下载完成后,不应移动、更改、重命名扩展文件或从设备上的位置中删除扩展文件。Once downloaded, expansion files should not be moved, altered, renamed, or deleted from their location on the device. 否则会导致再次下载扩展文件,这样会删除旧文件。To do so will cause the expansion files to be downloaded again, and the old file(s) will be deleted. 此外,扩展文件目录应仅包含扩展包文件。Additionally, the expansion file directory should contain only the expansion pack files.

扩展文件未对内容提供任何安全保护 – 其他应用程序或用户可访问存储在共享存储上的任何文件。Expansion files offer no security or protection around their content – other applications or users may access any files saved on the shared storage.

如果需要解压缩扩展文件,则解压缩文件应存储在单独的目录中,例如 Android.OS.Environment.ExternalStorageDirectory 中的一个目录。If it is necessary to unpack an expansion file, the unpacked files should be stored in a separate directory, such as one in Android.OS.Environment.ExternalStorageDirectory.

从扩展文件提取文件的另一方法是直接从扩展文件读取资产或资源。An alternative to extracting files from an expansion file is to read the assets or resources directly from the expansion file. 扩展文件只是可通过合适的 ContentProvider 进行使用的 zip 文件。The expansion file is nothing more than a zip file that can be used with an appropriate ContentProvider. Android.Play.ExpansionLibrary 包含的程序集 System.IO.Compression.Zip 中包括了一个允许对某些媒体文件直接进行文件访问的 ContentProviderThe Android.Play.ExpansionLibrary contains an assembly, System.IO.Compression.Zip, which includes a ContentProvider that will allow for direct file access to some media files. 如果将媒体文件打包为 zip 文件,媒体播放调用可能直接使用 zip 中的文件而无需解压缩 zip 文件。If media files are being packaged into a zip file, media playback calls may directly use files in the zip without having to unpack the zip file. 添加到 zip 文件时不应压缩媒体文件。The media files should not be compressed when added to the zip file.

文件名格式FileName Format

下载扩展文件后,Google Play 会使用下面的方案来对扩展进行命名:When the expansion files are downloaded, Google Play will use the following scheme to name the expansion:

[main|patch].<expansion-version>.<package-name>.obb

此方案的三个组件包括:The three components of this scheme are:

  • mainpatch – 这会指定是主扩展文件还是修补扩展文件。main or patch – This specifies whether this is the main or patch expansion file. 二者只能选其一。There can be only one of each.
  • <expansion-version> – 这是一个整数,该整数与文件首次关联的 APK 的 versionCode 匹配。<expansion-version> – This is an integer that matches the versionCode of the APK that the file was first associated with.
  • <package-name> – 这是应用程序的 Java 样式包名称。<package-name> – This is the application's Java-style package name.

例如,如果 APK 版本是 21,包名称是 mono.samples.helloworld,则主扩展文件应命名为 main.21.mono.samples.helloworld 。For example, if the APK version is 21, and the package name is mono.samples.helloworld, the main expansion file will be named main.21.mono.samples.helloworld.

下载过程Download Process

从 Google Play 安装应用程序时,扩展文件会随 APK 一并下载和保存。When an application is installed from Google Play, the expansion files should be downloaded and saved along with the APK. 在某些情况下可能有所例外,或者扩展文件可能会被删除。In certain situations this may not happen, or expansion files may be deleted. 为处理这种情况,应用需检查扩展文件是否存在,然后根据需要进行下载。To handle this condition, an app needs to check to see whether the expansion files exist and then download them, if necessary. 下方流程图显示了此过程的推荐流程:The following flowchart displays the recommended workflow of this process:

APK 扩展流程图APK expansion flowchart

应用程序启动时,应检查当前设备上是否存在合适的扩展文件。When an application starts up, it should check to see if the appropriate expansion files exist on the current device. 如果不存在,则应用程序必须在 Google Play 的应用程序授权中作出请求。If they do not, then the application must make a request from Google Play’s Application Licensing. 使用许可验证库 (LVL) 执行该检查,并且免费或许可应用程序都必须执行该检查。This check is made by using the License Verification Library (LVL), and must be made for both free and licensed applications. LVL 主要由付费应用程序用于实施许可证限制。The LVL is primarily used by paid applications to enforce license restrictions. 但是,Google 已扩展 LVL,使其也可用于扩展库。However, Google has extended the LVL so that it can be used with expansion libraries as well. 免费应用程序必须执行 LVL 检查,但可以忽略许可证限制。Free applications have to perform the LVL check, but can ignore the license restrictions. LVL 请求负责提供以下有关应用程序所需扩展文件的信息:The LVL request is responsible for providing the following information about the expansion files that the application requires:

  • 文件大小 – 扩展文件的文件大小作为检查的一部分,可用于确定是否已经下载正确的扩展文件。File Size – The file sizes of the expansion files are used as part of the check that determines whether or not the correct expansion files have already been downloaded.
  • 文件名 – 这是扩展包必须保存到其下的文件名(当前设备上)。Filenames – This is the file name (on the current device) to which the expansion packs must be saved.
  • 下载 URL – 用于下载扩展包的 URL。URL for Download – The URL that should be used to download the expansion packs. 每次下载所用的 URL 都是唯一的,提供之后很快会过期。This is unique for every download and will expire shortly after it is provided.

执行 LVL 检查后,应用程序应会下载扩展文件,对于下载过程,请考虑到以下几点:After the LVL check has been performed, the application should download the expansion files, taking into consideration the following points as part of the download:

  • 设备可能没有足够的空间来存储扩展文件。The device may not have enough space to store the expansion files.
  • 如果 Wi-Fi 不可用,应允许用户暂停或取消下载,以避免产生不需要的数据费用。If Wi-Fi is not available, then the user should be allowed to pause or cancel the download to prevent unwanted data charges.
  • 在后台下载扩展文件以避免阻止用户交互。The expansion files are downloaded in the background to avoid blocking user interactions.
  • 在后台进行下载时,应显示进度指示。While the download is occurring in the background, a progress indicator should be displayed.
  • 下载期间出现的错误可轻松进行处理和恢复。Errors that occur during the download are gracefully handled and recoverable.

体系结构概述Architectural Overview

主活动启动时,会检查是否已下载了扩展文件。When the main activity starts, it checks to see if the expansion files are downloaded. 如果已下载文件,则必须检查其有效性。If the files are downloaded, they must be checked for validity.

如果未下载扩展文件,或者当前文件无效,则必须下载新的扩展文件。If the expansion files have not been downloaded or if the current files are invalid, then new expansion files must be downloaded. 创建绑定服务作为应用程序的一部分。A bounded service is created as part of the application. 应用程序主活动启动时,会使用绑定服务根据 Google 授权服务执行检查,以找出要下载文件的文件名和 URL。When the main activity of the application is started, it uses the bounded service to perform a check against the Google Licensing services to find out the expansion file names and the URL of the files to download. 绑定服务然后会在后台线程下载文件。The bounded service will then download the files on a background thread.

为减轻将扩展文件集成到应用程序所需的工作量,Google 在 Java 中创建了几个库。To ease the effort required to integrate expansion files into an application, Google created several libraries in Java. 这些库包括:The libraries in question are:

  • 下载程序库 – 该库可减少将扩展文件集成到应用程序所需的工作量。Downloader Library – This is a library that reduces the effort required to integrate expansion files in an application. 该库会在后台服务下载扩展文件、显示用户通知、处理网络连接问题、恢复下载以及执行其他任务。The library will download the expansion files in a background service, display user notifications, handle network connectivity issues, resume downloads, etc.
  • 许可验证库 (LVL) – 该库用于执行和处理对应用程序授权服务的调用。License Verification Library (LVL) – A library for making and processing the calls to the Application Licensing services. 也可用于执行授权检查,以检查应用程序是否经授权在设备上使用。It can also be used to perform licensing checks, to see if the application is authorized for use on the device.
  • APK 扩展 Zip 库(可选)– 如果扩展文件在 zip 文件中,则该库会作为内容提供程序,允许应用程序直接从 zip 文件读取资源和资产,而无需展开 zip 文件。APK Expansion Zip Library (optional) – If the expansion files are in a zip file, this library will act as a content provider and allow an application to read resources and assets directly from the zip file without having to expand the zip file.

这些库已经移植到 C#,可用于 Apache 2.0 许可证。These libraries have been ported to C# and are available under the Apache 2.0 license. 若要将扩展文件快速集成到现有应用程序,可将这些库添加到现有 Xamarin.Android 应用程序。To quickly integrate expansion files into an existing application, these libraries can be added to an existing Xamarin.Android application. GitHub 上的 Android.Play.ExpansionLibrary 中提供有相应代码。The code is available at the Android.Play.ExpansionLibrary on GitHub.