[Android Framework シリーズ] 第 17 章 Android Q サンドボックス モード (スコープド ストレージ)

背景1枚

前章[Android フレームワーク シリーズ] 第 16 章 ストレージ アクセス フレームワーク (SAF)では主に Android 4.4 で導入されたストレージ アクセス フレームワーク (SAF) を分析しましたが、存储访问框架(SAF)この章ではAndroid10(Q)ストレージ関連を分析し、制限されたストレージ メソッドを理解します。

Googleユーザーが自分のファイルをより詳細に制御し、ファイルの乱雑さを制限できるように、デバイスのストレージへのアクセス方法がAndroid Q 変更されました。App

1.1 Android Qより前

プログラムは、許可を取得している限りREAD_EXTERNAL_STORAGE、外部ストレージのパブリック ディレクトリを自由に読み取ることができ、
プログラムが許可を取得している限りWRITE_EXTERNAL_STORAGE、外部ストレージに書き込まれたパブリック ディレクトリ上に新しいファイルやフォルダを自由に作成することができます。
ここに画像の説明を挿入します

1.2 Android Q以降

そこで Google は、プログラムによる外部ストレージ内のパブリック ディレクトリの使用を制限する分区存储ことを目的として、Android Q でこれを提案しましたパーティション化されたストレージは、内部ストレージのプライベート ディレクトリと外部ストレージのプライベート ディレクトリの両方に影響を与えません。

ここに画像の説明を挿入します

2 サンドボックスモード

2.1 Android Q では、アプリにレガシー ビューとフィルター ビューという 2 つのストレージ スペース モード ビューがあることが規定されています。

2.1.1 レガシービュー (互換モード)

Android Qプロジェクト targetSdkVersion <= 28 の場合、AndroidQ デバイスではデフォルトで互換モードが使用され、保存方法は以前と同じで、完全なアクセス許可でAppアクセスSdcardが完了します。

2.1.2 フィルターされたビュー (サンドボックス モード)

プロジェクトの targetSdkVersion > 28 の場合、AndroidQ デバイスはディレクトリ ファイルにApp直接アクセスすることしかできず、外部ファイルにアクセスする権限がありません。他のディレクトリへのアクセスは、、、または他のアプリを通じてのみ提供できますApp-specificApp-specificMediaStoreSAFContentProvider

2.2 スコープドストレージはストレージスペースを 2 つの部分に分割します

2.2.1 SD カードのパブリック ディレクトリ: ダウンロード、ドキュメント、写真、DCIM、映画、音楽、着信音

  1. パブリックディレクトリ内のファイルはAppアンインストール後に削除されません
  2. SAFインターフェース経由MediaStoreアクセス可能

2.2…2 data/data プライベート ディレクトリ (アプリ固有のディレクトリ)

  1. の場合Filtered View AppApp-specificディレクトリには自分自身のみが直接アクセスできます
  2. Appアンインストールするとデータは消去されます。

2.3 互換性への影響

Scoped StorageApp访问存储方式App数据存放に大きな影響を与えますApp间数据共享

2.4 適応

具体的な適応については、公式ドキュメントを参照してください。

2.4.1 アプリ実行ビュー

システムは、以下を通じてアプリの実行モードを決定します。

  1. App TargetSDK > 28、デフォルトFiltered View(沙箱模式)
  1. App TargetSDK <= 28、READ_EXTERNAL_STORAGE または WRITE_EXTERNAL_STORAGE 権限を宣言します、デフォルトLegacy View(兼容模式)
  1. アプリケーションはAndroidManifest.xml を通じて requestLegacyExternalStorage を設定し、対応するメソッドを選択できます
    :宣言されたREAD_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE許可 (宣言されていない場合は無視されます):
    requestLegacyExternalStorage=trueを意味します。Legacy View(兼容模式)
    requestLegacyExternalStorage=falseFiltered View(沙箱模式)
    (注意:该方式Android11后失效了)

    ここに画像の説明を挿入します
  1. システム アプリケーションは、システム権限を申請できandroid.permission.WRITE_MEDIA_STORAGE、ストレージ領域全体の権限も持ち、すべてのファイルにアクセスできます。ただし、CTS テストでは、ユーザー操作がなく、表示されるアプリのみが適用できます。具体的な参考資料《Android Bootcamp 2019 - Privacy Overview.pdf》
  1. アプリは次の条件が満たされた場合に所有されます
    : ① 声明INSTALL_PACKAGESまたは动态申请INSTALL_PACKAGES許可
    ② 所有権WRITE_EXTERNAL_STORAGE权限
    ③ アプリの所有権外置存储空间Read、Write权限
    ただし、Environment.isExternalStorageLegacyインターフェイスから判断すると、返されるのは必ずしもレガシー ビューであるとは限りません。

