非常に単純な要件を実装しようとしたとき、 画像をダウンロードしてローカルストレージに保存する — 最初はすべて順調に見えました。.
- Honor(Android 10) – 動作
- Redmi(Android 11) – 動作
- Xiaomi(Android 13) – 動作
- サムスン(Android 13) – 完全に失敗しました: ストレージの許可ダイアログがまったく表示されませんでした
同じコード、同じ機能なのに、Android 13を搭載したデバイスが1台、権限プロンプトを表示してくれませんでした。こうして、この小さな「画像をダウンロード」というタスクが、深刻な問題へと発展したのです。 スコープ付きストレージ そして 外部ストレージの管理.
この投稿では、ストレージの権限をどのように変更したかをまとめています。 Android 11以上, そして、バージョン間でのさまざまな動作をどのように処理するかについて説明します。.
1. バグ:ストレージ権限ダイアログが表示されない(Samsung Android 13)
要件は単純です。
画像をダウンロードしてデバイスに保存すると、ギャラリーに表示されます。.
私の 3 つのテストデバイスでは、次のようになりました。
- Honor – Android 10 → OK
- Redmi – Android 11 → OK
- Xiaomi – Android 13 → OK
しかし、 Android 13 を搭載した Samsung デバイス, 、システム ストレージの許可ダイアログが表示されなかった, 、私がどのように要求したとしても。.



