Android 14 推出了所選相片存取權,可讓使用者授權應用程式 不必授予媒體庫中特定圖片和影片的存取權 會存取特定類型的所有媒體。
只有應用程式指定 Android 14 (API 級別 34) 為目標時,系統才會啟用這項變更。 更高。如果您尚未使用相片挑選工具,建議您在 應用程式,讓您能在選取圖片和影片時,享有一致的體驗 這也加強使用者隱私 不必請求任何儲存空間 授予其要求的權限。
如果您透過儲存空間權限自行維護相片庫選擇器,並需要
由您全權掌控導入方式,並調整導入方式
使用新的 READ_MEDIA_VISUAL_USER_SELECTED
權限。如果您的應用程式
不會使用新權限,而是以相容性執行應用程式
模式。
目標 SDK 版本 | 已宣告 READ_MEDIA_VISUAL_USER_SELECTED |
已啟用所選相片存取權 | 使用者體驗行為 |
---|---|---|---|
SDK 33 | 否 | 否 | 不適用 |
是 | 是 | 由應用程式控制 | |
SDK 34 | 否 | 是 | 由系統控制 (相容性行為) |
是 | 是 | 由應用程式控制 |
建立或調整自己的圖片庫挑選器
建立自己的圖片庫選擇器時,需要進行大量的開發和維護, 而您的應用程式必須要求儲存空間權限,才能獲得使用者明確同意。 使用者可以拒絕這些要求;或者,如果應用程式在搭載 Android 14 且您的應用程式指定 Android 14 (API 級別 34) 以上版本,上限為 存取所選媒體。下圖範例顯示 權限,並使用新選項選取媒體
本節將說明建立自己的圖片庫時建議使用的方法
使用 MediaStore
的挑選器。如果您已為應用程式維護圖片庫挑選器
並且需要保有完全的掌控權,您可以參考這些範例來調整
。如果不更新導入方式來處理所選項目
相片存取權,系統會以相容模式執行應用程式。
要求權限
首先,請在 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
以及更新應用程式介面,讓使用者授予應用程式存取權
改用不同的圖片和影片組合下圖為
要求權限並重新選取媒體:
開啟選取對話方塊時,系統會根據下列條件顯示相片、影片或兩者:
授予該權限舉例來說,如果您在
不具備 READ_MEDIA_IMAGES
權限的 READ_MEDIA_VIDEO
權限,僅限
則會顯示在使用者介面中,供使用者選取檔案。
// 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 的權限
請考慮以下狀況:
- 您的應用程式已安裝在執行 Android 13 的裝置上。
- 使用者已授予
READ_MEDIA_IMAGES
權限,且 應用程式的READ_MEDIA_VIDEO
權限。 - 接著,您為安裝有該應用程式的裝置升級至 Android 14。
- 您的應用程式開始指定 Android 14 (API 級別 34) 以上版本為目標。
在此情況下,您的應用程式仍可完整存取使用者的相片和影片。
系統也會保留 READ_MEDIA_IMAGES
和 READ_MEDIA_VIDEO
權限
。
Android 12 以下版本的權限
請考慮以下狀況:
- 您的應用程式已安裝在執行 Android 13 的裝置上。
- 使用者已授予
READ_EXTERNAL_STORAGE
權限或 應用程式的WRITE_EXTERNAL_STORAGE
權限。 - 接著,您為安裝有該應用程式的裝置升級至 Android 14。
- 您的應用程式開始指定 Android 14 (API 級別 34) 以上版本為目標。
在此情況下,您的應用程式仍可完整存取使用者的相片和影片。
系統也會授予 READ_MEDIA_IMAGES
權限,且
為應用程式自動取得READ_MEDIA_VIDEO
權限。
最佳做法
本節列舉幾個使用
READ_MEDIA_VISUAL_USER_SELECTED
權限。如要瞭解詳情,請查閱
我們的權限最佳做法。
不要永久儲存權限狀態
請勿以永久方式儲存權限狀態,包括
SharedPreferences
或 DataStore
。儲存的狀態可能不會與
實際狀態權限狀態可能會在權限重設後變更,
應用程式休眠、使用者對應用程式設定進行變更,或
應用程式進入背景請改為使用
ContextCompat.checkSelfPermission()
。
不要為相片和影片假定完整存取權限
根據 Android 14 所導入的異動,您的應用程式可能只具備部分元素
存取裝置的相片庫。如果應用程式快取 MediaStore
資料
當使用 ContentResolver
進行查詢時,快取可能不是最新版本。
- 一律使用
ContentResolver
查詢MediaStore
,勿依賴 儲存快取。 - 在應用程式於前景運作時,將結果保留在記憶體中。
- 在應用程式經歷
onResume
應用程式的生命週期時重新整理結果 因為使用者可能透過 權限設定。
將 URI 存取權視為臨時權限處理
如果使用者在系統權限中選擇「選取相片和影片」
對話方塊中,應用程式對所選相片和影片的存取權最終會失效。
您的應用程式應該要能處理無法存取任何 Uri
的情況,
發揮更大的影響力
依權限篩選可選取的媒體類型
選項對話方塊會因要求的權限類型而異:
- 僅要求
READ_MEDIA_IMAGES
僅顯示可選取的圖片。 - 如果只要求
READ_MEDIA_VIDEO
,系統只會顯示可選取的影片。 - 要求
READ_MEDIA_IMAGES
和READ_MEDIA_VIDEO
會顯示 才能選取相片庫
根據應用程式的用途,請務必要求正確的
以免影響使用者體驗如果功能只預期
影片只能選取 READ_MEDIA_VIDEO
部。
在單一作業中要求權限
如要避免使用者看到多個系統執行階段對話方塊,請送出
READ_MEDIA_VISUAL_USER_SELECTED
、ACCESS_MEDIA_LOCATION
和「讀取媒體」
單一權限 (READ_MEDIA_IMAGES
和/或 READ_MEDIA_VIDEO
)
作業。
允許使用者管理所選項目
使用者選擇部分存取模式時,應用程式不應假設 裝置的相片庫是空的,應允許使用者授予其他權限 檔案。
使用者可能會決定透過 權限設定,但不會授予部分視覺媒體檔案的存取權。
相容性模式
如果您使用儲存空間權限但自行維護相片庫選擇器
調整應用程式,改用新版 READ_MEDIA_VISUAL_USER_SELECTED
權限後,每當使用者時,系統就會以相容模式執行應用程式
必須選取或重新選取媒體
初始選擇媒體時的行為
初次選取時,如果使用者選擇「選取相片和影片」(請參閱
圖 1),則 READ_MEDIA_IMAGES
和 READ_MEDIA_VIDEO
權限為
則是在應用程式工作階段期間授予,來提供臨時權限
暫時存取使用者所選相片和影片。應用程式移至
或是使用者主動終止應用程式時,系統最終
就會拒絕這些權限原理就和其他一次性權限一樣。
媒體選取期間的行為
如果應用程式日後需要存取其他相片和影片,
必須手動要求 READ_MEDIA_IMAGES
權限,或
再次READ_MEDIA_VIDEO
權限。系統會按照與
初始權限要求,提示使用者選取相片和影片 (請參閱
圖 2)。
如果您的應用程式採用權限最佳做法,就不應受到這項變更的影響
破壞應用程式尤其是在應用程式未假設該 URI 的情況下
保留存取權、儲存系統權限狀態,或重新整理
。不過,這個行為
根據應用程式的用途
來提供理想的建議為了提供最佳體驗
,我們建議導入相片挑選工具或調整
應用程式的圖片庫挑選器,直接使用
READ_MEDIA_VISUAL_USER_SELECTED
權限。