写真と動画への部分的なアクセス権を付与する

Android 14 では、「選択した写真へのアクセス」機能が導入され、ユーザーがアプリを許可できる ライブラリ内の特定の画像や動画に対する 特定のタイプのすべてのメディアへのアクセスが許可されます。

この変更は、アプリが Android 14(API ������� 34��または 高くなります。写真選択ツールをまだ使用していない場合は、実装することをおすすめします。 アプリを使用して、一貫性のある方法で画像や動画を選択できます。 ストレージをリクエストしなくてもユーザーのプライバシーを強化できる 付与できます。

ストレージの権限を使用して独自のギャラリー選択ツールを維持していて、 実装を完全に管理できる、実装を調整する 新しい READ_MEDIA_VISUAL_USER_SELECTED 権限を使用する。アプリが 新しい権限を使用しない場合、システムは互換性がある環境で モード

対象 SDK READ_MEDIA_VISUAL_USER_SELECTED が宣言されました 選択した写真へのアクセスが有効になりました UX の動作
SDK 33 × × なし
アプリによる制御
SDK 34 × システムで制御(互換動作)
アプリによる制御

独自のギャラリー選択ツールを作成するには、広範な開発とメンテナンスが必要です。 また、アプリはストレージ権限をリクエストして、ユーザーの明示的な同意を得る必要があります。 ユーザーはこれらのリクエストを拒否できます。アプリが Android 14(API レベル 34)以降をターゲットとするアプリの場合、制限 選択したメディアへのアクセス。次の画像は、3 つの Google Cloud Storage バケットを 新しいオプションを使用してメディアを選択できるようになりました。

<ph type="x-smartling-placeholder">
</ph> .
図 1.新しいダイアログでは アプリで利用できるようにしたい写真や動画 通常のオプションに移動し、完全アクセス権を付与するか、すべてのアクセスを拒否します。

このセクションでは、独自のギャラリーを作成する場合のおすすめの方法を説明します。 MediaStore を使用した選択ツールです。すでにアプリのギャラリー選択ツールを保持している場合 完全な制御を維持する必要がある場合は、これらの例を使用して 説明します。選択済みの API を処理するように実装を更新しない場合は、 フォトへのアクセス: アプリは互換モードで実行されます。

権限をリクエストする

まず、Android マニフェストで適切なストレージ権限をリクエストします。 OS バージョンによって異なります。

<!-- Devices running Android 12L (API level 32) or lower  -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />

<!-- Devices running Android 13 (API level 33) or higher -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

<!-- To handle the reselection within the app on devices running Android 14
     or higher if your app targets Android 14 (API level 34) or higher.  -->
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />

次に、OS のバージョンに応じて適切な実行時の権限をリクエストします。

// Register ActivityResult handler
val requestPermissions = registerForActivityResult(RequestMultiplePermissions()) { results ->
    // Handle permission requests results
    // See the permission example in the Android platform samples: https://github.com/android/platform-samples
}

// Permission request logic
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
    requestPermissions.launch(arrayOf(READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_VISUAL_USER_SELECTED))
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
    requestPermissions.launch(arrayOf(READ_MEDIA_IMAGES, READ_MEDIA_VIDEO))
} else {
    requestPermissions.launch(arrayOf(READ_EXTERNAL_STORAGE))
}

権限が必要ないアプリもあります

Android 10(API レベル 29)以降では、アプリに追加するためにストレージのアクセス許可は不要になりました。 共有ストレージに保存できますつまり、アプリはギャラリーに画像を追加したり、 動画の録画と共有ストレージへの保存も、PDF 形式の請求書のダウンロードも行えます。 ストレージ権限をリクエストする必要もありません。アプリが であり、画像や動画に対してクエリを実行しない場合は、ストレージのリクエストを停止してください。 許可し、AndroidManifest.xml で API 28 の maxSdkVersion を設定します。