2.4.2 現在のアプリ実行モードを確認する

現在のアプリがどのモードで実行されているかを判断するには、この API を使用して次のことを判断できます。

Environment.isExternalStorageLegacy();

2.5 パブリックディレクトリの読み取りと書き込み

アプリが開始された後はFiltered View、アプリ自体に直接アクセスすることしかできないApp-specific目录ため、Android Qパブリック ディレクトリにアクセスする 2 つの方法が提供されています。

2.5.1 MediaStore によって定義される Uri

MediaStoreアクセスには以下の種類が用意されておりUri、該当する Uri データを検索することでアクセスの目的を達成します。
以下のそれぞれのタイプはUri、 、InternalExternal、の 3 つのタイプに分類されます可移动存储

オーディオ

  1. 内部: MediaStore.Audio.Media.INTERNAL_CONTENT_URI
    content://media/internal/audio/media。
  2. 外部: MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
    content://media/external/audio/media。
  3. リムーバブル ストレージ: MediaStore.Audio.Media.getContentUri
    content://media//audio/media。

ビデオ

  1. 内部: MediaStore.Video.Media.INTERNAL_CONTENT_URI
    content://media/internal/video/media。
  2. 外部: MediaStore.Video.Media.EXTERNAL_CONTENT_URI
    content://media/external/video/media。
  3. リムーバブル ストレージ: MediaStore.Video.Media.getContentUri
    content://media//video/media。

画像

  1. 内部: MediaStore.Images.Media.INTERNAL_CONTENT_URI
    content://media/internal/images/media。
  2. 外部: MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    content://media/external/images/media。
  3. リムーバブル ストレージ: MediaStore.Images.Media.getContentUri
    content://media//images/media。

ファイル

  1. メディアストア。Files.Media.getContentUri
    content://media//file。

ダウンロード

  1. 内部: MediaStore.Downloads.INTERNAL_CONTENT_URI
    content://media/internal/downloads。
  2. 外部: MediaStore.Downloads.EXTERNAL_CONTENT_URI
    content://media/external/downloads。
  3. リムーバブル ストレージ: MediaStore.Downloads.getContentUri
    content://media//downloads。
2.5.1.1 すべてのボリュームの取得

前に説明した Uri の場合、getContentUriすべての Uri を取得する方法は次の方法で実行できます。

for(String volume:MediaStore.getExternalVolumeNames(this)){
    
    
	MediaStore.Audio.Media.getContentUri(volume);
}
2.5.1.2 Uriとパブリックディレクトリの関係

MediaProviderアプリをパブリック ディレクトリ ファイルに保存するには、メソッド内の Uri によって決定されます。相対パスはContentResolver insert次の表に示されており、完全なファイルはcontent://media//<Uri path> です。<Uri路径>

ここに画像の説明を挿入します

2.5.1.3 権限

MediaStoreユーザーはさまざまな方法でUri、追加、削除 (ファイル Uri を使用してファイルを削除できない場合は、SAF インターフェイスを使用する必要があります)、および変更を行うことができます。
アプリの対応する権限は次のとおりです。
ここに画像の説明を挿入します

2.5.1.4 クエリファイル

ContentResolver異なる URI に基づいて異なるコンテンツをクエリすることにより、次のようになります。

  try (Cursor c = getContentResolver()
                .query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, PROJECTION, null, null, null)) {
    
    
            while (c.moveToNext()) {
    
    
                Uri contentUri =
                        ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, c.getLong(0));
            }
        }

PS:MediaStore.Filesプロセス中はQuery、写真、ビデオ、オーディオ ファイルのみが表示されます。

2.5.1.5 ファイルの読み込み

ContentResolver queryインターフェイスを介して、ファイルを見つけた後にそれを読み取る方法は次の方法で実行できます。

  1. ContentResolver openFileDescriptorインターフェイスを通じて、対応する開始メソッドを選択します。
    たとえば、「r」は読み取りを意味し、「w」は書き込みを意味し、戻り値のParcelFileDescriptor型は ですFD
  2. インターフェースThumbnail経由でContentResolver loadThumbnailアクセス
    サイズを渡すと、MediaProvider指定されたサイズが返されますThumbnail
  3. ネイティブ コードがファイルにアクセスする
    場合、ネイティブ コードがファイルにアクセスする必要がある場合は、次の方法を参照できます:
    openFileDescriptor返すことによってParcelFileDescriptor
    ParcelFileDescriptor.detachFd()読み取りによってFD
    レイヤー コードFDに渡すインターフェイスを介して閉じる責任が必要Native
    AppcloseFD
   	ParcelFileDescriptor parcelFd = resolver.openFileDescriptor(uri, file0penMode);
	if (parcelFd != null) {
    
    
	      int fd = parcelFd.detachFd();
	      // Pass the integer value "fd" into your native code. Remember to call
	      // close(2) on the file descriptor when you're done using it.
	}
