既存のメディアファイルへ、アクセスする許可を取得するためのリクエストが、Media Store APIに準備されています。
このリクエストで許可を得たアプリは、ファイルの所有者に関係なく、アクセスが可能になります。
このリクエストの中の、createDeleteRequestについて、まとめます。
削除する許可を取得するリクエストです。
※環境:Android Studio Narwhal Feature Drop | 2025.1.2 Patch 1
Media Storeのリクエスト
Media Storeに、表のようなリクエストが準備されています。
リクエスト
(MediaStore.***) | 概要 | 許可後の動作 |
createWriteRequest | 書き込み許可を要求 | URIへ書き込み(更新)可能 |
createDeleteRequest | 削除する許可を要求 | 即時に削除 |
createTrashRequest | 廃棄する許可を要求 | ゴミ箱へ廃棄したと見なされる
(is_trashedカラムを設定)
一定時間経過後にシステムが削除 |
createFavoriteRequest | お気に入り登録する許可を要求 | お気に入り登録したと見なされる
(is_favoriteカラムを設定) |
※許可はアプリに対して与えられる |
いずれも、アプリが既存ファイル(自アプリ・他アプリが所有するファイル)へアクセスする許可を取得するためのリクエストです。
このリクエストを使うと、ダイアログが表示されて、ユーザーに許可・拒否の判定を求めます。
許可されたら、アクセスが実行されます。
許可の取得手順
許可の取得は、次のような手順で行います。