<!-- No permission is needed to add files to shared storage on Android 10 (API level 29) or higher  -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="28" />

メディアの再選択を処理する

Android 14 の「選択した写真へのアクセス」機能では、アプリで メディアを操作するための新しい READ_MEDIA_VISUAL_USER_SELECTED 権限 再度選択し、アプリのインターフェースを更新して、ユーザーがアプリへのアクセスを付与できるようにします 画像と動画のセットを変更できます次の図に、Google Cloud で 権限のリクエストとメディアの再選択:

<ph type="x-smartling-placeholder">
</ph> .
図 2.新しいダイアログでは アプリで利用できるようにしたい写真や動画を選択します

選択ダイアログを開くと、写真、動画、またはその両方が表示される 権限を制御します。たとえば、IP アドレスの READ_MEDIA_IMAGES 権限のない READ_MEDIA_VIDEO 権限のみ ユーザーがファイルを選択するための UI に動画が表示されました。

// Allow the user to select only videos
requestPermissions.launch(arrayOf(READ_MEDIA_VIDEO, READ_MEDIA_VISUAL_USER_SELECTED))

デバイスの認証情報への完全なアクセス権、部分的なアクセス権、または拒否する権限があるかどうかを それに応じてインターフェースを更新します。これらの権限をリクエストする アプリがストレージへのアクセスを必要とするときに(起動時ではなく)なお、 onStart アプリと onResume アプリの間で権限の付与を変更できる ライフサイクル コールバックを呼び出せます。これによりユーザーは、変更せずに設定でアクセスを 閉じることができます。

if (
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
    (
        ContextCompat.checkSelfPermission(context, READ_MEDIA_IMAGES) == PERMISSION_GRANTED ||
        ContextCompat.checkSelfPermission(context, READ_MEDIA_VIDEO) == PERMISSION_GRANTED
    )
) {
    // Full access on Android 13 (API level 33) or higher
} else if (
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE &&
    ContextCompat.checkSelfPermission(context, READ_MEDIA_VISUAL_USER_SELECTED) == PERMISSION_GRANTED
) {
    // Partial access on Android 14 (API level 34) or higher
}  else if (ContextCompat.checkSelfPermission(context, READ_EXTERNAL_STORAGE) == PERMISSION_GRANTED) {
    // Full access up to Android 12 (API level 32)
} else {
    // Access denied
}

デバイス ライブラリをクエリする

適切なストレージ権限にアクセスできることを確認したら、次のことができます。 MediaStore を操作してデバイス ライブラリをクエリする(同じアプローチが機能する) 付与されるアクセス権が部分的か完全か):

data class Media(
    val uri: Uri,
    val name: String,
    val size: Long,
    val mimeType: String,
)

// Run the querying logic in a coroutine outside of the main thread to keep the app responsive.
// Keep in mind that this code snippet is querying only images of the shared storage.
suspend fun getImages(contentResolver: ContentResolver): List<Media> = withContext(Dispatchers.IO) {
    val projection = arrayOf(
        Images.Media._ID,
        Images.Media.DISPLAY_NAME,
        Images.Media.SIZE,
        Images.Media.MIME_TYPE,
    )

    val collectionUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        // Query all the device storage volumes instead of the primary only
        Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL)
    } else {
        Images.Media.EXTERNAL_CONTENT_URI
    }

    val images = mutableListOf<Media>()

    contentResolver.query(
        collectionUri,
        projection,
        null,
        null,
        "${Images.Media.DATE_ADDED} DESC"
    )?.use { cursor ->
        val idColumn = cursor.getColumnIndexOrThrow(Images.Media._ID)
        val displayNameColumn = cursor.getColumnIndexOrThrow(Images.Media.DISPLAY_NAME)
        val sizeColumn = cursor.getColumnIndexOrThrow(Images.Media.SIZE)
        val mimeTypeColumn = cursor.getColumnIndexOrThrow(Images.Media.MIME_TYPE)

        while (cursor.moveToNext()) {
            val uri = ContentUris.withAppendedId(collectionUri, cursor.getLong(idColumn))
            val name = cursor.getString(displayNameColumn)
            val size = cursor.getLong(sizeColumn)
            val mimeType = cursor.getString(mimeTypeColumn)

            val image = Media(uri, name, size, mimeType)
            images.add(image)
        }
    }

    return@withContext images
}

