5

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

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

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

getExternalStorageDirectory()/Android/数据

我想我们可以问用户他们想要它在哪里,他们可以选择真正的外部 SD 卡。然而,这仍然会在内部 SD 卡上留下一个(基本上没用的).obb 文件,Google Play 说我们不能删除它。

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

4

3 回答 3

2

Per the Expansion File Storage Location documentation, expansion files are stored in

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

where shared-storage is what is returned by getExternalStorageDirectory(), which should be on the SD card for users that have an SD card.

Unfortunately, as stated on that same page:

To ensure proper behavior, you must not delete, move, or rename the expansion files.

I would take special attention to this paragraph:

If you must unpack the contents of your expansion files, do not delete the .obb expansion files afterwards and do not save the unpacked data in the same directory. You should save your unpacked files in the directory specified by getExternalFilesDir(). However, if possible, it's best if you use an expansion file format that allows you to read directly from the file instead of requiring you to unpack the data. For example, we've provided a library project called the APK Expansion Zip Library that reads your data directly from the ZIP file.

于 2013-03-09T00:10:20.743 回答
1

将 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。

于 2013-03-09T02:43:31.393 回答
0

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

如果你删除了 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 和解压缩的数据。

于 2013-08-04T07:42:38.897 回答