手順1
削除対象のURIを準備。Clientアプリを起動します。
手順2
Clientアプリはダイアログを表示して、削除する許可・拒否の判定を求めます。
手順3
ダイアログによる判定の結果をコールバックで返します。
手順1~3はアプリケーションコンポーネント(Activity)の連携と同じ動作です。
※詳細は「App component:Activity」を参照
削除の例
削除の具体的な例です。※Activity Result APIで記述しています。
コールバックの定義と登録
registerForActivityResultはコールバックの定義と登録を行います。
ラムダ式がコールバックです。「許可・拒否」はresultCodeで判断できます。
そして、このコールバックを利用するコンポーネントのランチャー(_MediaDeleteDialog : ActivityResultLauncher)を返します。
val _MediaDeleteDialog = registerForActivityResult(
ActivityResultContracts.StartIntentSenderForResult()
) { result ->
if(result.resultCode == RESULT_OK) { // アクセス許可
/* ここが実行される時点で、すでに削除済み */
}
else { } // アクセス拒否
}
registerForActivityResultは、LifecycleOwnerのcurrentStateが「STARTED」より前のタイミングで実行して下さい。Activityのライフサイクルと密接に関係しています。
※LifecycleOwnerについては「ライフサイクル対応コンポーネント作成」を参照
許可チェックとダイアログ起動
削除対象のURIを準備します。その後、Clientアプリを起動(launch)し、ダイアログを表示させます。
launchの引数は取得したい許可のリクエスト(MediaDeleteReq : IntentSenderRequest)です。削除を行いたいのでMediaStore.createDeleteRequestを使って、リクエストを構築しています。
@RequiresApi(Build.VERSION_CODES.R)
fun onDelete(uri: Uri, id: Long) {
val _uri = ContentUris.withAppendedId(uri, id) // URIを準備
_MediaDeleteDialog.launch(MediaDeleteReq(contentResolver, _uri))
}
@RequiresApi(Build.VERSION_CODES.R)
fun MediaDeleteReq(resolver: ContentResolver, uri: Uri): IntentSenderRequest {
val _pendingIntent = MediaStore.createDeleteRequest(resolver, listOf(uri))
val _intentSenderRequest = IntentSenderRequest.Builder(
_pendingIntent.intentSender
).build()
return _intentSenderRequest
}
MediaStore.createDeleteRequestはAPI≧30から利用が可能です。
削除の実行
削除の実行(onDelete)を行うと、ダイアログが表示されて、ユーザに「許可・拒否」の判定を求めます。
val _uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val _id = 1000000033
// val _uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
// val _id = 1000000034
// val _uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
// val _id = 1000000035
onDelete(_uri, _id)
メディアテーブルの状態
# pwd
/data/data/com.google.android.providers.media.module/databases
# sqlite3 ./external.db
sqlite> .headers on
sqlite> .mode column
sqlite> select _id,_display_name,_data from images;
_id _display_name _data
---------- ------------- -------------------------------------
1000000033 leaf.jpg /storage/emulated/0/Pictures/leaf.jpg
sqlite> select _id,_display_name,_data from video;
_id _display_name _data
---------- ------------- --------------------------------------
1000000034 myroom.mpeg /storage/emulated/0/Movies/myroom.mpeg
sqlite> select _id,_display_name,_data from audio;
_id _display_name _data
---------- ------------- --------------------------------------
1000000035 akatonbo.mp3 /storage/emulated/0/Music/akatonbo.mp3
※エミュレータ(API 33)で確認
メディアデータの状態
# pwd
/storage/emulated/0
# ls -l Pictures/* Movies/* Music/* */.thumbnails/*
-rw-rw---- 1 u0_a170 media_rw 5349 2025-08-22 12:09 Movies/.thumbnails/1000000034.jpg
-rwxrwx--- 1 u0_a170 media_rw 195759 2025-08-22 12:09 Movies/myroom.mpeg
-rw-rw---- 1 u0_a170 media_rw 11472 2025-08-22 12:11 Music/.thumbnails/1000000035.jpg
-rwxrwx--- 1 u0_a170 media_rw 45366 2025-08-22 12:09 Music/akatonbo.mp3
-rw-rw---- 1 u0_a170 media_rw 34088 2025-08-22 12:08 Pictures/.thumbnails/1000000033.jpg
-rwxrwx--- 1 u0_a170 media_rw 47891 2025-08-22 12:08 Pictures/leaf.jpg
※エミュレータ(API 33)で確認
なお、ダイアログに表示される画像はサムネイル(.thumbnail/メディア情報のID.jpg)です。
「許可」となったURIは、このアプリにより削除が可能です。
そして、システムにより、このURIに関係する全てのデータ(データベースのレコード、ファイル、サムネイル)が即時に削除されます。ユーザ側で削除処理をする必要はありません。
判定の結果をコールバックで返す時点で、すでに削除済みです。注意して下さい。
対象をグループで指定
URIをリストで指定すると、複数のURIをグループとして、一括で削除できます。
@RequiresApi(Build.VERSION_CODES.R)
fun onDelete(uri: Uri, ids: Array<Long>) {
val _uris = ids.map { ContentUris.withAppendedId(uri, it) } // URIを準備
_MediaDeleteDialog.launch(MediaDeleteReq(contentResolver, _uris))
}
@RequiresApi(Build.VERSION_CODES.R)
fun MediaDeleteReq(resolver: ContentResolver, uris: List<Uri>): IntentSenderRequest {
val _pendingIntent = MediaStore.createDeleteRequest(resolver, uris)
val _intentSenderRequest = IntentSenderRequest.Builder(
_pendingIntent.intentSender
).build()
return _intentSenderRequest
}
val _uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val _ids = arrayOf(1000000033, 1000000034, 1000000035, 1000000036)
onDelete(_uri, _ids)
メディアテーブルの状態
# pwd
/data/data/com.google.android.providers.media.module/databases
# sqlite3 ./external.db
sqlite> .headers on
sqlite> .mode column
sqlite> select _id,_display_name,_data from images;
_id _display_name _data
---------- ------------- -------------------------------------
1000000033 leaf.jpg /storage/emulated/0/Pictures/leaf.jpg
1000000034 donguri.jpg /storage/emulated/0/Pictures/donguri.
1000000035 bike.jpg /storage/emulated/0/Pictures/bike.jpg
1000000036 fall.jpg /storage/emulated/0/Pictures/fall.jpg
※エミュレータ(API 33)で確認
メディアデータの状態
# pwd
/storage/emulated/0
# ls -l Pictures/* */.thumbnails/*
-rw-rw---- 1 u0_a163 media_rw 34088 2025-08-23 00:50 Pictures/.thumbnails/1000000033.jpg
-rw-rw---- 1 u0_a163 media_rw 16914 2025-08-23 00:51 Pictures/.thumbnails/1000000034.jpg
-rw-rw---- 1 u0_a163 media_rw 22749 2025-08-23 00:51 Pictures/.thumbnails/1000000035.jpg
-rw-rw---- 1 u0_a163 media_rw 32504 2025-08-23 00:52 Pictures/.thumbnails/1000000036.jpg
-rwxrwx--- 1 u0_a163 media_rw 126143 2025-08-23 00:51 Pictures/bike.jpg
-rwxrwx--- 1 u0_a163 media_rw 54206 2025-08-23 00:51 Pictures/donguri.jpg
-rwxrwx--- 1 u0_a163 media_rw 82076 2025-08-23 00:52 Pictures/fall.jpg
-rwxrwx--- 1 u0_a163 media_rw 47891 2025-08-23 00:50 Pictures/leaf.jpg
※エミュレータ(API 33)で確認
ダイアログに表示されるサムネイルは、表示範囲から溢れたものが、重ねられて表示されます。つまり、省略されてしまいます。
「許可・拒否」という重大な判断をユーザーに求めているのに、判断材料になる情報を省略してもよいのか?!、疑問です。ですので、私としてはグループ指定をお勧めしません。