このコード スニペットは、MediaStore の操作方法を示すために簡略化されています。 本番環境対応のアプリでは、Paging ライブラリを使用して、優れたパフォーマンスを確保します。

最後の選択をクエリする

Android 15 以降と Android 14 で Google Play システム アップデートをサポートするアプリは、 部分的なアクセス権を持つユーザーが最後に作成した画像や動画をクエリする QUERY_ARG_LATEST_SELECTION_ONLY を有効にします。

if (getExtensionVersion(Build.VERSION_CODES.U) >= 12) {
    val queryArgs = bundleOf(
        QUERY_ARG_SQL_SORT_ORDER to "${Images.Media.DATE_ADDED} DESC"
        QUERY_ARG_LATEST_SELECTION_ONLY to true
    )

    contentResolver.query(collectionUri, projection, queryArgs, null)
}

デバイスのアップグレード後も、写真と動画へのアクセスは保持される

以前のバージョンの Android から Android 14 にアップグレードするデバイスにアプリがインストールされている場合、システムではそのユーザーの写真と動画への完全アクセス権は維持され、アプリに一部の権限が自動的に付与されます。デバイスが Android 14 にアップグレードされる前にアプリに付与されている権限のセットによって、具体的な動作は異なります。

Android 13 の権限

次のような状況を考えてみましょう。

  1. アプリは Android 13 を搭載したデバイスにインストールされています。
  2. ユーザーがアプリに READ_MEDIA_IMAGES 権限と READ_MEDIA_VIDEO 権限を付与しています。
  3. アプリがインストールされている状態で、デバイスが Android 14 にアップグレードされます。
  4. アプリのターゲットは Android 14(API レベル 34)以降になります。

この場合、アプリは引き続きそのユーザーの写真と動画への完全アクセス権を持ちます。また、アプリに付与されている READ_MEDIA_IMAGES 権限と READ_MEDIA_VIDEO 権限も自動的に保持されます。

Android 12 以前の権限

次のような状況を考えてみましょう。

  1. アプリは Android 13 を搭載したデバイスにインストールされています。
  2. ユーザーがアプリに READ_EXTERNAL_STORAGE 権限または WRITE_EXTERNAL_STORAGE 権限を付与しています。
  3. アプリがインストールされている状態で、デバイスが Android 14 にアップグレードされます。
  4. アプリのターゲットは Android 14(API レベル 34)以降になります。

この場合、アプリは引き続きそのユーザーの写真と動画への完全アクセス権を持ちます。また、READ_MEDIA_IMAGES 権限と READ_MEDIA_VIDEO 権限もアプリに自動的に付与されます。

おすすめの方法

このセクションでは、 READ_MEDIA_VISUAL_USER_SELECTED 権限。詳しくは、 権限に関するおすすめの方法をご覧ください。

権限の状態を永続的に保存しない

SharedPreferencesDataStore を含め、権限の状態を永続的に保存しないでください。保存された状態は、実際の状態と同期していない可能性があります。権限の状態は権限のリセット後に変化することがあります。 アプリの休止状態(ユーザーが開始したアプリの設定変更)や、 アプリがバックグラウンドに移行します代わりに、Terraform を使用してストレージの権限を確認する ContextCompat.checkSelfPermission()

写真と動画への完全アクセス権を持っていることを前提としない

