【问题标题】:Google Play Expansion File LocationGoogle Play 扩展文件位置
【发布时间】:2013-08-04 15:47:40
【问题描述】:

我们使用 Google Play 扩展 APK 机制获得了一个约 600MB 的大型扩展文件。我们还必须解压缩此文件以供实际使用。因此,整个应用程序加上数据需要大约 1.4 GB 的存储空间。

据我所知,Google Play 坚持将 .obb 下载到“内部”SD,而且似乎没有任何方法可以改变这一点。我们有很多用户,他们的“外部”SD 卡上有很多可用空间,但内部 SD 卡上的空间有限。他们在尖叫应用程序占用了这么多空间。对此我们有什么办法吗?

我们目前将 .obb 文件扩展为:

getExternalStorageDirectory()/Android/数据

我想我们可以询问用户他们想要的位置,然后他们可以选择真正的外部 SD 卡。但是,这仍然会在内部 SD 卡上留下一个(基本上没用的).obb 文件,Google Play 表示我们无法删除它。

有人对如何正确处理这个问题有任何建议吗?

【问题讨论】:

  • “我们有很多用户,他们的“外部”SD 卡上有很多可用空间,但内部 SD 卡上的空间有限”——从 Android 的角度来看,没有这样的概念。只有一个外部存储,用getExternalStorageDirectory() 表示。除此之外的任何事情都是由于设备制造商对 Android 的扩展,而 Play Expansion APK 的东西对此一无所知。

标签: android apk-expansion-files


【解决方案1】:

根据Expansion File Storage Location documentation,扩展文件存储在

<shared-storage>/Android/obb/<package-name>/

其中shared-storagegetExternalStorageDirectory() 返回的内容,对于拥有 SD 卡的用户,它应该在 SD 卡上。

很遗憾,正如同一页所述:

为确保正常运行,您不得删除、移动或重命名扩展文件。

我会特别注意这一段:

如果您必须解压扩展文件的内容,不要删除之后的 .obb 扩展文件,并且不要将解压后的数据保存在同一目录中。您应该将解压后的文件保存在getExternalFilesDir() 指定的目录中。但是,如果可能,最好使用允许您直接从文件中读取而不要求您解压缩数据的扩展文件格式。例如,我们提供了一个名为 APK Expansion Zip Library 的库项目,它可以直接从 ZIP 文件中读取您的数据。

【讨论】:

  • 感谢您的回复。问题是许多设备都有 2 个 SD 卡。一个内部的和一个外部的(可移动的)。 getExternalStorageDirectory() 似乎总是返回通常具有更有限存储空间的内部 SD 卡。我们必须非常快速地访问 .obb 文件(以及来自 C 代码)中的数据,因此我们必须对其进行扩展。
【解决方案2】:

将 OBB 文件放在其他任何地方的问题是,当用户卸载您的应用程序时,它们不会被删除,这往往会让他们心情不好,委婉地说。但是,如果您认为收益大于成本,那么没有什么技术可以阻止您更改存储位置,因为提供了执行 OBB 文件下载和验证的源代码,您可以修改其行为以满足您的需求。

例如,OBB文件的存放路径由com.google.android.vending.expansion.downloader.Helpers提供:

static public String getSaveFilePath(Context c) {
    File root = Environment.getExternalStorageDirectory();
    String path = root.toString() + Constants.EXP_PATH + c.getPackageName();
    return path;
}