「許可」となった(グループ指定された)URIは、このアプリにより削除が可能です。
そして、システムにより一括で消去されます。
関連記事:
ストレージのリソースは、内部メモリー、外部メモリー、クラウドの3つがあります。 外部メモリーは、主にSDカードです。 このSDカードはAndroid端末の世代が進むにつれて、扱いを変えてきました。 リソースとSDカードを主眼に置いたストレージの変遷について、まとめます。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
Adoptable Storage(API≧23、Android 6.0)が導入されて、SDカードの扱い方をユーザ側で指定できるようになりました。 「Adoptable Storage」について、まとめます。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
ストレージはデータの用途別に記憶領域が分けられます。 保存先を守らないと、セキュリティリスクが発生したり、他のアプリと協調した動作が出来なくなったり、します。 ですので、適切な場所へデータを保存しましょう。 今回は「用途別記憶領域とボリューム」について、まとめます。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
ストレージへアクセスする方法は、「扱うデータの種類」「アクセス先」「セキュリティの確保」などの要件により、最適なアクセス方法が存在するので、使い分けが必要です。 今回は「アクセスする方法」について、まとめます。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
「内部ストレージ」にアクセスする方法について、まとめます。 「内部ストレージ」は、セキュリティが高いうえに、端末の内部メモリーに構築されるので、必ず存在します。 使いたい時に安心して使え、もっとも使い勝手のよいストレージと言えます。 アプリのデータを保存したいならば、保存先として真っ先に考えるストレージです。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
外部ストレージへアクセスするアプリは、パーミッション(許可)をユーザーから取得する必要があります。 パーミッションを得たアプリは、許可された権限の範囲内で、ストレージへアクセスが可能です。 これらは、ユーザーデータのプライバシー保護と密接に関係しています。 プライバシー保護をより強固にするために、パーミッションと権限の範囲の仕様は改変されてきました。 今回は、改変の歴史を辿りつつ、「パーミッションと権限の範囲」について、まとめます。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
「外部ストレージ_プライマリ」にアクセスする方法について、まとめます。 「外部ストレージ_プライマリ」は、アプリ間で共有するデータを保存するストレージです。 主にカメラ、音楽プレーヤー、動画プレーヤーで扱うデータを保存します。 「外部ストレージ_プライマリ」に保存したデータは、他のアプリに公開することになるので、秘匿性の高いデータの保存に適しません。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
「外部ストレージ_セカンダリ」にアクセスする方法について、まとめます。 「外部ストレージ_セカンダリ」は、デバイス間(または、アプリ間)で共有するデータを保存するストレージです。 デバイスとは、他の携帯端末やパソコンなどを指します。 ストレージがSDカードのような取り外し可能なリソース上に構築されているので、データの共有は取り外したストレージを他のデバイスへ取り付けて行います。 「外部ストレージ_セカンダリ」に保存したデータは、他のデバイスに公開することになるので、秘匿性の高いデータの保存に適しません。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
「外部ストレージ_プライマリ」に保存されるメディアデータは、Media Storeと呼ばれる特別な方法でアクセスします。 他の方法も可能ですが、Media Storeが最も適した方法です。 この「メディアデータへMedia Storeでアクセス」する方法を、まとめます。 この記事は、Imagesデータ編です。また、基本的なアクセス(読み書き)に的を絞って説明しています。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
メディアデータはデータベースによって管理されています。 Media Store APIを使ってメディアデータへアクセスしているのであれば、データベースの所在や構成などを意識する必要はありません。 ただ、「より複雑な制御をしたい場合」や「デバックを効率化したい場合」などに、データベースの知識が役立ちます。 今回は「メディアデータのデータベースによる管理」について、まとめます。 この記事は、Imagesデータ編です。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
「外部ストレージ_プライマリ」に保存されるメディアデータは、Media Storeと呼ばれる特別な方法でアクセスします。 他の方法も可能ですが、Media Storeが最も適した方法です。 この「メディアデータへMedia Storeでアクセス」する方法を、まとめます。 この記事は、Imagesデータ編です。また、基本的なアクセス(読み書き)に的を絞って説明しています。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
メディアデータはデータベースによって管理されています。 Media Store APIを使ってメディアデータへアクセスしているのであれば、データベースの所在や構成などを意識する必要はありません。 ただ、「より複雑な制御をしたい場合」や「デバックを効率化したい場合」などに、データベースの知識が役立ちます。 今回は「メディアデータのデータベースによる管理」について、まとめます。 この記事は、Imagesデータ編です。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
「外部ストレージ_プライマリ」に保存されるメディアデータは、Media Storeと呼ばれる特別な方法でアクセスします。 他の方法も可能ですが、Media Storeが最も適した方法です。 別の記事で「メディアデータへMedia Storeでアクセス」する方法を、まとめました。 その記事は、基本的なアクセスとして「追加(insert)&読み書き」のみを説明しています。 この記事は、上記に加えて「参照(query)・更新(update)・削除(delete)」を説明します。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
「外部ストレージ_プライマリ」に保存されるメディアデータは、データベースで管理されます。 Media Storeを使うと、このデータベースを通してメディアデータへアクセスできます。 データベース(SQLite)が持つ検索機能を使ってアクセス対象を絞り込めるので、とても便利です。 この記事は、「絞り込みアクセス」について、まとめます。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
メディアデータはMedia Storeを使ったアクセスが最適です。 その理由は、メディア特有の付加情報を使って、データを管理できるからです。 管理されたデータはブログラムから扱い易いです。また、ユーザの使い勝手(エクスペリエンス)も向上します。 バケットはメディアデータを管理する付加情報の一つです。 無くてもアクセスは可能ですが、積極的に取り入れた方が良いと思います。 今回は「ファイル名とバケットを指定したアクセス」について、まとめます。 「API≦28」と「API≧29」で動作が異なります。注意して下さい。 ※環境:Android Studio Narwhal Feature Drop | 2025.1.2 ...
メディアデータはMedia Storeを使ったアクセスが最適です。 その理由は、メディア特有の付加情報を使って、データを管理できるからです。 管理されたデータはブログラムから扱い易いです。また、ユーザの使い勝手(エクスペリエンス)も向上します。 バケットはメディアデータを管理する付加情報の一つです。 無くてもアクセスは可能ですが、積極的に取り入れた方が良いと思います。 今回は「ファイル名とバケットを指定したアクセス」について、まとめます。 「API≦28」と「API≧29」で動作が異なります。注意して下さい。 ※環境:Android Studio Narwhal Feature Drop | 2025.1.2 ...
メディアデータはアプリ間で共有されるので、アプリがデータへアクセスするには、アクセス許可が必要です。 この許可の権限の範囲は、プライバシー保護の観点から、徐々に狭められてきました。 そして、対象範囲別ストレージにおいて、他アプリが所有するファイルへの書き込みは、URI(ファイル)毎の許可が必要になっています。 許可の取得は、ユーザと対話をする形式(ダイアログ)で行われます。手順が少し複雑です。 ここに「他アプリが所有するファイルへ書き込み」する方法を、まとめます。 ※環境:Android Studio Narwhal Feature Drop | 2025.1.2 Patch 1 ...