125

バックグラウンド

Android 4.4 (KitKat) では、Google は SD カードへのアクセスをかなり制限しました。

Android Lollipop (5.0) の時点で、開発者は新しい API を使用して、特定のフォルダーへのアクセスを許可するかどうかをユーザーに確認するよう求めることができます。これについては、この Google グループの投稿に記載されています。

問題

この投稿では、次の 2 つの Web サイトにアクセスするように指示されています。

これは内部の例のように見えますが (後で API デモで表示される可能性があります)、何が起こっているのかを理解するのは非常に困難です。

これは新しい API の公式ドキュメントですが、使用方法について十分な詳細が説明されていません。

これがあなたに言うことです:

ドキュメントのサブツリー全体へのフル アクセスが本当に必要な場合は、まず ACTION_OPEN_DOCUMENT_TREE を起動して、ユーザーがディレクトリを選択できるようにします。次に、結果の getData() を fromTreeUri(Context, Uri) に渡して、ユーザーが選択したツリーの操作を開始します。

DocumentFile インスタンスのツリーをナビゲートするときに、いつでも getUri() を使用して、そのオブジェクトの基になるドキュメントを表す Uri を取得し、openInputStream(Uri) などで使用できます。

KITKAT 以前を実行しているデバイスでコードを簡素化するには、DocumentsProvider の動作をエミュレートする fromFile(File) を使用できます。

質問

新しい API についていくつか質問があります。

  1. 本当にどうやって使うの?
  2. 投稿によると、OS は、アプリにファイル/フォルダーへのアクセス許可が与えられたことを記憶します。ファイル/フォルダにアクセスできるかどうかを確認するにはどうすればよいですか? アクセスできるファイル/フォルダのリストを返す関数はありますか?
  3. Kitkat でこの問題をどのように処理しますか? サポート ライブラリの一部ですか。
  4. どのアプリがどのファイル/フォルダーにアクセスできるかを示す OS の設定画面はありますか?
  5. 複数のユーザーが同じデバイスにアプリをインストールするとどうなりますか?
  6. この新しい API に関する他のドキュメントやチュートリアルはありますか?
  7. 権限を取り消すことはできますか? もしそうなら、アプリに送信されているインテントはありますか?
  8. 許可を求めることは、選択したフォルダーに対して再帰的に機能しますか?
  9. アクセス許可を使用すると、ユーザーの選択によって複数選択の機会をユーザーに与えることもできますか? または、アプリは許可するファイル/フォルダーを具体的にインテントに伝える必要がありますか?
  10. エミュレータで新しい API を試す方法はありますか? つまり、SD カード パーティションがありますが、プライマリ外部ストレージとして機能するため、(単純なアクセス許可を使用して) すべてのアクセスが既に与えられています。
  11. ユーザーが SD カードを別のものに交換するとどうなりますか?
4

3 に答える 3

149

良い質問がたくさんあります。掘り下げてみましょう。:)

どうやって使うんですか?

KitKat で Storage Access Framework を操作するための優れたチュートリアルを次に示します。

https://developer.android.com/guide/topics/providers/document-provider.html#client

Lollipop の新しい API とのやり取りは非常に似ています。ユーザーにディレクトリ ツリーを選択するように求めるには、次のようなインテントを起動できます。

    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
    startActivityForResult(intent, 42);

次に、onActivityResult() で、ユーザーが選択した Uri を新しい DocumentFile ヘルパー クラスに渡すことができます。選択したディレクトリ内のファイルを一覧表示し、新しいファイルを作成する簡単な例を次に示します。

public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
    if (resultCode == RESULT_OK) {
        Uri treeUri = resultData.getData();
        DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);

        // List all existing files inside picked directory
        for (DocumentFile file : pickedDir.listFiles()) {
            Log.d(TAG, "Found file " + file.getName() + " with size " + file.length());
        }

        // Create a new file and write into it
        DocumentFile newFile = pickedDir.createFile("text/plain", "My Novel");
        OutputStream out = getContentResolver().openOutputStream(newFile.getUri());
        out.write("A long time ago...".getBytes());
        out.close();
    }
}

