web-dev-qa-db-ja.com

ユーザーにアプリの内部ストレージディレクトリへのアクセスを許可するにはどうすればよいですか?

私のアプリはファイルをその内部ストレージディレクトリ(/Android/data/com.mycompany.myapp/files、getFilesDir()によって返される)に保存しています。ユーザーが自分のファイル管理アプリからそれらのファイルに直接アクセスできるようにしたいと思いますモバイルデバイスまたはAndroid File Transferデスクトップアプリケーション。

ストレージオプション開発者ガイド のコメント:

デフォルトでは、内部ストレージに保存されたファイルはアプリケーション専用であり、他のアプリケーションはそれらにアクセスできません(ユーザーもアクセスできません)。

「デフォルト」とは、ユーザーがこれらのファイルにアクセスできるようにデフォルトのアクセス権を変更できることを意味しますが、その方法のドキュメントは見つかりません。現在、ファイル管理アプリで/ Android/dataディレクトリを参照すると、com.mycompany.myappディレクトリが非表示になります。

現在、次のようにファイルデータを保存しています。

String fileName = "myfile.jpg";
String filePath = getFilesDir() + File.separator + fileName;
FileOutputStream fileStream = new FileOutputStream(filePath);
fileData.writeTo(fileStream); // fileData is a ByteArrayOutputStream
fileStream.close();

個々のファイルの権限を誰でも読み取り可能に設定してみましたが、これではディレクトリが表示されませんでした。

FileOutputStream fileStream = this.app.openFileOutput(fileName, Context.MODE_WORLD_READABLE);

また、AndroidManifestファイルのドキュメントを確認したところ、何も見つかりませんでした。誰か私がこれを行う方法を知っていますか?

13
arlomedia

getFilesDir()getExternalFilesDir()の結果を詳しく調べたところ、getFilesDir()/data/data/[packagename]/filesを返し、getExternalFilesDir()/Android/data/[packagename]/filesを返すことがわかりました。 /Android/dataで参照していたアプリファイルは内部ストレージディレクトリであると思っていましたが、実際にはそれらが外部ストレージディレクトリであることがわかりました。

内部ストレージディレクトリが実際に通常のユーザーが利用できない場合は、「デフォルトでは」利用できないと言っているのではなく、ドキュメントに記載されていることを望みます。少なくとも私にとって、「デフォルトで」とは、デフォルトの動作を変更できることを意味します。

とにかく、アプリを削除すると、getExternalFilesDir()に保存されたファイルが自動的に削除されることをテストして確認しました。そのため、アプリと明確に関連付けられている(アプリ固有のディレクトリ名を使用し、アプリで削除される)が、ユーザーが時折手動でファイルを管理するためにアクセスできる保存場所に対する私のニーズを満たします。

これは、これを読んでいる他の人に役立つかもしれない比較です:

  • getFilesDir()-アプリ固有のディレクトリを作成します。ユーザーから隠されています。アプリで削除
  • getExternalFilesDir()-アプリ固有のディレクトリを作成します。ユーザーがアクセスできる。アプリで削除
  • getExternalStoragePublicDirectory()-共有ディレクトリ(Musicなど)を使用します。ユーザーがアクセスできる。アプリを削除しても残る
45
arlomedia

私はあなたが開発者のドキュメントで混乱していると思います、私はあなたを責めることはできません、それは私が今まで読んだ中で最高のドキュメントではありません。とにかく、Androidは、ファイルシステムにファイルを保存する2つの方法を提供します。

  1. 内部ストレージの使用
  2. 外部ストレージの使用

内部ストレージは常に利用可能であり、アプリにのみアクセスできます。システム内の他のアプリは、アプリがこのパーティションに保存したファイルにアクセスできません。

外部ストレージは「世界中で読み取り可能」であり、誰でも、どのアプリからでもアクセスできるため、必要なのはここだと思います。欠点は、ユーザーがUSBデバイスにマウントできるため、利用できない可能性があることです。ユーザーはいつでも削除できます。

非常に危険なので、ドキュメントの説明に従って MODE_WORLD_WRITEABLEMODE_WORLD_READABLE も使用しないでください。さらに、これらの定数はAPIレベル17以降廃止されました

勧告

ファイルを公開する必要がある場合は、外部ストレージに保存します。 External Storage...にアクセスするたびにアプリがクラッシュしないように、マニフェストファイルで権限を宣言する必要があります。

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

External Storageが使用できない場合があるため、操作を実行する前にその状態を確認する必要があります。そうしないと、アプリがクラッシュします...

public enum StorageState{
  NOT_AVAILABLE, WRITEABLE, READ_ONLY
}

public StorageState getExternalStorageState() {
    StorageState result = StorageState.NOT_AVAILABLE;
    String state = Environment.getExternalStorageState();

    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return StorageState.WRITEABLE;
    }
    else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        return StorageState.READ_ONLY;
    }

    return result;
}

ドキュメンテーションおよび注意する必要のある事項に関する詳細情報があります。たとえば、アプリにこれらのファイルの所有権を与えると、アプリがアンインストールされたときに、システムがこれらのファイルを自動的に削除できます。詳細については、 Android Developers Site)のドキュメントを参照してください

11
Leo

これをマニフェストに追加

次に、これをアクティビティに追加します。

_private static final String RequieredPermission = Manifest.permission.READ_EXTERNAL_STORAGE;
_

次に、HandlePermission()を呼び出します。ここで、通常はアクティビティのOncreateメソッドで、権限を確認する必要があります。次に、これらの機能が必要です。

_@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        Log.d("amir", "onRequestPermissionsResult: called");
        switch (requestCode) {
            case REQUEST_PERMISSION_READING_STATE:
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(MainActivity.this, "Permission Granted!", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(MainActivity.this, "Permission Denied!", Toast.LENGTH_SHORT).show();
                }
        }

    }

    private void HandlePermission() {
        int permissionCheck = ContextCompat.checkSelfPermission(
                this, RequieredPermission);
        if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    RequieredPermission)) {
                showExplanationaboutPermission("Permission Needed", "Rationale", RequieredPermission, REQUEST_PERMISSION_READING_STATE);
            } else {
                requestPermission(RequieredPermission, REQUEST_PERMISSION_READING_STATE);
            }
        } else {
            Toast.makeText(MainActivity.this, "Permission (already) Granted!", Toast.LENGTH_SHORT).show();
        }
    }

    private void showExplanationaboutPermission(String title,
                                                String message,
                                                final String permission,
                                                final int permissionRequestCode) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(title)
                .setMessage(message)
                .setPositiveButton(Android.R.string.ok, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        requestPermission(permission, permissionRequestCode);
                    }
                });
        builder.create().show();
    }

    private void requestPermission(String permissionName, int permissionRequestCode) {
        ActivityCompat.requestPermissions(this,
                new String[]{permissionName}, permissionRequestCode);
    }
_
0
Nabat Farsi