Android 14 で導入された変更により、アプリには一部のみ デバイスのフォト ライブラリへのアクセス。ContentResolver を使用してクエリが行われたときにアプリが MediaStore データをキャッシュに保存していた場合、キャッシュが最新ではない可能性があります。

  • 保存されたキャッシュに依存するのではなく、常に ContentResolver を使用して MediaStore をクエリしてください。
  • アプリがフォアグラウンドにある間、結果をメモリに保持してください。
  • アプリが onResume アプリのライフサイクルに達したら結果を更新する ユーザー アカウント キーを使用して、フルアクセスから部分アクセスに切り替えることができます。 [権限の設定] をクリ���クします。

URI アクセスを一時的なものとして扱う

ユーザーがシステム権限で [写真と動画を選択] を選択した場合、 選択した写真や動画へのアプリのアクセス権が最終的に期限切れになります。 アプリで Uri にアクセスできないケースを常に処理する必要があります。 重要です

選択可能なメディアタイプを権限でフィルタ

選択ダイアログは、リクエストされた権限タイプの影響を受けます。

  • READ_MEDIA_IMAGES のみをリクエストすると、選択可能な画像のみが表示されます。
  • READ_MEDIA_VIDEO のみをリクエストすると、選択可能な動画のみが表示されます。
  • READ_MEDIA_IMAGESREAD_MEDIA_VIDEO の両方をリクエストすると、全体が表示されます。 選択できるようになります。

アプリのユースケースに基づいて、 権限を設定することで、ユーザー エクスペリエンスの低下を防ぐことができます。特徴量が READ_MEDIA_VIDEO のみをリクエストしてください。

1 回のオペレーションで権限をリクエストする

ユーザーに複数のシステム ランタイム ダイアログ ボックスが表示されないようにするには、1 回のオペレーションで READ_MEDIA_VISUAL_USER_SELECTEDACCESS_MEDIA_LOCATION、「読み取りメディア」権限(READ_MEDIA_IMAGESREAD_MEDIA_VIDEO のいずれかまたは両方)をリクエストします。

ユーザーが選択内容を管理できるようにします

ユーザーが部分アクセスモードを選択した場合、アプリで デバイスのフォト ライブラリが空で、ユーザーが追加を許可できるはずです。 できます。

ユーザーは、 一部のビジュアル メディア ファイルへのアクセスを許可せずに、権限の設定を行うことができます。

互換性モード

ストレージの権限を使用して独自のギャラリー選択ツールを維持しているが、 新しい READ_MEDIA_VISUAL_USER_SELECTED を使用するようにアプリを調整 権限を設定すると、ユーザーが特定の権限を持っていないときはいつでも、 メディアを選択または再選択する必要があります。

最初のメディア選択時の動作

最初の選択時に [写真と動画を選択] を選択すると、(参照: 図 1 のように、READ_MEDIA_IMAGES 権限と READ_MEDIA_VIDEO 権限は、 付与され、一時的な権限の付与と、 ユーザーが選択した写真や動画への一時的なアクセス制限。アプリが ユーザーが積極的にアプリを強制終了した場合は、最終的に 拒否されます。この動作は、他の 1 回だけのアクセス許可と同��です。

メディアの再選択時の動作

後からアプリで追加の写真や動画にアクセスする必要が生じた場合は、 READ_MEDIA_IMAGES 権限または READ_MEDIA_VIDEO 権限を再度付与します。システムはトレーニングとデプロイの 最初の許可リクエストの際に、写真や動画を選択するようユーザーに促します( 図 2)。

権限に関するおすすめの設定に沿っているアプリの場合、この変更が適用されません。 問題になります。これは、アプリでこの URI が想定されるものがない場合に、特に当てはまります。 システム権限の状態を保存したり、システム権限セットの 権限の変更後に画像を表示します。ただし、この動作が アプリのユースケースに応じて最適な方法を選択できます。快適にご利用いただくため 写真選択ツールを実装するか、 ギャラリー選択ツールを使用して、 READ_MEDIA_VISUAL_USER_SELECTED 権限。