によって返される Uri は、DocumentFile.getUri()さまざまなプラットフォーム API で使用できるほど柔軟です。たとえば、 を使用Intent.setData()して共有できますIntent.FLAG_GRANT_READ_URI_PERMISSION

ネイティブ コードからその Uri にアクセスする場合は、orを呼び出しContentResolver.openFileDescriptor()てから、従来の POSIX ファイル記述子整数を取得します。ParcelFileDescriptor.getFd()detachFd()

ファイル/フォルダにアクセスできるかどうかを確認するにはどうすればよいですか?

既定では、ストレージ アクセス フレームワークのインテントを通じて返された Uris は、再起動後も保持されません。プラットフォームはパーミッションを保持する機能を「提供」しますが、必要に応じてパーミッションを「取得」する必要があります。上記の例では、次のように呼び出します。

    getContentResolver().takePersistableUriPermission(treeUri,
            Intent.FLAG_GRANT_READ_URI_PERMISSION |
            Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

ContentResolver.getPersistedUriPermissions()APIを使用して、アプリがアクセスできる永続的な許可をいつでも把握できます。永続化された Uri にアクセスする必要がなくなった場合は、ContentResolver.releasePersistableUriPermission().

これはキットカットで入手できますか?

いいえ、古いバージョンのプラットフォームに新しい機能をさかのぼって追加することはできません。

ファイル/フォルダーにアクセスできるアプリを確認できますか?

現在、これを示す UI はありませんが、adb shell dumpsys activity providers出力の "Granted Uri Permissions" セクションで詳細を確認できます。

複数のユーザーが同じデバイスにアプリをインストールするとどうなりますか?

Uri アクセス許可の付与は、他のすべてのマルチユーザー プラットフォーム機能と同様に、ユーザーごとに分離されます。つまり、2 人の異なるユーザーの下で実行されている同じアプリには、Uri アクセス許可の付与が重複したり共有されたりすることはありません。

権限を取り消すことはできますか?

バッキング DocumentProvider は、クラウドベースのドキュメントが削除されたときなど、いつでもアクセス許可を取り消すことができます。これらの取り消された権限を発見する最も一般的な方法は、それらがContentResolver.getPersistedUriPermissions()上記から消えたときです。

許可に関係するいずれかのアプリのアプリ データが消去されるたびに、アクセス許可も取り消されます。

許可を求めることは、選択したフォルダーに対して再帰的に機能しますか?

そうです、ACTION_OPEN_DOCUMENT_TREEインテントは、既存のファイルと新しく作成されたファイルとディレクトリの両方に再帰的にアクセスできるようにします。

これは複数選択を許可しますか?

はい、KitKat から複数選択がサポートされており、インテントEXTRA_ALLOW_MULTIPLEの開始時に設定することで許可できます。またはをACTION_OPEN_DOCUMENT使用して、選択できるファイルの種類を絞り込むことができます。Intent.setType()EXTRA_MIME_TYPES

http://developer.android.com/reference/android/content/Intent.html#ACTION_OPEN_DOCUMENT

エミュレータで新しい API を試す方法はありますか?

はい、エミュレーター上であっても、プライマリ共有ストレージデバイスがピッカーに表示されるはずです。READ/WRITE_EXTERNAL_STORAGEアプリが共有ストレージへのアクセスにストレージ アクセス フレームワークのみを使用している場合、アクセス許可はまったく必要ないため、アクセス許可を削除するか、android:maxSdkVersion機能を使用して古いプラットフォーム バージョンでのみアクセス許可を要求できます。

ユーザーが SD カードを別のものに交換するとどうなりますか?

物理メディアが関係する場合、基になるメディアの UUID (FAT シリアル番号など) は、返される Uri に常に書き込まれます。ユーザーが複数のスロット間でメディアを交換した場合でも、システムはこれを使用して、ユーザーが最初に選択したメディアに接続します。

ユーザーが 2 枚目のカードを交換した場合は、新しいカードにアクセスできるようにする必要があります。システムは UUID ごとに付与を記憶するため、ユーザーが後で元のカードを再挿入した場合、以前に付与された元のカードへのアクセスを引き続き使用できます。

http://en.wikipedia.org/wiki/Volume_serial_number

于 2014-11-05T19:53:49.717 に答える