當我嘗試實現一個非常簡單的需求時—— 下載圖片並將其保存到本地存儲 — 起初一切看起來都很正常。.
- 榮耀(Android 10)-運作正常
- Redmi(Android 11)-運作正常
- 小米(Android 13)-運作正常
- 三星(Android 13) 完全失敗:儲存權限對話框始終不會顯示。
同樣的程式碼,同樣的功能,但一台運行 Android 13 的裝置就是不顯示權限提示。就這樣,一個原本簡單的「下載圖片」任務,演變成了深入的調查。 作用域儲存 和 管理外部存儲.
這篇文章總結了我如何調整儲存權限。 Android 11 以上版本, 以及我如何處理不同版本之間的不同行為。.
1. 漏洞:儲存權限對話方塊始終不顯示(三星安卓 13)
要求很簡單:
下載圖片並儲存到裝置中,使其顯示在圖庫中。.
我的三台測試設備如下:
- 榮耀 – 安卓 10 → 確定
- Redmi – Android 11 → 確定
- 小米 – Android 13 → 確定
但是, 運行 Android 13 的三星設備, 系統 從未顯示過儲存權限對話框, 無論我如何要求,都無濟於事。.



起初我以為這只是另一個 OEM 廠商的怪癖,但在檢查了 Android 各個版本之間的存儲權限更改後,我意識到我所依賴的行為在 Android 13 上針對 SDK 33 時實際上已被棄用。.
2. 根本原因:WRITE/READ_EXTERNAL_STORAGE 在 Android 13 (SDK 33) 中已棄用
在舊版的 Android 系統中,我們可以直接在清單檔案中宣告這兩個權限:
讀取外部存儲寫入外部存儲
然後根據需要,在運行時請求它們。.
在 Android 13 (SDK 33) 上 targetSdkVersion = 33, 這種方法開始失效:
寫入外部存儲是 已棄用且實際上無用 在最新的 Android 版本上- 如果你添加
maxSdkVersion=32這些權限在 Android 11/12 上仍然有效。
但他們是 忽略 在 Android 13 上,目標版本為 33 - 同時,Play 商店要求新應用程式至少要面對 SDK 33。
因此,對於 Android 11 及更高版本,我們必須進行以下調整:
- 作用域儲存
- 在某些情況下,還需要特殊許可:
管理外部存儲
管理外部存儲 賦予應用程式對所有共用儲存內容(包括非媒體檔案)的廣泛存取權限。 不是 允許存取其他應用程式的私有目錄,但 Google Play 仍然認為這是一項高度敏感的權限。.
為了支援不同的安卓版本,我最終將權限處理拆分為:
- 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_EXTEL_STORAGE mission mission. 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+ – 重定向到系統「所有檔案存取權限」設定頁面 valintent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION) intent.data = Uri.parse("package:" + activity.packageName) activity.startActivityForResult(intent, 200) } else { // 10 7 – Android – 普通權限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 的回呼函數和我們自己的邏輯:
override fun onRequestPermissionsResult( requestCode: Int, permissions: Array , grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, thisity mission fInts, 10,005), 錯誤) { AppInitUtils().saveFreshAppImageToGallery(this, curImg) PaperThreeVariable.isToRequestPer = false } override fun onPermissionsDenied(requestCode: Int, perms: MutableList ) { PaperThreeVariable.isToRequestPer = false if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) { AppSettingsDialog.Builder(this) .setRationale("此函式需要啟用儲存式") .setNegativeButton(d)(D)p. }
我在這裡使用 EasyPermissions 的原因:
- 使用者可以 永久否認 權限問題,導致重複請求靜默失敗
- EasyPermissions 讓以下操作變得更簡單:
- 偵測「永久拒絕」狀態
- 顯示一個對話框,引導使用者進行以下操作: 系統設定 → 應用權限 手動啟用儲存存取
獲得許可後,我呼叫:
AppInitUtils().saveFreshAppImageToGallery(this, curImg)
實際儲存影像並刷新圖庫。.
經過此次適配,三星 Android 13 裝置終於與其他裝置表現一致了。.
補充說明:我的小米裝置顯示為 Android 13,但 Android Studio 的「歷史連接裝置」卻將其識別為 Android 12。這或許可以解釋為什麼在某些情況下它仍然可以運作——但這正是版本感知權限處理如此重要的原因。.
4. 關於 MANAGE_EXTERNAL_STORAGE 和 Google Play 限制
管理外部存儲 功能強大:
它授予對以下內容的讀取/寫入權限 所有共享儲存 在設備上。.
因此,Google Play 將其視為 高度敏感的許可:
- 它主要用於 檔案管理器/備份/防毒軟體 類型應用程式
- 你必須提交使用理由才能使用它。
- 如果您的應用程式只是典型的消費者應用程式(例如,保存圖片、簡單下載),那麼您的請求很可能不會被批准。 拒絕
所以,如果你的唯一要求是:
“將圖片保存到圖庫並使其對用戶可見。”
那你應該 強烈建議避免 管理外部存儲 相反:
- 使用 媒體商店 將影像插入系統媒體庫
- 或使用無需完全文件存取權即可保存映像的 API。
有幾種模式:
- 將影像儲存到 Pictures/DCIM 目錄
- 通知媒體掃描器或依賴 MediaStore,以便畫廊可以讀取它。
- 做所有這些 無需請求 MANAGE_EXTERNAL_STORAGE
對於內部或非 Play 商店分發(例如,企業內部應用程式商店),從技術上講,您仍然可以使用 Environment.getExternalStorageDirectory(), 但我並不建議在 2025 年圍繞這個主題設計一個新應用。.
5. 版本演進總結(Android 9 → 13)
為了將所有內容集中在一個地方,這裡對外部儲存和權限在不同版本中的行為方式進行了概述。.
Android 9 及以下版本(API 28 及更早版本)
- 權限:
讀取外部存儲寫入外部存儲
- 行為:
- 應用程式可以自由存取
/sdcard及其子目錄 - 即使卸載了應用程序,該應用程式建立的檔案仍會保留在裝置上。
- 應用程式可以自由存取
- 典型方法:
- 直接在外部儲存路徑下進行讀寫操作
Android 10 (API 29) – 引進了作用域存儲
- 權限:
讀取外部存儲仍然有效寫入外部存儲它仍然存在,但其有效範圍已縮小。
- 行為:
- 作用域儲存 引入:
- 應用程式僅限於其自身的應用程式專屬目錄。
Android/data/你的軟體包名稱/ - 直接存取其他應用程式的檔案受到限制
- 應用程式僅限於其自身的應用程式專屬目錄。
- 媒體檔案(圖像、視訊、音訊)應透過以下方式存取: 媒體商店
requestLegacyExternalStorage=true可能會暫時保留舊的行為
(但從 Android 11 開始,此標誌將被忽略)
- 作用域儲存 引入:
- 推薦方法:
- 對於圖像/視訊/音訊:使用 媒體商店
- 對於私人文件:請使用
getExternalFilesDir()或者getDataDir()
Android 11 (API 30) – 強制執行作用域存儲
- 權限:
讀取外部存儲有效,但僅適用於 MediaStore 管理的媒體。寫入外部存儲有效地 過時的 用於一般外部存儲管理外部存儲為特殊的「所有文件存取」用例而引入
- 行為:
requestLegacyExternalStorage=true不再有效;作用域儲存是 始終開啟- 訪問
/sdcard/root 權限被阻止 - 應用程式只能:
- 訪問他們自己的私人目錄
- 透過以下方式存取共享媒體 媒體商店
- 推薦方法:
- 對於典型應用:
- 使用 MediaStore 或 新加坡武裝部隊 (
操作_開啟文檔,操作_建立文檔)針對使用者選擇的文件
- 使用 MediaStore 或 新加坡武裝部隊 (
- 僅考慮
管理外部存儲如果你的應用程式確實是一款檔案管理器、備份工具、安全應用程式等等。.
- 對於典型應用:
Android 13 (API 33) – 媒體權限拆分
- 權限:
讀取媒體影像– 存取影像讀取媒體視頻– 訪問視頻讀取媒體音訊– 存取音訊
- 行為:
- 媒體權限是 細粒:
- 用戶可以僅授予圖像存取權限、僅授予視訊存取權限等等。.
- Android 11 中的作用域儲存規則仍然有效。
- 媒體權限是 細粒:
- 推薦方法:
- 請申請您需要的具體媒體授權:
- 例如,如果您只處理圖像,則只需請求即可。
讀取媒體影像
- 例如,如果您只處理圖像,則只需請求即可。
- 做 不是 要求
讀取外部存儲在 Android 13 及更高版本中,該功能已被新的媒體權限取代。
- 請申請您需要的具體媒體授權:
快速矩陣(概念圖)
- Android 9 以下版本
- 外部儲存的存取範圍很廣,由 READ/WRITE_EXTERNAL_STORAGE 控制。
- Android 10
- 引入了範圍存儲,但也有退路(
請求舊版外部存儲)
- 引入了範圍存儲,但也有退路(
- Android 11
- 強制執行範圍存儲,移除舊式交換機
管理外部存儲出現但受到嚴格限制
- Android 13
- 媒體存取分為
READ_MEDIA_*權限 - 相同的作用域儲存規則,但使用者控制更加細粒度。
- 媒體存取分為
6. 重點總結
- 不要以為「在一台 Android 13 裝置上運作正常」就代表它在所有裝置上都能正常運作;OEM 廠商和系統報告可能存在不一致的情況。.
- 為了 Android 11+, 可以從以下角度思考:
- 應用私有目錄 + 媒體庫 + SAF, 不是「生的」。
/sdcard使用權”
- 應用私有目錄 + 媒體庫 + SAF, 不是「生的」。
- 對待
管理外部存儲作為一個 最後手段 尤其對於某些特定類型的應用,如果您打算在 Google Play 上發布,那就更需要注意了。. - 始終進行測試 多款設備和安卓版本, 尤其是在權限和儲存方面。.
本文源自於我在實際 Android 專案(包括運行 Android 13 的三星裝置)中的調試和調整。 GPT 僅協助翻譯和潤飾文字;所有技術內容和決策均出自本人。.


