Android 6.0权限和装载OBB

时间:2016-07-13 15:28:26

标签: android android-permissions apk-expansion-files

我在Android 6.0及更高版本上的权限存在问题。

我正在使用的游戏是使用WRITE_EXTERNAL_STORAGE权限。在Android 6.0及更高版本上,必须显示要求用户允许的警报。

我已收到删除此提醒的请求,这意味着游戏无法再使用WRITE_EXTERNAL_STORAGE。

从技术上讲,游戏现在不是在任何地方写入和读取外部存储。所有保存和缓存的文件都存储在特定于应用程序的目录中(/storage/emulated/0/Android/data/com.company.productname) 但是,游戏必须读取(有时下载)OBB文件,该文件存储在/storage/emulated/0/Android/obb/com.company.productname目录中。

即使没有设备上的WRITE_EXTERNAL_STORAGE或READ_EXTERNAL_STORAGE,游戏也可以访问此目录:

  • Motorola Nexus 6
  • LG Nexus 5

但它似乎无法访问此目录:

  • 三星Galaxy S5,S6和S7
  • Nvidia Shield平板电脑

我甚至使用Alpha测试检查了它,以模拟从商店下载游戏。

当给予存储权限时(通过应用程序设置),一切运行正常。

如何安装OBB?

我使用的虚幻引擎4正在使用C open()函数来处理OBB文件:

int32 Handle = open(LocalPath, O_RDONLY);

其中LocalPath是obb文件的完整路径:/storage/emulated/0/Android/obb/com.company.productname/main.10003.com.company.productname.obb

问题是:

  1. 游戏是否需要READ / WRITE _EXTERNAL_STORAGE才能读取和下载OBB文件?
  2. 如果是,那么我怎样才能摆脱询问用户权限的警报。
  3. 如果没有,那么为什么三星Galaxy S系列会出现这样的麻烦?

4 个答案:

答案 0 :(得分:10)

好吧,似乎问题已列在其他地方,但我找不到,因为我不知道这是确切的问题......

https://code.google.com/p/android/issues/detail?id=197287

由于某种原因,API23将OBB的用户设置为root用户,而不是正确的用户,因此应用程序无法访问它。

重启设备后一切正常。

目前还没有明确的解决方法。

感谢@Larry提供所有必要且有用的信息:)

答案 1 :(得分:2)

请您检查您的商店申请是否有书面许可。

答案 2 :(得分:1)

感谢@Larry指出正确的解决方案。

对于那些想知道为什么AOSP APK Expansion支持库未经许可无法运行的人,这里是修改后的APKExpansionSupport.java

package com.android.vending.expansion.zipfile;
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.io.File;
import java.io.IOException;
import java.util.Vector;

import android.content.Context;

public class APKExpansionSupport {
    public static String[] getAPKExpansionFiles(Context ctx, int mainVersion, int patchVersion) {
        String packageName = ctx.getPackageName();
        Vector<String> ret = new Vector<>(2);
        File expPath = ctx.getObbDir();
        // Check that expansion file path exists
        if (expPath.exists()) {
            if ( mainVersion > 0 ) {
                String strMainPath = expPath + File.separator + "main." + mainVersion + "." + packageName + ".obb";
                File main = new File(strMainPath);
                if ( main.isFile() ) {
                    ret.add(strMainPath);
                }
            }
            if ( patchVersion > 0 ) {
                String strPatchPath = expPath + File.separator + "patch." + mainVersion + "." + packageName + ".obb";
                File main = new File(strPatchPath);
                if ( main.isFile() ) {
                    ret.add(strPatchPath);
                }
            }
        }
        String[] retArray = new String[ret.size()];
        ret.toArray(retArray);
        return retArray;
    }

    public static ZipResourceFile getResourceZipFile(String[] expansionFiles) throws IOException {
        ZipResourceFile apkExpansionFile = null;
        for (String expansionFilePath : expansionFiles) {
            if ( null == apkExpansionFile ) {
                apkExpansionFile = new ZipResourceFile(expansionFilePath);
            } else {
                apkExpansionFile.addPatchFile(expansionFilePath);
            }
        }
        return apkExpansionFile;
    }

    public static ZipResourceFile getAPKExpansionZipFile(Context ctx, int mainVersion, int patchVersion) throws IOException{
        String[] expansionFiles = getAPKExpansionFiles(ctx, mainVersion, patchVersion);
        return getResourceZipFile(expansionFiles);
    }
}

答案 3 :(得分:0)

根据上述评论主题提供答案。问题在于提供LocalPath的方式。在Android中,不同制造商之间的文件系统路径不一致,您不应该对存储路径做出任何假设。

所以不要这样(只是示例代码):

public class MyActivity extends Activity {
    static final String LocalPath = "/storage/emulated/0/Android/obb/com.company.productname/main.10003.com.company.p‌​roductname.obb ";
    ...
}

你需要做这样的事情:

public class MyActivity extends Activity {
    File mObb;
    ...

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate();
        ...

        mObb = new File(getObbDir(), getPackageName() + ".obb");

        //  Get the path for passing to UE4 later
        String LocalPath = mObb.getAbsolutePath();
    }

这将确保您的代码在给定设备的主外部存储上为您的应用获取正确的OBB位置。然后,您可以将OBB保存在那里,稍后当您的应用程序启动UE4时,它可以指向该文件。

应用程序在OBB(和其他文件)的主外部存储上的位置不需要读取和写入该应用程序的权限。如果外部存储上的路径不是上述方法生成的路径,则需要WRITE_EXTERNAL_STORAGE权限才能写入数据。