web-dev-qa-db-ja.com

Android 6.0アクセス許可とOBBのマウント

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

しかし、次のディレクトリにはアクセスできません:

  • Samsung Galaxy S5、S6、S7
  • Nvidia Shieldタブレット

ストアからのゲームのダウンロードをシミュレートするために、アルファテストを使用してそれを確認しました。

ストレージへのアクセス許可が(アプリの設定を介して)与えられると、すべてが正常に実行されます。

OBBはどのようにマウントされますか?

私が使用しているUnreal Engine 4は、OBBファイルを処理するためにCのopen()関数を使用しています。

int32 Handle = open(LocalPath, O_RDONLY);

ここで、LocalPathはobbファイルへのフルパスです:/storage/emulated/0/Android/obb/com.company.productname/main.10003.com.company.productname.obb

質問は:

  1. OBBファイルを読み取ってダウンロードするには、ゲームにREAD/WRITE _EXTERNAL_STORAGEが必要ですか?
  2. はいの場合、ユーザーにアクセス許可を求める警告をどのようにして取り除くことができますか?.
  3. そうでない場合、Samsung Galaxy Sシリーズがそのような問題を引き起こすのはなぜですか?
9
zompi

問題は別の場所に記載されているようですが、正確な問題であることを知らなかったため、見つけることができませんでした...

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

API23は、何らかの理由でOBBのユーザーをrootに設定したものであり、適切なユーザーではありません。そのため、アプリはそれにアクセスできません。

デバイスを再起動した後、すべてが正常に動作します。

現時点では、これに対する明確な回避策はありません。

すべての必要かつ役立つ情報を提供してくれて@Larryに感謝します:)

10
zompi

ストアからのアプリケーションに書き込み権限があるかどうかを確認してください。

2
Ciprian Jijie

適切なソリューションを指摘してくれた@Larryに感謝します。

なぜAOSP APK拡張サポートlibrayが許可なしに機能しないのか疑問に思う方のために、変更された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);
    }
}
1
Dima Rostopira

上記のコメントスレッドに基づいて、ここで回答を提供します。問題は、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データを書き込むには権限が必要です。

0
Larry Schiefer