最初は、これは単なる OEM の癖だと思っていましたが、Android バージョン間のストレージ権限の変更を確認した後、SDK 33 をターゲットにしたときに Android 13 で事実上非推奨になっていた動作に依存していることに気付きました。.
2. 根本原因: WRITE/READ_EXTERNAL_STORAGE は Android 13 (SDK 33) で非推奨になっています
以前のバージョンの Android では、マニフェストで次の 2 つの権限を宣言するだけで済みました。
外部ストレージの読み取り外部ストレージへの書き込み
必要に応じて実行時に要求します。.
Android 13(SDK 33)では ターゲットSDKバージョン = 33, 、そのアプローチは崩れ始めます:
外部ストレージへの書き込みは 廃止され、事実上役に立たない 最近のAndroidバージョン- 追加すると
最大SDKバージョン=32これらの権限はAndroid 11/12でも動作します
しかし、彼らは 無視された Android 13で33をターゲットにした場合 - 同時に、Playストアでは新しいアプリは少なくともSDK 33をターゲットにする必要がある。
したがって、Android 11 以降では次の点に適応する必要があります。
- スコープ付きストレージ
- 場合によっては、特別な許可が必要です。
外部ストレージの管理
外部ストレージの管理 アプリにすべての共有ストレージコンテンツ(メディアファイル以外のファイルも含む)への広範なアクセスを許可します。 ない 他のアプリのプライベートディレクトリへのアクセスを許可しますが、Google Play では依然として非常に機密性の高い権限とみなされます。.
さまざまな Android バージョンをサポートするために、権限の処理を次のように分割しました。
- Android 11 以前 (API < 30) – 古いスタイルの外部ストレージ権限
- Android 11以上 – スコープストレージ + 特別な処理
外部ストレージの管理厳密に必要な場合
3. 段階的な適応
3.1 マニフェストでMANAGE_EXTERNAL_STORAGEを宣言する
の中で AndroidManifest.xml:
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />⚠️ 注:
外部ストレージの管理センシティブな権限のため、Google Playでは制限されています。画像を保存したいだけの場合の代替手段については後ほど説明します。.
3.2 権限が付与されているかどうかを確認する
私は 簡単な権限 権限チェックを簡素化します。.
private fun checkPer(activity: PreViewActivity): Boolean { return if (Build.VERSION.SDK_INT >= 30) { EasyPermissions.hasPermissions( activity, android.Manifest.permission.MANAGE_EXTERNAL_STORAGE ) } else { EasyPermissions.hasPermissions( activity, android.Manifest.permission.WRITE_EXTERNAL_STORAGE ) } }
- の上 Android 11以降(API >= 30): 確認しました
外部ストレージの管理 - の上 Android 10以下: 私はまだ確認します
外部ストレージへの書き込み
この分割は重要です。 外部ストレージへの書き込み 新しいバージョンでは動作しなくなりました。.
3.3 権限がない場合に権限を要求する
許可が与えられない場合は、システムのバージョンに応じて異なる方法で許可を要求します。.
private fun requestStoragePermission(activity: PreViewActivity, curImg: Int) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // Android 11+ – システムの「すべてのファイルへのアクセス」設定ページにリダイレクトします val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION) intent.data = Uri.parse("package:" + activity.packageName) activity.startActivityForResult(intent, 200) } else { // Android 10 以下 – 通常のランタイム権限 val perm = android.Manifest.permission.WRITE_EXTERNAL_STORAGE PaperThreeVariable.isToRequestPer = true EasyPermissions.requestPermissions( PermissionRequest.Builder( activity, 200, perm ).build() ) } }
- の上 Android 11以降: 通常のランタイムダイアログを「ポップ」するだけでは
外部ストレージの管理
ユーザーをシステム設定ページに送信し、「すべてのファイルへのアクセス」を手動で許可する必要があります。. - の上 Android 10以下: 従来のランタイム権限ダイアログは引き続き機能します。.
3.4 権限コールバックの処理
EasyPermissions は、Activity のコールバックと独自のロジックを橋渡しするのに役立ちます。
オーバーライド fun onRequestPermissionsResult( requestCode: Int, 権限: Array , grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this) } override fun onPermissionsGranted(requestCode: Int, perms: MutableList ) { AppInitUtils().saveFreshAppImageToGallery(this, curImg) PaperThreeVariable.isToRequestPer = false } オーバーライド fun onPermissionsDenied(requestCode: Int, perms: MutableList ) { PaperThreeVariable.isToRequestPer = false if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) { AppSettingsDialog.Builder(this) .setRationale("この機能を使用するには、ストレージ権限を有効にする必要があります") .setNegativeButton("No") .setPositiveButton("Yes") .build() .show() } }
ここで EasyPermissions を使用する理由:
- ユーザーは 永久に拒否する 権限により、繰り返しのリクエストがサイレントに失敗する
- EasyPermissions を使用すると、次のことが簡単になります。
- 「永久に拒否」状態を検出する
- ユーザーを誘導するダイアログを表示する システム設定 → アプリの権限 ストレージアクセスを手動で有効にする
許可が与えられたら、次のように呼び出します。
AppInitUtils().saveFreshAppImageToGallery(this, curImg)
実際に画像を保存し、ギャラリーを更新します。.
この適応後、Samsung Android 13 デバイスは最終的に他のデバイスと同じように動作するようになりました。.
補足: 私の Xiaomi デバイスは Android 13 として報告されましたが、Android Studio の「接続済みデバイスの履歴」では Android 12 として認識されました。これが、それでも一部のケースで機能した理由を説明している可能性がありますが、これがまさにバージョンに応じた権限処理が重要である理由です。.
4. MANAGE_EXTERNAL_STORAGEとGoogle Playの制限について
外部ストレージの管理 強力です:
読み取り/書き込みアクセスを許可します すべての共有ストレージ デバイス上で。.
このため、Google Playではこれを 非常に機密性の高い許可:
- 主な目的は ファイルマネージャー / バックアップ / ウイルス対策 タイプアプリ
- 使用するには正当な理由を提出する必要がある
- もしあなたのアプリが典型的な消費者向けアプリ(例えば、画像の保存や簡単なダウンロード)であれば、あなたのリクエストはおそらく 拒否された
したがって、唯一の要件が次のとおりである場合:
“「画像をギャラリーに保存し、ユーザーが閲覧できるようにします。」”
ならば 避けることを強く検討する 外部ストレージの管理 代わりに:
- 使用 メディアストア システムメディアライブラリに画像を挿入する
- または、完全なファイルアクセスを必要とせずに画像を保存できるAPIを使用する
次のようないくつかのパターンがあります。
- 画像をPictures/DCIMディレクトリに保存する
- メディアスキャナに通知するか、ギャラリーが受け取れるようにMediaStoreを利用する
- これらすべてを行う MANAGE_EXTERNAL_STORAGEを要求せずに
社内またはPlayストア以外での配布(企業内部のアプリストアなど)の場合、技術的には引き続き使用できます。 環境.getExternalStorageDirectory(), ただし、2025 年にこれに基づいて新しいアプリを設計することはお勧めしません。.
5. バージョンごとのまとめ(Android 9 → 13)
すべてを 1 か所にまとめるために、バージョン間での外部ストレージと権限の動作の概要を以下に示します。.
Android 9 以下 (API 28 以前)
- 権限:
外部ストレージの読み取り外部ストレージへの書き込み
- 行動:
- アプリは自由にアクセスできる
/SDカードおよびそのサブディレクトリ - アプリによって作成されたファイルは、アプリをアンインストールした後もデバイスに残ります
- アプリは自由にアクセスできる
- 典型的なアプローチ:
- 外部ストレージパスの下で直接読み取り/書き込み
Android 10 (API 29) – スコープ別ストレージの導入
- 権限:
外部ストレージの読み取りまだ動作する外部ストレージへの書き込みまだ存在するが、その有効範囲は縮小されている
- 行動:
- スコープ付きストレージ が導入されました:
- アプリは、以下のアプリ固有のディレクトリに制限されます。
Android/データ/パッケージ名/ - 他のアプリのファイルへの直接アクセスは制限されています
- アプリは、以下のアプリ固有のディレクトリに制限されます。
- メディアファイル(画像、動画、音声)は、 メディアストア
リクエストレガシー外部ストレージ=true一時的に古い行動を維持できる
(ただし、このフラグは Android 11 以降では無視されます)
- スコープ付きストレージ が導入されました:
- 推奨されるアプローチ:
- 画像/動画/音声の場合: メディアストア
- プライベートファイルの場合:
外部ファイルディレクトリを取得する()またはgetDataDir()
Android 11 (API 30) – スコープ別ストレージの適用
- 権限:
外部ストレージの読み取り動作しますが、MediaStore によって管理されるメディアに対してのみ動作します。外部ストレージへの書き込み事実上 廃止 一般的な外部ストレージ用外部ストレージの管理特別な「すべてのファイルへのアクセス」ユースケースのために導入されました
- 行動:
リクエストレガシー外部ストレージ=true動作しなくなりました。スコープストレージは 常にオン- アクセス
/SDカード/ルートがブロックされています - アプリは次のことのみを実行できます。
- 独自のプライベートディレクトリにアクセスする
- 共有メディアにアクセスするには メディアストア
- 推奨されるアプローチ:
- 一般的なアプリの場合:
- MediaStoreを使用するか、 SAF (
アクション_ドキュメントを開く,アクション_ドキュメント作成)ユーザーが選択したファイル
- MediaStoreを使用するか、 SAF (
- 考慮するだけ
外部ストレージの管理アプリが実際にファイルマネージャー、バックアップツール、セキュリティアプリなどである場合.
- 一般的なアプリの場合:
Android 13 (API 33) – メディア権限の分割
- 権限:
メディア画像を読む– 画像にアクセスREAD_MEDIA_VIDEO– ビデオにアクセスするREAD_MEDIA_AUDIO– オーディオにアクセス
- 行動:
- メディアの許可は きめ細かい:
- ユーザーは、画像アクセスのみ、ビデオアクセスのみなどを許可できます。.
- Android 11のスコープ別ストレージルールはそのまま適用されます
- メディアの許可は きめ細かい:
- 推奨されるアプローチ:
- 必要な特定のメディア権限をリクエストします。
- たとえば、画像のみを扱う場合は、
メディア画像を読む
- たとえば、画像のみを扱う場合は、
- する ない リクエスト
外部ストレージの読み取りAndroid 13以降では、新しいメディア権限に置き換えられます
- 必要な特定のメディア権限をリクエストします。
クイックマトリックス(概念)
- Android 9以下
- 外部ストレージへのアクセスは広範囲にわたり、READ/WRITE_EXTERNAL_STORAGE によって制御されます。
- Android 10
- スコープストレージが導入されましたが、エスケープハッチがあります(
リクエストレガシー外部ストレージ)
- スコープストレージが導入されましたが、エスケープハッチがあります(
- Android 11
- スコープストレージが強制され、従来のスイッチが削除されました
外部ストレージの管理登場するが、非常に制限されている
- 人造人間13号
- メディアアクセスは
READ_MEDIA_*権限 - スコープストレージのルールは同じだが、よりきめ細かなユーザーコントロールが可能
- メディアアクセスは
6. まとめ
- 「1 台の Android 13 デバイスで動作する」からといって、どこでも動作するとは限りません。OEM やシステム レポートは一貫性がない可能性があります。.
- のために Android 11以降, 、次の点について考えてみましょう。
- アプリのプライベートディレクトリ + MediaStore + SAF, 「生」ではなく
/SDカードアクセス"”
- アプリのプライベートディレクトリ + MediaStore + SAF, 「生」ではなく
- 扱う
外部ストレージの管理として 最後の手段 特に Google Play で公開する予定の場合は、非常に特殊なアプリ タイプ向けです。. - 常にテストする 複数のデバイスとAndroidバージョン, 特に権限とストレージに関しては注意が必要です。.
この記事は、実際のAndroidプロジェクト(Android 13搭載のSamsungデバイスを含む)における私自身のデバッグと適応に基づいています。GPTは翻訳と文言の洗練にのみ協力しており、技術的な内容と決定はすべて私自身の責任です。.


