Runtime Permission เป็นกลไกการขอสิทธิ์ระหว่างการทำงานของแอปพลิเคชัน ซึ่งถูกนำมาใช้ใน Android 6.0 (API 23) แตกต่างจากการให้สิทธิ์เมื่อติดตั้ง runtime permissions อนุญาตให้ผู้ใช้สามารถให้หรือเพิกถอนการเข้าถึงข้อมูลที่ละเอียดอ่อน (กล้อง ตำแหน่งที่ตั้งทางภูมิศาสตร์ รายชื่อติดต่อ) ได้ทุกเมื่อ ตามข้อมูลจาก Android Developers (2026) แอปมากกว่า 85% ใน Google Play ใช้ runtime permission อย่างน้อยหนึ่งรายการ
ประเด็นสำคัญ
Runtime Permission คือโมเดลความปลอดภัยของ Android ที่แอปขอเข้าถึงข้อมูลที่ละเอียดอ่อนในเวลาที่ฟังก์ชันนั้นจำเป็นสำหรับผู้ใช้จริงๆ ก่อน Android 6.0 สิทธิ์ทั้งหมดจะถูกให้เมื่อติดตั้งแอป และผู้ใช้ไม่สามารถเพิกถอนได้โดยไม่ต้องถอนการติดตั้งแอปทั้งหมด
ก่อน Android 6.0 ผู้ใช้จะเห็นรายการสิทธิ์ทั้งหมดเมื่อติดตั้งและสามารถยอมรับทั้งหมดหรือปฏิเสธการติดตั้งได้ การศึกษาในปี 2015 แสดงให้เห็นว่าผู้ใช้ 87% ไม่ได้อ่านรายการสิทธิ์เมื่อติดตั้ง Android 6.0 นำเสนอ runtime permissions โดยแบ่งสิทธิ์เป็นแบบปกติ (อัตโนมัติ) และแบบอันตราย (ต้องขอ) Android 11 เพิ่มสิทธิ์แบบครั้งเดียว — เพิกถอนโดยอัตโนมัติเมื่อปิดแอป Android 13 นำเสนอ Photo Picker และการแจ้งเตือนแบบ push เป็น runtime permissions แยกต่างหาก
iOS ใช้โมเดลที่คล้ายกันตั้งแต่ iOS 10 ซึ่งการเข้าถึงกล้อง ไมโครโฟน และตำแหน่งที่ตั้งทางภูมิศาสตร์จะถูกขอเมื่อใช้งานครั้งแรก อย่างไรก็ตาม iOS ไม่มีแนวคิดของ “สิทธิ์ปกติ” — สิทธิ์แต่ละรายการจะถูกขออย่างชัดแจ้ง และการปฏิเสธจะคงอยู่จนกว่านักพัฒนาจะขออีกครั้งผ่านการตั้งค่าระบบ
Runtime Permission ทำงานผ่านไดอะล็อกของระบบที่เรียกโดยเมธอด requestPermissions() (AndroidX — ActivityResultLauncher) ระบบจะแสดงไดอะล็อกมาตรฐานพร้อมคำอธิบาย และผู้ใช้เลือก “อนุญาต” หรือ “ปฏิเสธ” หลังจากตอบกลับ การเรียกกลับจะถูกทริกเกอร์เพื่อให้แอปประมวลผลการตัดสินใจของผู้ใช้
private lateinit var requestPermissionLauncher: ActivityResultLauncher<String>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
if (isGranted) {
startCamera()
} else {
showPermissionDeniedDialog()
}
}
}
private fun checkCameraPermission() {
when {
ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED -> {
startCamera()
}
ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA) -> {
showRationaleDialog { requestPermissionLauncher.launch(Manifest.permission.CAMERA) }
}
else -> {
requestPermissionLauncher.launch(Manifest.permission.CAMERA)
}
}
}
เมธอด shouldShowRequestPermissionRationale จะคืนค่า true หากผู้ใช้ปฏิเสธคำขอแล้วหนึ่งครั้ง ในกรณีนี้ แนะนำให้แสดงไดอะล็อกพร้อมคำอธิบายว่าเหตุใดแอปจึงต้องการสิทธิ์ จากนั้นจึงขอใหม่ ซึ่งจะเพิ่มโอกาสที่ผู้ใช้จะยินยอม 30–40% (ข้อมูลจาก Google I/O 2024)
Android จัดประเภทสิทธิ์ทั้งหมดเป็นหลายระดับการป้องกัน: ปกติ อันตราย ลายเซ็น และพิเศษ สิทธิ์ปกติ จะได้รับโดยอัตโนมัติเมื่อติดตั้ง สิทธิ์อันตราย ต้องการคำขอขณะรันไทม์ สิทธิ์ลายเซ็น จะใช้ได้เฉพาะแอปที่เซ็นชื่อด้วยใบรับรองเดียวกันเท่านั้น
| กลุ่ม | สิทธิ์ | ระดับ API |
|---|---|---|
| CAMERA | CAMERA | API 23+ |
| LOCATION | ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION, ACCESS_BACKGROUND_LOCATION | API 23+ (พื้นหลัง — API 29+) |
| STORAGE | READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE, READ_MEDIA_IMAGES (API 33+) | API 23+ (การเปลี่ยนแปลงใน API 33) |
| PHONE | READ_PHONE_STATE, CALL_PHONE, READ_CALL_LOG | API 23+ |
| MICROPHONE | RECORD_AUDIO | API 23+ |
| CONTACTS | READ_CONTACTS, WRITE_CONTACTS, GET_ACCOUNTS | API 23+ |
| NOTIFICATIONS | POST_NOTIFICATIONS | API 33+ |
สิทธิ์พิเศษ (SYSTEM_ALERT_WINDOW, WRITE_SETTINGS, MANAGE_EXTERNAL_STORAGE) ต้องการการนำทางเพิ่มเติมไปยังการตั้งค่าระบบผ่าน Settings.ACTION_MANAGE_OVERLAY_PERMISSION สิทธิ์เหล่านี้ไม่สามารถขอผ่านไดอะล็อกมาตรฐานของระบบและต้องการการดำเนินการอย่างชัดแจ้งจากผู้ใช้ในหน้าจอการตั้งค่า
Android 12 นำเสนอการเปลี่ยนแปลงที่สำคัญในโมเดล runtime permissions สิทธิ์แบบครั้งเดียว อนุญาตให้เข้าถึงกล้อง ไมโครโฟน หรือตำแหน่งที่ตั้งทางภูมิศาสตร์ได้เพียงเซสชันเดียว เมื่อผู้ใช้ปิดแอป สิทธิ์จะถูกเพิกถอนโดยอัตโนมัติ ตัวบ่งชี้ความเป็นส่วนตัว คือตัวบ่งชี้สีเขียวในแถบสถานะที่แสดงเมื่อแอปกำลังใช้กล้องหรือไมโครโฟน
// Android 12+ — การจัดการสิทธิ์ตำแหน่งแบบครั้งเดียว
private fun checkLocationPermission() {
val permissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
val fineLocationGranted = permissions[Manifest.permission.ACCESS_FINE_LOCATION]
val coarseLocationGranted = permissions[Manifest.permission.ACCESS_COARSE_LOCATION]
if (fineLocationGranted == true) {
showUserLocation()
} else {
showLocationDisabledDialog()
}
}
permissionLauncher.launch(
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
)
}
// ตรวจสอบว่าสิทธิ์ถูกเพิกถอนโดยระบบหรือไม่ (Android 12+)
class PermissionReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Intent.ACTION_PERMISSION_REVOCATION) {
handleRevokedPermission(intent.getStringExtra(Intent.EXTRA_REVOKED_PERMISSION))
}
}
}
Android 13 เพิ่มสิทธิ์ POST_NOTIFICATIONS ในกลุ่มอันตราย ซึ่งต้องมีการขออย่างชัดแจ้งในการส่งการแจ้งเตือนแบบ push Android 14 นำเสนอข้อจำกัดเกี่ยวกับตำแหน่งที่ตั้งทางภูมิศาสตร์เบื้องหลัง: แอปต้องได้รับการอนุมัติอย่างชัดแจ้งจากผู้ใช้ทุกครั้งที่ขอตำแหน่งเบื้องหลัง Photo Picker (API 33+) แทนที่ความจำเป็นของ READ_EXTERNAL_STORAGE สำหรับการเลือกรูปภาพ
การปฏิเสธ ของผู้ใช้ต่อคำขอสิทธิ์เป็นสถานการณ์ปกติที่ต้องจัดการอย่างถูกต้อง การปฏิเสธมีสองประเภท: แบบครั้งเดียว (ผู้ใช้กด “ปฏิเสธ”) และแบบถาวร (ผู้ใช้เลือก “ไม่ต้องถามอีก”) ในกรณีที่สอง ไดอะล็อกของระบบจะไม่ปรากฏอีก และแอปต้องนำทางผู้ใช้ไปยังการตั้งค่าระบบ
หลังจากการปฏิเสธครั้งแรก แอปควรแสดง ไดอะล็อกแสดงเหตุผล — คำอธิบายของแอปเองว่าทำไมจึงจำเป็นต้องมีสิทธิ์ หากผู้ใช้ปฏิเสธอีกครั้ง แอปควรนำทางไปยังหน้าจอการตั้งค่าแอปผ่าน Settings.ACTION_APPLICATION_DETAILS_SETTINGS Material 3 แนะนำให้ใช้ PermissionRequestBottomSheet เพื่อประสบการณ์ผู้ใช้ที่เป็นธรรมชาติมากขึ้น
สิ่งสำคัญคือต้องไม่บล็อกฟังก์ชันการทำงานของแอปทั้งหมดเมื่อถูกปฏิเสธ ตัวอย่างเช่น หากผู้ใช้ปฏิเสธ ตำแหน่งที่ตั้งทางภูมิศาสตร์ แอปควรเสนอให้ป้อนที่อยู่ด้วยตนเอง สำหรับ กล้อง อนุญาตให้อัปโหลดรูปภาพจากแกลเลอรี Google แนะนำให้จัดหากลไกสำรองสำหรับ runtime permissions ทั้งหมดเสมอ
Runtime permissions ไม่เพียงแต่เป็นกลไกทางเทคนิค แต่ยังเป็นองค์ประกอบของความไว้วางใจของผู้ใช้ที่มีต่อแอปอีกด้วย การขอสิทธิ์ในเวลาที่ไม่เหมาะสม (เช่น เมื่อเปิดครั้งแรก) จะลดโอกาสในการยินยอมอย่างมาก Google Play Store วิเคราะห์ความถี่และบริบทของคำขอสิทธิ์: แอปที่มีการร้องขอมากเกินไปจะได้รับตำแหน่งการค้นหาที่ต่ำกว่า
บริบท — ขอสิทธิ์ทันทีก่อนดำเนินการที่ต้องใช้สิทธิ์นั้น น้อยที่สุด — ขอเฉพาะสิทธิ์ที่จำเป็นจริงๆ สำหรับการทำงานของฟีเจอร์ ความโปร่งใส — อธิบายให้ผู้ใช้ทราบว่าทำไมจึงต้องมีสิทธิ์ก่อนไดอะล็อกของระบบ การเพิกถอน — สมัครรับ ACTION_PERMISSION_REVOCATION เพื่อจัดการการเพิกถอนสิทธิ์ขณะรันไทม์อย่างถูกต้อง
สำหรับการทดสอบ runtime permissions ให้ใช้คำสั่ง adb: adb shell pm revoke <package> android.permission.CAMERA ช่วยให้สามารถจำลองการเพิกถอนสิทธิ์ได้โดยไม่ต้องติดตั้งแอปใหม่ Espresso และ UiAutomator รองรับการทดสอบไดอะล็อกสิทธิ์ผ่าน GrantPermissionRule การรวมเครื่องมือเหล่านี้ในไปป์ไลน์ CI/CD เป็นสิ่งจำเป็นสำหรับแอปที่มี runtime permissions
Google Play Console มีส่วนตรวจสอบสิทธิ์ ซึ่งนักพัฒนาสามารถดูได้ว่าสิทธิ์ถูกขอมากน้อยเพียงใด ผู้ใช้กี่เปอร์เซ็นต์ให้การเข้าถึง และสิทธิ์ใดถูกเพิกถอนไปแล้ว การวิเคราะห์ข้อมูลนี้ช่วยระบุคำขอที่ไม่มีประสิทธิภาพและปรับปรุงประสบการณ์ผู้ใช้ ตัวอย่างเช่น หากผู้ใช้น้อยกว่า 40% ให้ตำแหน่งที่ตั้งทางภูมิศาสตร์ ให้พิจารณาทบทวนช่วงเวลาการขอและเพิ่มคำอธิบายที่น่าเชื่อถือมากขึ้น
การใช้ Android Vitals เพื่อตรวจสอบ ANR (แอปไม่ตอบสนอง) ที่เกี่ยวข้องกับสิทธิ์ก็มีความสำคัญเช่นกัน หากคำขอสิทธิ์ถูกดำเนินการบนเธรดหลักหรือไดอะล็อกของระบบบล็อก UI อาจทำให้เกิด ANR บนอุปกรณ์ที่ช้า ย้ายการตรวจสอบและขอสิทธิ์ไปยังเธรดแยกต่างหากหรือใช้ coroutines ของ Kotlin สำหรับการประมวลผลแบบอะซิงโครนัสเพื่อหลีกเลี่ยงการบล็อกอินเทอร์เฟซผู้ใช้
คำถามที่พบบ่อย
shouldShowRequestPermissionRationale จะคืนค่า false เมื่อปฏิเสธแบบถาวร (เมื่อผู้ใช้เลือก “ไม่ต้องถามอีก”) เมธอดจะคืนค่า true เมื่อปฏิเสธแบบครั้งเดียว ทำให้สามารถแสดงไดอะล็อกแสดงเหตุผลได้ หากเมธอดคืนค่า false ทางเลือกเดียวคือนำทางผู้ใช้ไปยังการตั้งค่าระบบ
ได้ ActivityResultContracts.RequestMultiplePermissions อนุญาตให้ขออาร์เรย์ของสิทธิ์ในการเรียกครั้งเดียว ระบบจะแสดงไดอะล็อกตามลำดับสำหรับแต่ละสิทธิ์ แนะนำให้จัดกลุ่มสิทธิ์ที่เกี่ยวข้องกันตามตรรกะ (เช่น CAMERA และ RECORD_AUDIO สำหรับการบันทึกวิดีโอ) แต่ไม่ควรขอมากกว่า 2–3 รายการในครั้งเดียว
Android TV ใช้โมเดล runtime permissions เดียวกันกับไดอะล็อกที่แสดงบนหน้าจอทีวี Wear OS เวอร์ชัน 3+ รองรับ runtime permissions แต่ไดอะล็อกจะแสดงบนนาฬิกา สำหรับ Android Auto สิทธิ์ทั้งหมดจะถูกขอบนโทรศัพท์ และระบบรถยนต์จะได้รับสิทธิ์ที่ได้รับการอนุมัติแล้วผ่านการเชื่อมต่อบริดจ์
ตามข้อมูลเบื้องต้น Android 16 จะแนะนำ “การหมดอายุของสิทธิ์” สำหรับสิทธิ์แบบครั้งเดียวโดยเพิกถอนอัตโนมัติหลังจาก 24 ชั่วโมง นอกจากนี้ยังคาดว่าจะมีข้อกำหนดที่เข้มงวดมากขึ้นสำหรับ ตำแหน่งเบื้องหลัง และรายการสิทธิ์อันตรายที่ขยายเพิ่มสำหรับหมวดหมู่ใหม่ (เซ็นเซอร์สิ่งแวดล้อม การสแกน Wi-Fi) รายละเอียดที่แน่ชัดจะปรากฏในไตรมาสที่ 3 ของปี 2027
iOS ไม่รองรับ “สิทธิ์ปกติ” — สิทธิ์แต่ละรายการจะถูกขออย่างชัดแจ้งผ่านไดอะล็อกของระบบ ผู้ใช้สามารถเพิกถอนสิทธิ์ได้ทุกเมื่อผ่านการตั้งค่า ความแตกต่างหลักคือ iOS จะไม่ตรวจสอบสถานะสิทธิ์ล่วงหน้าผ่านสิ่งที่เทียบเท่ากับ checkSelfPermission: ระบบจะแสดงไดอะล็อกโดยอัตโนมัติเมื่อเข้าถึง API ที่ได้รับการป้องกันครั้งแรก
สรุป
POST_NOTIFICATIONS เป็น runtime permission Android 14 เพิ่มข้อกำหนดตำแหน่งเบื้องหลังที่เข้มงวดขึ้นREAD_EXTERNAL_STORAGE สำหรับการเลือกรูปภาพเราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม