Android 14 เปิดตัว "การเข้าถึงรูปภาพที่เลือก" ซึ่งช่วยให้ผู้ใช้ให้สิทธิ์แอปเข้าถึงรูปภาพและวิดีโอที่เฉพาะเจาะจงในคลังภาพ แทนที่จะให้สิทธิ์เข้าถึงสื่อทุกประเภท
การเปลี่ยนแปลงนี้จะเปิดใช้ก็ต่อเมื่อแอปกำหนดเป้าหมายเป็น Android 14 (API ระดับ 34) ขึ้นไปเท่านั้น หากคุณยังไม่ได้ใช้เครื่องมือเลือกรูปภาพ เราขอแนะนำให้ติดตั้งใช้งานในแอปเพื่อให้ผู้ใช้ได้รับประสบการณ์ที่สม่ำเสมอในการเลือกรูปภาพและวิดีโอ รวมถึงช่วยเพิ่มความเป็นส่วนตัวของผู้ใช้โดยไม่ต้องขอสิทธิ์เข้าถึงพื้นที่เก็บข้อมูล
หากคุณดูแลรักษาเครื่องมือเลือกแกลเลอรีของคุณเองโดยใช้สิทธิ์เข้าถึงพื้นที่เก็บข้อมูลและต้องการควบคุมการติดตั้งใช้งานอย่างเต็มรูปแบบ ให้ปรับการติดตั้งใช้งานเพื่อใช้สิทธิ์ READ_MEDIA_VISUAL_USER_SELECTED
ใหม่ หากแอปของคุณไม่ได้ใช้สิทธิ์ใหม่ ระบบจะเรียกใช้แอปในโหมดความเข้ากันได้
SDK เป้าหมาย | ประกาศแล้ว READ_MEDIA_VISUAL_USER_SELECTED รายการ |
เปิดใช้การเข้าถึงรูปภาพที่เลือกไว้แล้ว | ลักษณะการทํางานของ UX |
---|---|---|---|
SDK 33 | ไม่ | ไม่ | ไม่มี |
ใช่ | ใช่ | ควบคุมโดยแอป | |
SDK 34 | ไม่ | ใช่ | ควบคุมโดยระบบ (ลักษณะการทำงานที่ใช้ร่วมกัน) |
ใช่ | ใช่ | ควบคุมโดยแอป |
สร้างหรือปรับแต่งเครื่องมือเลือกแกลเลอรีของคุณเอง
การสร้างเครื่องมือเลือกแกลเลอรีของคุณเองต้องมีการพัฒนาและการบำรุงรักษาอย่างมาก และแอปของคุณต้องขอสิทธิ์ในการเข้าถึงพื้นที่เก็บข้อมูลเพื่อขอความยินยอมจากผู้ใช้อย่างชัดเจน ผู้ใช้สามารถปฏิเสธคำขอเหล่านี้ หรือหากแอปของคุณทำงานในอุปกรณ์ที่ใช้ Android 14 และแอปกำหนดเป้าหมายเป็น Android 14 (API ระดับ 34) ขึ้นไป ให้จำกัดการเข้าถึงสื่อที่เลือก รูปภาพต่อไปนี้แสดงตัวอย่างการขอสิทธิ์และการเลือกสื่อโดยใช้ตัวเลือกใหม่
ส่วนนี้จะสาธิตแนวทางที่แนะนำในการสร้างเครื่องมือเลือกแกลเลอรีของคุณเองโดยใช้ MediaStore
หากคุณดูแลรักษาเครื่องมือเลือกแกลเลอรีสําหรับแอปอยู่แล้วและจำเป็นต้องควบคุมอย่างเต็มรูปแบบ ให้ใช้ตัวอย่างเหล่านี้เพื่อปรับการใช้งาน หากคุณไม่อัปเดตการใช้งานเพื่อจัดการสิทธิ์เข้าถึง Photos แบบเลือก ระบบจะเรียกใช้แอปของคุณในโหมดความเข้ากันได้
ขอสิทธิ์
ก่อนอื่น ให้ขอสิทธิ์เก็บข้อมูลที่เหมาะสมในไฟล์ Manifest ของ Android โดยขึ้นอยู่กับเวอร์ชันของระบบปฏิบัติการ
<!-- 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" />
จากนั้นขอสิทธิ์รันไทม์ที่ถูกต้อง โดยขึ้นอยู่กับเวอร์ชันระบบปฏิบัติการด้วย
// 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 ได้โดยไม่ต้องขอสิทธิ์เข้าถึงพื้นที่เก็บข้อมูล หากแอปเพิ่มไฟล์ไปยังพื้นที่เก็บข้อมูลที่ใช้ร่วมกันเท่านั้นและไม่ค้นหารูปภาพหรือวิดีโอ คุณควรหยุดการขอสิทธิ์พื้นที่เก็บข้อมูลและตั้งค่า maxSdkVersion
ของ API 28 ใน AndroidManifest.xml
โดยทำตามขั้นตอนดังนี้
<!-- 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
ใหม่เพื่อควบคุมการเลือกสื่ออีกครั้ง และอัปเดตอินเทอร์เฟซของแอปเพื่อให้ผู้ใช้มอบสิทธิ์เข้าถึงชุดรูปภาพและวิดีโออื่นให้กับแอป รูปภาพต่อไปนี้แสดงตัวอย่างของการส่งคําขอสิทธิ์และการเลือกสื่ออีกครั้ง
เมื่อเปิดกล่องโต้ตอบการเลือก ระบบจะแสดงรูปภาพ วิดีโอ หรือทั้ง 2 อย่าง ทั้งนี้ขึ้นอยู่กับสิทธิ์ที่ขอ ตัวอย่างเช่น หากคุณขอสิทธิ์ READ_MEDIA_VIDEO
โดยไม่มีสิทธิ์ READ_MEDIA_IMAGES
เฉพาะวิดีโอเท่านั้นที่จะปรากฏใน 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
ในแอปที่พร้อมใช้งานจริง ให้ใช้การแบ่งหน้าด้วยสิ่งต่างๆ เช่น ไลบรารีการแบ่งหน้าเพื่อช่วยรับประกันประสิทธิภาพที่ดี
ค้นหารายการที่เลือกล่าสุด
แอปใน 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
แคชอาจไม่เป็นข้อมูลล่าสุด
- ค้นหา
MediaStore
เสมอโดยใช้ContentResolver
แทนการใช้แคชที่จัดเก็บไว้ - เก็บผลลัพธ์ไว้ในหน่วยความจำขณะที่แอปทำงานอยู่เบื้องหน้า
- รีเฟรชผลลัพธ์เมื่อแอปของคุณผ่าน
onResume
วงจรของแอปเนื่องจากผู้ใช้อาจเปลี่ยนจากการเข้าถึงแบบเต็มเป็นการเข้าถึงแบบบางส่วนผ่านการตั้งค่าสิทธิ์
ถือว่าการเข้าถึง URI เป็นสิทธิ์เข้าถึงชั่วคราว
หากผู้ใช้เลือกเลือกรูปภาพและวิดีโอในกล่องโต้ตอบสิทธิ์ของระบบ การเข้าถึงรูปภาพและวิดีโอที่เลือกไว้ของแอปจะหมดอายุในที่สุด
แอปของคุณควรจัดการกรณีที่ไม่มีสิทธิ์เข้าถึง Uri
เสมอ ไม่ว่าสิทธิ์ของ Uri
นั้นจะเป็นอย่างไรก็ตาม
กรองประเภทสื่อที่เลือกได้ตามสิทธิ์
กล่องโต้ตอบการเลือกจะไวต่อประเภทสิทธิ์ที่ขอ
- การขอเฉพาะ
READ_MEDIA_IMAGES
จะแสดงเฉพาะรูปภาพที่เลือกได้ - การขอเฉพาะ
READ_MEDIA_VIDEO
จะแสดงเฉพาะวิดีโอที่เลือกได้ - การขอให้ทั้ง
READ_MEDIA_IMAGES
และREAD_MEDIA_VIDEO
แสดงคลังภาพทั้งหมดให้เลือกได้
คุณควรขอสิทธิ์ที่เหมาะสมเพื่อหลีกเลี่ยงประสบการณ์การใช้งานที่ไม่ดี โดยอิงตาม Use Case ของแอป หากฟีเจอร์หนึ่งๆ ต้องการวิดีโอเท่านั้น โปรดส่งคำขอสำหรับ 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