2.5.1.6 新しいファイルの作成

新しいファイルをパブリック ディレクトリに保存する必要がある場合は、ContentResolver insert別のインターフェイスを使用しUri、別のディレクトリに保存することを選択する必要があります。
ここに画像の説明を挿入します

2.5.1.7 ファイルの変更

マルチメディア ファイルを変更する必要がある場合は、ContentResolver queryインターフェイスを通じて対応するファイルの URI を見つける必要があります。
新しいファイルを自分で作成したわけではない場合は、「2.5.1.3 権限」の説明に注意して適用する必要があります。適用しない場合は、ポップアップ ボックスが表示されWRITE_EXTERNAL_STORAGE权限、ユーザーに選択が表示されます。次のインターフェイスを介して、変更する必要があるファイルを取得するか、次の手順を実行しますcatch RecoverableSecurityException
ここに画像の説明を挿入します
ここに画像の説明を挿入します
FDOutputStream

  1. getContentResolver().openOutputStream(contentUri) は、
    対応するファイルの OutputStream を取得します。
  2. getContentResolver().openFile または getContentResolver().openFileDescriptor は、
    openFile または openFileDescriptor を通じてファイルを開きます。書き込み許可を示す「w」をモードとして選択する必要があります。これらのインターフェイスは ParcelFileDescriptor を返します。
    getContentResolver().openFileDescriptor(contentUri,“w”);
    getContentResolver().openFile(contentUri,“w”,null);
2.5.1.8 ファイルの削除

ContentResolver インターフェイスを介してファイルを削除します。Uri はクエリの Uri です。

getContentResolver().delete(contentUri,null,null);

2.5.2 SAF インターフェース経由

2.5.2.1 SAF の概要

SAFつまり、Storage Access Framework別のファイルを選択してDocumentsProviderファイルを開いたり参照したりできる機能をユーザーに提供します。前の章を振り返ることができます

Android ではデフォルトで次のものが提供されますDocumentsProvider:
MediaDocumentsProviderExternalStorageProviderDownloadStorageProvider
それらの違いは次のとおりです。
ここに画像の説明を挿入します
ここに画像の説明を挿入します

この図には、次の 3 つの領域があります。

  1. メディアドキュメント提供
  2. ダウンロードストレージプロバイダー
  3. 外部ストレージプロバイダー
  4. サードパーティのドキュメントプロバイダー
2.5.2.2 使用方法

詳細については公式ドキュメントを参照してください

一般的な方法は次のとおりです。

  1. 単一のファイルを選択しますここに画像の説明を挿入します
  2. ディレクトリ、
    ここに画像の説明を挿入します
    ファイル管理プログラム、およびクリーンアップ プログラムを選択します。この方法を使用すると、対応するディレクトリとサブディレクトリに対するすべての管理権限を取得できます。
  3. 新しいファイルを作成する
    ここに画像の説明を挿入します
  4. 消去
DocumentsContract.deleteDocument(getContentResolver(),uri);
  1. 改訂

①OutputStreamを取得する

getContentResolver().openOutputStream(uri);

②書き込み可能なParcelFileDescriptorを取得する

getContentResolver().openFileDescriptor(contentUri,"w");
getContentResolver().openFile (contentUri,"w",null);

特定のデモのリファレンス

2.6 アプリ固有のディレクトリへのアクセス

アクセスには2 つの状況がありApp-specific、1 つ目はアクセスApp自身App-specific目录、2 つ目はアクセスです其他App目录文件

2.6.1 アプリ自身のアプリ固有のディレクトリ

Android Q、アプリが開始された場合Filtered View、アプリは独自のディレクトリ内のファイルにのみ直接アクセスできます。

  1. Android Q では、 Environment.getExternalStorageDirectory および getExternalStoragePublicDirectoryインターフェイス
    が廃止されました。アプリはフィルターされたビューであり、このディレクトリに直接アクセスできません。

  2. ファイル (「/sdcard/」) を介したアプリへのアクセスはフィルターされたビューであり、このディレクトリに直接アクセスすることはできません
  3. アプリ固有のディレクトリを取得します
    Media インターフェイスを取得します: getExternalMediaDirs
    Cache インターフェイスを取得します: getExternalCacheDirs
    Obb インターフェイスを取得します: getObbDirs
    Data インターフェイスを取得します: getExternalFilesDirs

