Android APK扩展文件

Android APK扩展文件的上传与下载

扩展文件的由来

在上传Android APK到Google Play的时候,Google对APK的大小有限制-不能超过50M。但是对于一些应用或者游戏来说50M是远远不够的,比如应用需要附带很多多媒体文件,或者游戏中的地图资源文件等。那么,传统的解决方案是将这些大尺寸的资源文件放到自由的服务器上,当第一次启动应用的时候前往服务器下载这些资源。

针对这一情况,Google提供了一种更为方便的解决方案-APK扩展文件。也就是除了APK之外,开发者还可以为你的应用上传最多两个扩展文件,每个文件最大为2G。有了这4G的空间,相信几乎所有的应用都不会再有大小限制的烦恼。

创建扩展文件

两个扩展文件分别为主(main)扩展和补充(patch)扩展文件,其中主扩展文件用来存放扩展资源的主题,一般来说应用只需要这一个扩展文件。而补充扩展文件是当资源发生变化的时候(比如你的应用又增加了10张地图文件),以patch的形式来提交这些变化。这样做的好处是,用户就不需要再重新下载整个大资源包,而仅仅需要下载新增的部分(patch扩展文件)既可,大大节省了流量,提高了效率。

扩展文件的命名

扩展文件的命名必须遵循一定的规则:

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

文件名包含四部分,其中:

  • main|patch: 用来表示是主扩展还是补充扩展。
  • expansion-version: 当前上传apk的version code。
  • package-name: apk的包名
  • obb:后缀,其实本质就是zip文件,Google play会自动将zip文件改为obb文件。

所以你只需要将所有的扩展资源打包到一个zip文件中,文件的命名需要符合上述规范。

Tip:如果你的扩展文件是一些媒体文件并且你不想解压资源包,而是借助media playback call(例如MediaPlayer.setDataSource() and SoundPool.load())直接播放资源包里面的媒体文件。那么在创建扩展文件包的时候务必不要压缩文件,而仅仅是打包即可。具体做法:如果是命令行加上-n参数,如果是windows上用winzip,需要如下图所示:

上传扩展文件

扩展文件是不能单独上传的,也就是说每次需要上传扩展文件的时候,必须要同时先上传一个apk文件,即使apk没有变化(至少version code要变),然后在上传好新的 apk后(这个时候先不要选择Save),确认的窗口中有提示 问是否需要expansion file,这事选择上传事先已经创建好的扩展文件即可。

两点注意事项:

  • 扩展文件名字中的version部分,需要和本次上传的apk的version code一致
  • 如果是第一次为当前应用上传apk,那么不能上传扩展文件,你需要提交后,再次提交一个apk然后同时上传扩展文件(这或许是Google play的一个bug)

下载扩展文件

扩展文件默认是跟随apk文件一起下载到用户的设备上的,如果仔细观察下载过程的话,你会发现它是在apk下载完成后进行的。

扩展文件下载的位置位于: <shared-storage>/Android/obb/<package-name>/

其中shared-storage是设备的primary external storage。

但是Google play并不完全保证扩展文件每次都会随着apk下载到用户设备上,这就要求在你的应用中需要检测其是否已经自动下载了,如果没有,则需要通过程序来进行下载,这里给出一个参考流程:

下载方法

为了方便我们用在应用中下载并且使用扩展文件,Android提供了两个extra来简化开发者的工作:

  • Google play Licensing package
  • Google play APK Expansion Library package

我们可以通过android manager把需要两个extra的库下载下来:play licensing lib和apk expansion lib。

下载后会放到sdk\extras\google的对应的两个目录下,其中play licensing对应一个库,expansion对应两个库。可以将这两个工程build成两个相应的jar包供应用使用。

关于具体的下载可以参考APK expansion extra下面对应的sample应用,比较简单。

使用方法

将APK扩展文件下载下来之后,紧接着我们就要考虑如何使用它了。如果你的扩展文件是zip文件的话,恭喜你,在你刚刚下载的APK Expansion Library包中还提供了对zip文件的处理,你可以很简单的将zip包中的文件拷贝出来放到你想要的位置。以下代码仅供参考:

public void copyFileFromZip() {
    try {
        ZipResourceFile expansionFile = APKExpansionSupport.getAPKExpansionZipFile(mContext,
                mMainVersion, mPatchVersion);

        if(expansionFile != null) {
            ZipResourceFile.ZipEntryRO[] entries = expansionFile.getAllEntries();

            for(ZipResourceFile.ZipEntryRO entry : entries) {
                String imgName = entry.mFileName.toString();
                Log.d(TAG, "entry name is: " + entry.mFileName.toString());
                InputStream is = expansionFile.getInputStream(imgName);


                String outFilePath = DEPTH_FILE_DES+imgName;
                Log.d(TAG, "outfile path is: " + outFilePath);
                File outFile = new File(outFilePath);

                //copy the image now
                if(!outFile.exists()) {
                    copyInputStreamToFile(is, outFile);
                }
            }
        } else {
            Log.d(TAG, "too bad, no expansion file found");
        }
    } catch (IOException e) {
        Log.d(TAG, "get expansion file exception");
        e.printStackTrace();
    }
}

结束语

Google play提供的扩展文件方案极大方便地解决了开发者对于较多资源使用的需求,并且由于不需要开发者自己额外的提供自己的资源服务器,所以还大大地降低了开发者的成本。辅以Android提供的相应库,开发成本也将变得很低。

Reference

Android developer