web-dev-qa-db-ja.com

Android MediaStoreから読み取ろうとするとKitKat securityExceptionが発生する

Java.lang.SecurityException:許可の拒否:ProcessRecord {430b1748 29271:com.xxx/u0a88}(pid = 29271、uid = 10088)からプロバイダーcom.Android.providers.media.MediaDocumentsProviderを開くには、Android.permission.MANAGE_DOCUMENTSまたはAndroidが必要です。 permission.MANAGE_DOCUMENTS

MANAGE_DOCUMENTSおよびREAD_EXTERNAL_STORAGE権限を追加しましたが、まだこのエラーが発生しています。問題のコード:

 public static String getImagePath(HailoDriverApplication app, Uri uri) {
    Cursor cursor = null;
    if (uri == null) {
        return null;
    }
    try {
        cursor = app.getContentResolver().query(uri, new String[] {
            MediaStore.Images.Media.DATA
        }, null, null, null);
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        if (cursor.moveToFirst()) {
            return cursor.getString(column_index);
        }
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
    return null;
}

マニフェストのリクエストされたスニペット:

<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
package="com.x.x.x" >

<uses-sdk
    Android:minSdkVersion="8"
    Android:targetSdkVersion="16" />

<uses-permission Android:name="Android.permission.INTERNET" />
<uses-permission Android:name="Android.permission.VIBRATE" />
<uses-permission Android:name="Android.permission.ACCESS_NETWORK_STATE" />
<uses-permission Android:name="Android.permission.ACCESS_COURSE_LOCATION" />
<uses-permission Android:name="Android.permission.ACCESS_FINE_LOCATION" />
<uses-permission Android:name="Android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission Android:name="Android.permission.WAKE_LOCK" />
<uses-permission Android:name="Android.permission.READ_LOGS" />
<uses-permission Android:name="Android.permission.READ_PHONE_STATE" />
<uses-permission Android:name="Android.permission.READ_CONTACTS" />
<uses-permission Android:name="Android.permission.CHANGE_WIFI_STATE" />
<uses-permission Android:name="Android.permission.ACCESS_WIFI_STATE" />
<uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission Android:name="Android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission Android:name="Android.permission.MANAGE_DOCUMENTS" />
<uses-permission Android:name="Android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission Android:name="com.google.Android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission
    Android:name="Android.permission.UPDATE_DEVICE_STATS"
    tools:ignore="ProtectedPermissions" />
<uses-permission Android:name="Android.permission.WRITE_SETTINGS" />
<uses-permission Android:name="Android.intent.action.BATTERY_CHANGED" />
<uses-permission
    Android:name="Android.permission.INSTALL_PACKAGES"
    tools:ignore="ProtectedPermissions" />
<uses-permission Android:name="Android.permission.GET_ACCOUNTS" />
<uses-permission Android:name="com.google.Android.c2dm.permission.RECEIVE" />
46
serenskye

過去数日間同じ問題がありました。いくつかのソリューションを試しましたが、何らかの理由で、マニフェストにAndroid.permission.MANAGE_DOCUMENTS権限が追加されていても、一部の画像のUriコンテンツプロバイダーで権限が拒否されました。

当面の回避策は次のとおりです。

i = new Intent(Intent.ACTION_PICK, Android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, CHOOSE_IMAGE);

これにより、新しいKitKatドキュメントビューではなく、古い画像ギャラリーが強制的に開かれます。

これで、onActivityResultで次を呼び出すことでUriを取得できます。

Uri selectedImageURI = data.getData();

お役に立てれば。

44
rahulritesh

ユーザーにファイルの追加を促すために使用されるインテントで、Intent.ACTION_GET_CONTENTまたはIntent.ACTION_PICKの代わりにIntent.ACTION_OPEN_DOCUMENT(KitKat API 19以降)を使用します。次に、Uriを使用するときは、@ feriのリンク( https://developer.Android.com/guide/topics/providers/document -provider.html#permissions ):

final int takeFlags = data.getFlags()
        & (Intent.FLAG_GRANT_READ_URI_PERMISSION
        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// Check for the freshest data.
getContentResolver().takePersistableUriPermission(originalUri, takeFlags);

Intent.ACTION_GET_CONTENT、Intent.ACTION_PICK、およびIntent.ACTION_OPEN_DOCUMENTの違いについて詳しくは、こちらをご覧ください。 http://developer.Android.com/reference/Android/content/Intent.html#ACTION_OPEN_DOCUMENT

13
Tony Wickham

OK、問題を乗り越える実用的なサンプルを見つけました:

            intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
            intent.addCategory(Intent.CATEGORY_OPENABLE);
            intent.setType("image/*");
            startActivityForResult(intent, myClassConstant.SELECT_PICTURE);

これが私が学んだことです...これはキットカットの変更であり、このコードはAPI 19以上でのみ動作します。古いバージョンでは機能しないため、KitKatより前のメソッドも必要です。 Category_Openable引数(私の場合は画像)を使用してファイルを取得したら、URIとして参照することで使用できます。私の場合、URIString(ファイルパス)を保存し、オープンが発生した後、それを使用して必要なことを行うことができます。

今私が理解しようとしている問題は、ファイルのアクセス許可がどのくらい持続するかです。私のコードはUriStringを探し、ファイルを開こうとするため、昨日から期限切れになっているようです。上記のコードを使用して画像を選択すると、それが機能します-名前が保存され、プログラムを終了して戻ることができました...しかし、今朝の最初のプログラムの実行(後12時間以上触れないでください)、ファイルを見つけることができなかったように動作しました(そして、デバッガーを見ると、重大ではないエラーが再び表示されるのがわかります)。

だから今質問は次のとおりです。ファイル(名前)が何であるかを知った後、どのようにアクセス許可を保持しますか。

11
user1082348

表示したいUriは、Android 4.4 KitKat。これはギャラリーとGoogleドライブのどちらでもよい。これらのドキュメントにアクセスするには、システムファイルピッカーを使用するようです。ユーザーが開くファイルを選択すると、システムはアプリに許可を与え、ファイルを開くダイアログを開始します。他の画像にはアクセスできず、セキュリティ例外が発生します。

Uriが永続化されている場合、Uriへのアクセスを許可された権利も永続化されなければなりません。詳細については、こちらをご覧ください: https://developer.Android.com/guide/topics/providers/document-provider.html#permissions

3
feri

MANAGE_DOCUMENTSパーミッションは、システムのみが保持できます:

MANAGE_DOCUMENTS権限。デフォルトでは、プロバイダーは誰でも利用できます。この許可を追加すると、プロバイダーがシステムに制限されます。この制限はセキュリティにとって重要です。

Storage Access Framework から取得)

したがって、DocumentProviderでこの権限を使用すると、プロバイダーへのアクセスをシステムのみに制限できます。つまり、System UI pickerのみがファイルにアクセスできます。そのため、アプリがProviderからファイルを選択するには、ACTION_OPEN_DOCUMENTIntentを起動する必要があり、実際にはSystem UI pickerを起動します。ユーザーはそこからファイルを選択し、URIが返されます。

3
Ovidiu Latcu

解決策は、ギャラリーの画像にアクセスする代わりに、 http://developer.Android.com/guide/topics/providers/document-provider.html#client を使用しているようです

他のアプローチがうまくいかない理由はわかりません。しかし、現時点では短期的な修正です。

0
serenskye