2.6.2 アプリ固有のディレクトリ内のマルチメディア ファイル

アプリ固有のディレクトリ内のマルチメディア ファイル:

  1. アプリ自身のアクセスはApp-specific2.6.1 アプリ自身のディレクトリと同じです
  2. 他のアプリからのアクセス
    ① デフォルトでは内部のマルチメディアファイルはスキャンされません スキャンが必要な場合はデータベースに追加する必要Media Scannerがありますアクセス方法は2.5パブリックディレクトリの読み書きと同じです シェアリングでアプリを共有App-specificMediaScannerConnection.scanFileMediaProvider

    ContentProvider

2.6.3 その他のアプリディレクトリファイル

アプリはフィルターされたビューです。他のアプリは現在のアプリのプライベート ディレクトリに直接アクセスできません。次の方法を使用する必要があります:

2.6.3.1 SAF ファイル経由
  1. アプリのカスタマイズを共有するDocumentsProvider

アプリのカスタマイズにDocumentsProviderは次の手順が必要です。
a) 指定するDocumentsProvider
ここに画像の説明を挿入します

b)DocumentsProvider基本インターフェイスを実装します。
ここに画像の説明を挿入します
ここに画像の説明を挿入します

  1. アプリにアクセスしACTION_OPEN_DOCUMENTてブラウジングを開始する
    ここに画像の説明を挿入します

ここに画像の説明を挿入します
ここに画像の説明を挿入します

2.6.3.2 FileProviderを実装する共有アプリ

FileProvider 固有の使用法のリファレンス

一般的な手順の概要は次のとおりです。

  1. 指定App FileProvider
    ここに画像の説明を挿入します

  2. ファイルパスを指定します。構成ファイルはres/xmlに配置する必要があります。
    ここに画像の説明を挿入します

  3. 共有 URI を取得する
    ここに画像の説明を挿入します

  4. 権限を設定して URI を送信する
    ここに画像の説明を挿入します
    ここに画像の説明を挿入します

  5. アプリを受信し、受け付けたインターフィルターを設定する
    ここに画像の説明を挿入します

  6. Uriの受信と処理
    ここに画像の説明を挿入します

2.6.3.3 アプリのカスタムプライベートプロバイダー

ContentProviderアプリは特にカスタマイズできます内部文件共享が、UI の操作は期待されていません。

2.7 メディアストア

2.7.1 MediaStore_data フィールド

MediaStoreでは、DATA即(_data)字段Android Q放棄され始めました。ファイルの読み取りと書き込みには を渡す必要がありますopenFileDescriptor

2.7.2 MediaStore ファイルの保留ステータス

Android Q では、現在のファイルのステータスをマークするために がMediaStore追加されました。他のアプリはファイルをクエリします。インターフェイスが設定されていない場合、保留ステータスに設定されているファイルはクエリできません。これにより、アプリにはこのファイルへの排他的アクセスが与えられます。ダウンロード時など、いくつかの状況で使用されます。ダウンロード中、ファイルは保留中ステータスでダウンロードが完了し、ファイルの保留中ステータスは 0 に設定されます。IS_PENDING FlagPending
MediaStoresetIncludePending
ここに画像の説明を挿入します

2.7.3 MediaColumns.RELATIVE_PATH はストレージ パスを設定します

Android Qでは、MediaStoreパブリックディレクトリにファイルを保存することで、2.5.1.2項のUriとパブリックディレクトリの関係で指定した各記憶領域の第1階層ディレクトリに加え、MediaColumnsを通じて保存先の第2ディレクトリを指定することができます。 RELATIVE_PATH. このディレクトリ 複数のレベルを作成できます。具体的なコードは次のとおりです。

  1. ContentResolver の挿入メソッドは、
    values.put(Media.RELATIVE_PATH,"Pictures/album/family ") を通じて保存ディレクトリを指定します。このうち、Pictures は第 1 レベルのディレクトリであり、album/family はサブディレクトリです。
  2. ContentResolver の更新メソッドは、
    values.put(Media.RELATIVE_PATH,"Pictures/album/family ") を通じて保存ディレクトリを指定します。update メソッドを使用すると、保存場所を移動できます。

2.7.4 画像の Exif メタデータへのアクセス