(还需要修改getFilesystemRoot(String path)&isFilenameValid(String filename)

如果您也在使用 Google 的扩展 zipfile lib,那么您还需要更改 com.android.vending.expansion.zipfile.APKExpansionSupport 中指定 Environment.getExternalStorageDirectory() 作为根目录的 3 个方法。

这些改变至少应该让你成功了一半。

另外请注意,外部 SD 卡的问题是它们的速度差异很大,通常内部 SD 至少会有不错的速度。也许您可以将 OBB 分成 2 个文件(假设您不需要更新文件功能),然后将其中一个移动到外部 SD。

【讨论】:

  • 我对破解系统来完成这项工作不感兴趣。我真正的问题是我是否在某处遗漏了一些设置以允许这一切发生在外部 SD 卡上。从上面的 CommonWare 的 cmets 听起来好像没有。
  • 没有。但它并没有入侵系统,因为它从来都不是 Android 平台的一部分。它只是 Google Play 应用提供的一套库加服务。
【解决方案3】:

我遇到了同样的问题,但我找到了解决方法。

如果你删除了 OBB,doesFileExist(在 Helpers.java 中)将返回 false。在您的 ExpDownloaderActivity 中,您检查扩展文件已交付,您将使用此信息重新下载 OBB。

我已经更改了 dosFileExist 和 expansionFilesDelivered,使其不返回布尔值,而是返回具有以下含义的整数:

fileStatus == 0:OBB 丢失(必须下载)

fileStatus == 1: OBB 可用,可以解压到其他地方

fileStatus == 2: OBB 中的数据已经存储到另一个地方

现在的技巧: 将数据从 OBB 解压到我最喜欢的位置后,我将原始 OBB 替换为同名文件,该文件仅包含原始 OBB 的文件大小作为字符串。这会释放 sdcard 上的占用空间。

进一步调用doesFileExist 和expansionFilesDelivered 将返回filestatus = 2,这意味着不需要任何操作。

这是我在 Helpers.java 中所做的更改:

static public int doesFileExist(Context c, String fileName, long fileSize,
        boolean deleteFileOnMismatch) {
    // the file may have been delivered by Market --- let's make sure
    // it's the size we expect


    File fileForNewFile = new File(Helpers.generateSaveFileName(c, fileName));
    if (fileForNewFile.exists()) {
        if (fileForNewFile.length() == fileSize) {
            return 1;
        } else if (fileForNewFile.length() < 100) {
            // Read the file and look for the file size inside
            String content = "";
            long isSize = 0;
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(fileForNewFile);
                char current;
                while (fis.available() > 0) {
                    current = (char) fis.read();
                    content = content + String.valueOf(current);
                }

            } catch (Exception e) {
                Log.d("ReadOBB", e.toString());
            } finally {
                if (fis != null)
                    try {
                        fis.close();
                    } catch (IOException ignored) {
                }
            }
            try {
                isSize = Long.parseLong(content);
            } catch(NumberFormatException nfe) {
                Log.d("ReadOBBtoInt", nfe.toString());
            } 
            if (isSize == fileSize) {
                return 2;
            }
        }
        if (deleteFileOnMismatch) {
            // delete the file --- we won't be able to resume
            // because we cannot confirm the integrity of the file
            fileForNewFile.delete();
        }
    }
    return 0;
}

如果 OBB 的文件大小不匹配,我会读取 OBB 并与存储在其中的文件大小进行比较(这应该是文件大小)。如果这给出了匹配,我知道该文件已被处理。

这是我在 ExpDownloaderActivity 中所做的更改:

int expansionFilesDelivered() {
    int fileStatus = 0;

    for (XAPKFile xf : xAPKS) {
        if (xf.mFileSize > 0) {
            String fileName = Helpers.getExpansionAPKFileName(this, xf.mIsMain, xf.mFileVersion);
            fileStatus = Helpers.doesFileExist(this, fileName, xf.mFileSize, false);
            if (fileStatus==0)
                return 0;
        }
    }
    return fileStatus;
}

在ExpDownloaderActivity的onCreate中:

    initializeDownloadUI();

    int fileStatus = expansionFilesDelivered();
    if (fileStatus==0) {        // OBB is missing
            // ... Download the OBB file, same as on Downloader example
    } else if (fileStatus==1) {
        validateXAPKZipFiles(); // and, if OBB has no errors, unpack it to my favorite place
                                // if done, create a new OBB file with the original name
                                // and store a string with the original filesize in it.
    } else {
        finish();               // No action required        }

所以我可以在任何我想要的地方解压数据,并且 - 正如 OP 所提到的 - 不需要 sdcard 上的空间来存储完整的 OBB 解压数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-10
    相关资源
    最近更新 更多