web-dev-qa-db-ja.com

Android-SDカードへの書き込み許可ダイアログを要求

デバイスのSDカードのルートディレクトリへの書き込みアクセスを取得できません。 SDカード内のデバイスの内部ストレージとアプリパッケージフォルダーに問題なく書き込むことができます。 Storage Access Frameworkを使用してSDカードにアクセスできることがわかったので、他のアプリを調べてSDカードにアクセスする方法を確認し、Total Commanderのきちんとした権限ダイアログを見つけました。

write to SD card permission dialog

例が見つからないため、このようなダイアログを表示するにはどうすればよいですか?私の目標は、アプリをアンインストールした後も残る大きなファイルをSDカードに保存することです。

同様の質問:

Android(外部SDカードに書き込む):Java.io.IOException:Permission denied

Android MがSDカードに書き込む-権限が拒否されました

SAF(ストレージアクセスフレームワーク)を使用したAndroid SDカードの書き込み権限

3

オープンソースのファイルマネージャを見つけました。コードを見て、最終的に解決策を見つけました。

Android N(7.0.0)(api 24)以上でのみ動作します。

最初にSDカードのルートパスを取得し、ユーザー権限ダイアログを表示します。

public void takeCardUriPermission(String sdCardRootPath) {
        if (Android.os.Build.VERSION.SDK_INT >= Android.os.Build.VERSION_CODES.N) {
            File sdCard = new File(sdCardRootPath);
            StorageManager storageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
            StorageVolume storageVolume = storageManager.getStorageVolume(sdCard);
            Intent intent = storageVolume.createAccessIntent(null);
            try {
                startActivityForResult(intent, 4010);
            } catch (ActivityNotFoundException e) {
            }
        }
    }

ユーザーがリクエストを受け入れると、onActivityResult()がトリガーされ、インテントデータからURIを保存できます

protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == 4010) {

            Uri uri = data.getData();

            grantUriPermission(getPackageName(), uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
                    Intent.FLAG_GRANT_READ_URI_PERMISSION);

            final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
                    Intent.FLAG_GRANT_READ_URI_PERMISSION);

            getContentResolver().takePersistableUriPermission(uri, takeFlags);
        }
    }

これで、SDカードのルートのURIを取得してStorage Access Frameworkで使用できるようになりました

public Uri getUri() {
        List<UriPermission> persistedUriPermissions = getContentResolver().getPersistedUriPermissions();
        if (persistedUriPermissions.size() > 0) {
            UriPermission uriPermission = persistedUriPermissions.get(0);
            return uriPermission.getUri();
        }
        return null;
    }
1

残念ながら、createAccessIntentの使用はAndroid Qで非推奨になり、 documentation はAndroid Q、すぐにRESULT_CANCELEDを返します。

ACTION_OPEN_DOCUMENT_TREE でインテントを使用することをお勧めします。最初に開くディレクトリを指定できます(これはAndroid O以上でのみサポートされています)。ユーザー、しかしこれはまだ非常にユーザーフレンドリーなアプローチではありません。

誰かが知っている他のユーザーフレンドリーな解決策があるかどうか疑問に思っていますか? AndroidがcreateAccessIntentを削除した理由がわかりません。最もユーザーフレンドリーな方法のようです。

3
Shawney

外部ストレージに読み取り書き込み権限を付与するには、まずAndroidManifest.xmlファイルで以下の権限を宣言する必要があります。

<uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission Android:name="Android.permission.READ_EXTERNAL_STORAGE"/>

次の行をアクティビティクラスに追加します。

private static final int REQUEST_CODE_WRITE_EXTERNAL_STORAGE_PERMISSION = 1;

Android 6.0よりも大きいOSバージョンを使用する場合、以下のように、実行時にJavaコードで2つ以上の外部ストレージアクセス許可が必要です。

// Check whether this app has write external storage permission or not.
int writeExternalStoragePermission = ContextCompat.checkSelfPermission(ExternalStorageActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
// If do not grant write external storage permission.
if(writeExternalStoragePermission!= PackageManager.PERMISSION_GRANTED)
{
    // Request user to grant write external storage permission.
    ActivityCompat.requestPermissions(ExternalStorageActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_WRITE_EXTERNAL_STORAGE_PERMISSION);
}

プログラムが上記のコードを実行すると、Androidは確認ダイアログをポップアップし、必要な権限を許可または拒否できるようにします。

許可または拒否ボタンをクリックすると、以下のメソッドが呼び出され、その中にトーストメッセージを表示できます。これをアクティビティに追加します。

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    if(requestCode == REQUEST_CODE_WRITE_EXTERNAL_STORAGE_PERMISSION)
    {
        int grantResultsLength = grantResults.length;
        if(grantResultsLength > 0 && grantResults[0]==PackageManager.PERMISSION_GRANTED)
        {
            Toast.makeText(getApplicationContext(), "You grant write external storage permission. Please click original button again to continue.", Toast.LENGTH_LONG).show();
        }else
        {
            Toast.makeText(getApplicationContext(), "You denied write external storage permission.", Toast.LENGTH_LONG).show();
        }
    }
1
J-Abdo