Android Q では、アプリが画像の Exif メタデータにアクセスする必要がある場合、次の操作を行う必要があります。

  1. 適用するACCESS_MEDIA_LOCATION权限
  2. デモコードは次のとおりですMediaStore.setRequireOriginal返回新Uri

    ここに画像の説明を挿入します

2.7.5 アプリのフィルター ビュー、アクセス許可の概要

さまざまなディレクトリにアクセスするためのアプリの権限は次のように要約されます。
ここに画像の説明を挿入します

2.7.6 アプリケーションのアンインストール

アプリがAndroidManifest.xml次のように宣言している場合:android:hasFragileUserData="true"
アプリをアンインストールするときに、アプリ データを保持するかどうかを尋ねるメッセージが表示されます。
ここに画像の説明を挿入します

2.7.7 アプリデータの移行

Android Q では、App TargetSDK>=Qデフォルトは ですFiltered Viewアプリがフィルター ビューの場合、データの移行が必要になります。そうでない場合、古いデータは使用できなくなります。データ移行は次の側面から開始できます。

  1. ストレージを操作するための完全な権限を得るには、アプリLegacy Viewをダウンロードする
  2. 非公開領域に保存されているアプリ ファイルには、SAF访问SAF を通じてディレクトリ ファイルを選択することでアクセスでき、ユーザーはアプリ ファイルへのアクセスを選択できます。
    ここに画像の説明を挿入します

  3. Imagesアプリは、保存する必要があるファイルを対応するパブリック ディレクトリに配置できます。その他のファイルは、アンインストール後にファイルを削除せずにその下にVideo配置Audioできます。Downloads

2.7.8 MediaStore クエリ

MediaStoreアクションを実行するために使用する場合queryProjection使用する場合は、で定義するColumn Name必要がありますMediaStore

2.8 WRITE_MEDIA_STORAGE権限

2.8.1 背景

WRITE_MEDIA_STORAGEこれは、アプリがすべてのストレージ デバイスにアクセスできるようにする非常に強力な権限です。すべてのストレージ デバイスへのアクセス許可。これはメディア スタックにのみ与えられる必要があります。

2.8.2 互換性への影響

Android システムでは、ユーザー グループWRITE_MEDIA_STORAGEを取得できることが規定されていますmedia_rw
ここに画像の説明を挿入します

  1. T カードや U ディスクなどのすべてのリムーバブル ストレージ デバイスについて、Android にマウントされている場合、通常のアプリには読み取り権限のみがあり、書き込み権限はありません。リムーバブル ストレージ デバイスに書き込むことができるのは、media_rw ユーザー グループ アプリのみです。
  2. Android Q のスコープ付きストレージの場合、この権限を使用してアプリが互換モードで実行されるように設定できます。
  3. Android CTS がテストを実施します。ユーザーが起動可能なアプリはこの許可を申請できません。
    詳細については、「Android Bootcamp 2019 - Privacy About.pdf」を参照してください。

2.8.3 適応

アプリがMediaまたはにアクセスする必要がある場合は、または を外置存储设备使用できますMediaStoreStorage Access Framework(SAF)接口

3 まとめ

さて、要約は次のとおりです。

  1. App TargetSDK > 28 即 Android10(Q)及以上プロジェクト、Google はストレージ サンドボックス モードを制限しました。Android10(Q)以上的设备推奨される使用法では私有目录data/data、直接アクセスできなくなりました外部SD卡存储目录。使用する必要がある場合は、インターフェース外部SD卡存储目录を介してアクセスする必要があり、アクセスできるの、、、、、、など_ _ これらの外部 SD カード ストレージ ディレクトリ (パブリック ディレクトリ) はすべてのアプリからアクセスできるため、あまり安全ではありません。SAFMediaStore特定的外部SD卡存储目录DownloadsDocumentsPicturesDCIMMoviesMusicRingtones
  2. App TargetSDK <= 28 即 Android10(Q)以下WRITE_MEDIA_STORAGEプロジェクトは、権限がある限り無制限ですREAD_MEDIA_STORAGEしたがって、外部 SD ストレージを変更したくない場合は、プロジェクトの targetSdk を <=28 に変更してください。
  3. SAFインターフェイスMediaStoreへのアクセス方法については外部SD卡存储特定目录、上記の説明を参照するか、詳細は公式ドキュメントを参照してください。ここではMediaStore参考用に使用方法のデモを示します外部SD卡存储特定目录[スター] をクリックすることを忘れないでください。

おすすめ

転載: blog.csdn.net/u010687761/article/details/133200887