แอป Android ทุกแอปทำงานในแซนด์บ็อกซ์ที่จำกัดการเข้าถึง หากแอปของคุณจำเป็นต้องใช้ ทรัพยากรหรือข้อมูลที่อยู่นอกแซนด์บ็อกซ์ของตน คุณสามารถประกาศรันไทม์ สิทธิ์ และตั้งค่าคำขอสิทธิ์ ที่ให้สิทธิ์การเข้าถึงนี้ ขั้นตอนเหล่านี้เป็นส่วนหนึ่งของเวิร์กโฟลว์การใช้ สิทธิ์
ถ้าคุณประกาศเรื่องอันตราย สิทธิ์และหาก แอปของคุณติดตั้งอยู่ในอุปกรณ์ที่ใช้ Android 6.0 (API ระดับ 23) หรือ คุณต้องขอสิทธิ์ที่เป็นอันตรายขณะรันไทม์โดยทำตาม ขั้นตอนต่างๆ ในคู่มือนี้
หากคุณไม่ได้ประกาศสิทธิ์ที่เป็นอันตราย หรือหากแอปของคุณติดตั้งอยู่ใน ซึ่งใช้ Android 5.1 (API ระดับ 22) หรือต่ำกว่านั้น สิทธิ์จะ โดยอัตโนมัติ และคุณไม่จำเป็นต้องทำตามขั้นตอนที่เหลือ ในหน้านี้
หลักการพื้นฐาน
หลักการพื้นฐานสำหรับการขอสิทธิ์ระหว่างรันไทม์มีดังนี้
- ขอสิทธิ์ในบริบทเมื่อผู้ใช้เริ่มโต้ตอบกับ ที่จำเป็น
- ไม่ต้องบล็อกผู้ใช้ มีตัวเลือกให้ยกเลิก UI เพื่อการศึกษาเสมอ เช่น โฟลว์ที่อธิบายเหตุผลในการขอสิทธิ์
- หากผู้ใช้ปฏิเสธหรือเพิกถอนสิทธิ์ที่ฟีเจอร์ต้องการ ด้วยความยินดี ลดแอปลงเพื่อให้ผู้ใช้ใช้แอปของคุณต่อไปได้ โดยอาจเป็น ปิดใช้ฟีเจอร์ที่ต้องใช้สิทธิ์
- อย่าคาดเดาการทำงานของระบบ เช่น อย่าคิดไปเองว่าสิทธิ์ ปรากฏในกลุ่มสิทธิ์เดียวกัน กลุ่มสิทธิ์เป็นเพียงการช่วย ระบบจะลดจำนวนกล่องโต้ตอบของระบบที่แสดงต่อผู้ใช้เมื่อ แอปขอสิทธิ์ที่เกี่ยวข้องอย่างใกล้ชิด
ขั้นตอนการขอสิทธิ์
ก่อนที่จะประกาศและขอสิทธิ์รันไทม์ในแอป ให้ประเมิน แอปของคุณจำเป็นต้องทำเช่นนั้นหรือไม่ คุณสามารถ ตอบโจทย์กรณีการใช้งานมากมายในแอป เช่น การถ่ายภาพ การหยุดสื่อชั่วคราว เล่น และการแสดงโฆษณาที่เกี่ยวข้อง โดยไม่ต้องประกาศ สิทธิ์
หากคุณสรุปได้ว่าแอปต้องประกาศและขอสิทธิ์รันไทม์ โปรดทำตามขั้นตอนเหล่านี้
- ในไฟล์ Manifest ของแอป ให้ประกาศพารามิเตอร์ สิทธิ์ที่แอปของคุณอาจต้อง อีกครั้ง
- ออกแบบ UX ของแอปเพื่อให้เชื่อมโยงกับการดำเนินการบางอย่างในแอป สิทธิ์รันไทม์ที่ต้องการ แจ้งให้ผู้ใช้ทราบว่าการดำเนินการใดที่ผู้ใช้ต้องการ เพื่อให้สิทธิ์แก่แอปของคุณในการเข้าถึงข้อมูลส่วนตัวของผู้ใช้
- รอให้ผู้ใช้เรียกใช้งานหรือการดำเนินการในแอป ที่ต้องใช้สิทธิ์เข้าถึงข้อมูลส่วนตัวบางอย่างของผู้ใช้ ในขณะนั้น แอปของคุณจะทำสิ่งต่อไปนี้ได้ ขอสิทธิ์รันไทม์ที่จำเป็นสำหรับการเข้าถึงข้อมูลนั้น
ตรวจสอบว่าผู้ใช้ให้สิทธิ์รันไทม์แล้วหรือไม่ สิทธิ์ที่แอปของคุณต้องการ หากเป็นเช่นนั้น แอปของคุณจะสามารถเข้าถึง ข้อมูลส่วนตัวของผู้ใช้ หากยัง ให้ไปยังขั้นตอนถัดไป
คุณต้องตรวจสอบว่าได้รับอนุญาตทุกครั้งที่ดำเนินการ การดำเนินการที่ต้องใช้สิทธิ์นั้น
ตรวจสอบว่าแอปควรแสดงเหตุผลต่อผู้ใช้หรือไม่ ซึ่งอธิบายว่าเหตุใดแอปของคุณจำเป็นต้องให้ผู้ใช้มอบสิทธิ์รันไทม์หนึ่งๆ โดยเฉพาะ หากระบบระบุว่าแอปไม่ควรแสดงเหตุผล ให้ดำเนินการต่อ ขั้นตอนถัดไปได้โดยตรง โดยไม่ต้องแสดงองค์ประกอบ UI
แต่หากระบบพิจารณาว่าแอปของคุณควรแสดงเหตุผล แสดงเหตุผลแก่ผู้ใช้ในองค์ประกอบ UI ในเหตุผลนี้ อธิบายข้อมูลที่แอปของคุณพยายามเข้าถึงอย่างชัดเจนและประโยชน์ที่แอปพยายามเข้าถึง แอปสามารถแสดงต่อผู้ใช้ได้หากให้สิทธิ์รันไทม์ หลัง ผู้ใช้รับทราบเหตุผลแล้ว ให้ไปยังขั้นตอนถัดไป
ขอสิทธิ์รันไทม์ที่แอปของคุณต้องการ เพื่อเข้าถึงข้อมูลส่วนตัวของผู้ใช้ ระบบจะแสดงรันไทม์ ข้อความแจ้งสิทธิ์ เช่น สิทธิ์ที่แสดงในภาพรวมสิทธิ์
ตรวจสอบคำตอบของผู้ใช้ ไม่ว่าผู้ใช้จะเลือกที่จะให้หรือปฏิเสธ สิทธิ์รันไทม์
หากผู้ใช้ให้สิทธิ์แอปของคุณ คุณก็จะเข้าถึง ข้อมูลผู้ใช้ หากผู้ใช้ปฏิเสธการอนุญาตแทน ให้ลดระดับอย่างสุภาพ ประสบการณ์การใช้งานแอปเพื่อเสนอฟังก์ชันให้กับผู้ใช้ หากไม่มีข้อมูลที่มีการป้องกันโดยการอนุญาตนั้น
รูปที่ 1 แสดงเวิร์กโฟลว์และชุดการตัดสินใจที่เกี่ยวข้องกับเรื่องนี้ กระบวนการ:
ตรวจสอบว่าแอปได้รับสิทธิ์แล้วหรือไม่
หากต้องการตรวจสอบว่าผู้ใช้ได้ให้สิทธิ์หนึ่งๆ แก่แอปของคุณแล้วหรือไม่ ให้ส่งผ่าน
สิทธิ์ดังกล่าวลงใน
ContextCompat.checkSelfPermission()
เมธอดนี้จะส่งคืน
PERMISSION_GRANTED
หรือ PERMISSION_DENIED
ขึ้นอยู่กับว่าแอปมีสิทธิ์หรือไม่
อธิบายเหตุผลที่แอปต้องการสิทธิ์
กล่องโต้ตอบสิทธิ์ที่ระบบแสดงเมื่อคุณเรียกใช้
requestPermissions()
บอกสิทธิ์ที่แอปต้องการ แต่ไม่ได้บอก
ทำไม ในบางกรณี ผู้ใช้อาจพบว่าดูน่าสงสัย คุณควร
อธิบายให้ผู้ใช้ทราบว่าทำไมแอปของคุณจึงต้องการสิทธิ์ก่อนที่จะโทร
requestPermissions()
ผลการวิจัยแสดงให้เห็นว่าผู้ใช้รู้สึกสบายใจขึ้นมากกับคำขอสิทธิ์ หาก ทราบเหตุผลที่แอปต้องการ เช่น จำเป็นต้องขอสิทธิ์เพื่อ รองรับฟีเจอร์หลักของแอปหรือสำหรับการโฆษณา ดังนั้นหากคุณ โดยใช้เพียงการเรียก API เพียงบางส่วนซึ่งอยู่ในกลุ่มสิทธิ์ ช่วยระบุอย่างชัดเจนถึงสิทธิ์ที่คุณใช้และเหตุผล สำหรับ ตัวอย่างเช่น ถ้าคุณใช้เฉพาะตำแหน่งคร่าวๆ ให้แจ้งให้ผู้ใช้ทราบเรื่องนี้ใน คำอธิบายแอปหรือในบทความช่วยเหลือเกี่ยวกับแอป
ในบางกรณี คุณควรแจ้งให้ผู้ใช้ทราบเกี่ยวกับ การเข้าถึงข้อมูลที่ละเอียดอ่อนแบบเรียลไทม์ ตัวอย่างเช่น หากคุณกำลังเข้าถึง กล้องหรือไมโครโฟน คุณควรแจ้งให้ผู้ใช้ทราบโดยใช้ ไอคอนการแจ้งเตือนที่ใดที่หนึ่งในแอปของคุณ หรือในถาดการแจ้งเตือน ทำงานในพื้นหลัง) จึงดูเหมือนว่าคุณไม่ได้กำลัง เก็บรวบรวมข้อมูลโดยไม่เปิดเผย
สุดท้ายแล้ว หากคุณต้องการขอสิทธิ์เพื่อทำสิ่งต่างๆ ในแอป แต่เหตุผลที่ผู้ใช้ไม่ชัดเจนคือหาวิธีที่ผู้ใช้ รู้ว่าทำไมคุณถึงต้องมีสิทธิ์ที่ละเอียดอ่อนที่สุด
หากเมธอด ContextCompat.checkSelfPermission()
แสดง PERMISSION_DENIED
โทรหา shouldShowRequestPermissionRationale()
หากวิธีนี้แสดงผล true
ให้แสดง UI ด้านการศึกษาแก่ผู้ใช้ ใน UI นี้
อธิบายว่าทำไมคุณลักษณะที่ผู้ใช้ต้องการเปิดใช้
สิทธิ์
นอกจากนี้หากแอปขอสิทธิ์ที่เกี่ยวข้องกับตำแหน่ง ไมโครโฟน หรือกล้องถ่ายรูป ให้พิจารณาอธิบายเหตุผลที่แอปต้องการ การเข้าถึงข้อมูลนี้ได้
ขอสิทธิ์
หลังจากที่ผู้ใช้ดู UI เพื่อการศึกษา หรือค่าที่ส่งกลับของ
shouldShowRequestPermissionRationale()
บ่งบอกว่าคุณไม่จำเป็นต้องแสดง
UI การศึกษา ให้ขอสิทธิ์ ผู้ใช้จะเห็นระบบ
กล่องโต้ตอบสิทธิ์ ซึ่งผู้ใช้สามารถเลือกว่าจะให้สิทธิ์
สิทธิ์ในแอปของคุณ
โดยใช้ RequestPermission
ซึ่งรวมอยู่ในไลบรารี AndroidX ที่คุณอนุญาตให้ระบบจัดการ
รหัสคำขอสิทธิ์ให้คุณ เพราะ
การใช้สัญญา RequestPermission
จะทำให้ตรรกะของคุณง่ายขึ้น เราจึงแนะนำให้ทำ
โซลูชันเมื่อทำได้ อย่างไรก็ตาม หากจำเป็น คุณยังสามารถจัดการรหัสคำขอได้ด้วย
เป็นส่วนหนึ่งของคำขอสิทธิ์และ
รวมโค้ดคำขอนี้ไว้ในตรรกะ Callback สิทธิ์ของคุณ
อนุญาตให้ระบบจัดการรหัสคำขอสิทธิ์
เพื่อช่วยให้ระบบสามารถจัดการรหัสคำขอที่เชื่อมโยงกับ
คำขอสิทธิ์ ให้เพิ่มทรัพยากร Dependency ในไลบรารีต่อไปนี้ใน
ไฟล์ build.gradle
ของโมดูล:
androidx.activity
เวอร์ชัน 1.2.0 ขึ้นไปandroidx.fragment
เวอร์ชัน 1.3.0 ขึ้นไป
จากนั้นคุณสามารถใช้ชั้นเรียนต่อไปนี้
- หากต้องการขอสิทธิ์เดียว ให้ใช้
RequestPermission
- หากต้องการขอสิทธิ์หลายรายการพร้อมกัน ให้ใช้
RequestMultiplePermissions
ขั้นตอนต่อไปนี้จะแสดงวิธีใช้สัญญา RequestPermission
กระบวนการสำหรับสัญญา RequestMultiplePermissions
จะเกือบเหมือนกัน
ในตรรกะการเริ่มต้นของกิจกรรมหรือส่วนย่อย ให้ส่งผ่านการติดตั้งใช้งาน จาก
ActivityResultCallback
เป็นการเรียกเพื่อregisterForActivityResult()
ActivityResultCallback
จะกำหนดวิธีที่แอปของคุณจัดการกับการตอบสนองของผู้ใช้ต่อ คำขอสิทธิ์เก็บการอ้างอิงค่า
registerForActivityResult()
ที่แสดงผลไว้ เป็นประเภทActivityResultLauncher
หากต้องการแสดงกล่องโต้ตอบสิทธิ์ของระบบเมื่อจำเป็น ให้เรียกใช้
launch()
ในอินสแตนซ์ของActivityResultLauncher
ที่คุณบันทึกไว้ใน ขั้นตอนก่อนหน้าหลังจากเรียก
launch()
แล้ว กล่องโต้ตอบสิทธิ์ของระบบจะปรากฏขึ้น เมื่อ ผู้ใช้เลือก ระบบจะเรียกใช้การติดตั้งใช้งานของคุณแบบไม่พร้อมกัน ของActivityResultCallback
ซึ่งคุณกำหนดไว้ในขั้นตอนก่อนหน้าหมายเหตุ: แอปของคุณไม่สามารถปรับแต่งกล่องโต้ตอบที่ปรากฏ เมื่อคุณโทรหา
launch()
หากต้องการให้ข้อมูลเพิ่มเติมหรือ เปลี่ยน UI ของแอปเพื่อให้ผู้ใช้ดำเนินการได้ง่ายขึ้น ทำความเข้าใจว่าทำไมฟีเจอร์ในแอปของคุณจึงต้องการสิทธิ์บางอย่าง สำหรับ ตัวอย่างเช่น คุณอาจเปลี่ยนข้อความในปุ่มที่เปิดใช้นอกจากนี้ ข้อความในกล่องโต้ตอบสิทธิ์ของระบบยังอ้างอิงฟังก์ชัน สิทธิ์ กลุ่มที่เชื่อมโยงกับสิทธิ์ที่คุณขอ ช่วงเวลานี้ การจัดกลุ่มสิทธิ์ได้รับการออกแบบมาเพื่อทำให้ใช้งานระบบได้ง่าย และแอปของคุณ ไม่ควรพึ่งพาสิทธิ์ที่อยู่ในหรือภายนอก กลุ่มสิทธิ์
ข้อมูลโค้ดต่อไปนี้แสดงวิธีจัดการการตอบกลับสิทธิ์
Kotlin
// Register the permissions callback, which handles the user's response to the // system permissions dialog. Save the return value, an instance of // ActivityResultLauncher. You can use either a val, as shown in this snippet, // or a lateinit var in your onAttach() or onCreate() method. val requestPermissionLauncher = registerForActivityResult(RequestPermission() ) { isGranted: Boolean -> if (isGranted) { // Permission is granted. Continue the action or workflow in your // app. } else { // Explain to the user that the feature is unavailable because the // feature requires a permission that the user has denied. At the // same time, respect the user's decision. Don't link to system // settings in an effort to convince the user to change their // decision. } }
Java
// Register the permissions callback, which handles the user's response to the // system permissions dialog. Save the return value, an instance of // ActivityResultLauncher, as an instance variable. private ActivityResultLauncher<String> requestPermissionLauncher = registerForActivityResult(new RequestPermission(), isGranted -> { if (isGranted) { // Permission is granted. Continue the action or workflow in your // app. } else { // Explain to the user that the feature is unavailable because the // feature requires a permission that the user has denied. At the // same time, respect the user's decision. Don't link to system // settings in an effort to convince the user to change their // decision. } });
และข้อมูลโค้ดนี้แสดงขั้นตอนที่แนะนำให้ตรวจสอบ สิทธิ์และการขอสิทธิ์จากผู้ใช้เมื่อจำเป็น
Kotlin
when { ContextCompat.checkSelfPermission( CONTEXT, Manifest.permission.REQUESTED_PERMISSION ) == PackageManager.PERMISSION_GRANTED -> { // You can use the API that requires the permission. } ActivityCompat.shouldShowRequestPermissionRationale( this, Manifest.permission.REQUESTED_PERMISSION) -> { // In an educational UI, explain to the user why your app requires this // permission for a specific feature to behave as expected, and what // features are disabled if it's declined. In this UI, include a // "cancel" or "no thanks" button that lets the user continue // using your app without granting the permission. showInContextUI(...) } else -> { // You can directly ask for the permission. // The registered ActivityResultCallback gets the result of this request. requestPermissionLauncher.launch( Manifest.permission.REQUESTED_PERMISSION) } }
Java
if (ContextCompat.checkSelfPermission( CONTEXT, Manifest.permission.REQUESTED_PERMISSION) == PackageManager.PERMISSION_GRANTED) { // You can use the API that requires the permission. performAction(...); } else if (ActivityCompat.shouldShowRequestPermissionRationale( this, Manifest.permission.REQUESTED_PERMISSION)) { // In an educational UI, explain to the user why your app requires this // permission for a specific feature to behave as expected, and what // features are disabled if it's declined. In this UI, include a // "cancel" or "no thanks" button that lets the user continue // using your app without granting the permission. showInContextUI(...); } else { // You can directly ask for the permission. // The registered ActivityResultCallback gets the result of this request. requestPermissionLauncher.launch( Manifest.permission.REQUESTED_PERMISSION); }
จัดการรหัสคำขอสิทธิ์ด้วยตนเอง
ทางเลือกในการอนุญาตให้ระบบจัดการคำขอสิทธิ์
คุณสามารถจัดการคำขอสิทธิ์ได้
ด้วยตัวเอง โดยใส่รหัสคำขอในการโทรหา
requestPermissions()
ข้อมูลโค้ดต่อไปนี้แสดงวิธีขอสิทธิ์โดยใช้ รหัสคำขอ:
Kotlin
when { ContextCompat.checkSelfPermission( CONTEXT, Manifest.permission.REQUESTED_PERMISSION ) == PackageManager.PERMISSION_GRANTED -> { // You can use the API that requires the permission. performAction(...) } ActivityCompat.shouldShowRequestPermissionRationale( this, Manifest.permission.REQUESTED_PERMISSION) -> { // In an educational UI, explain to the user why your app requires this // permission for a specific feature to behave as expected, and what // features are disabled if it's declined. In this UI, include a // "cancel" or "no thanks" button that lets the user continue // using your app without granting the permission. showInContextUI(...) } else -> { // You can directly ask for the permission. requestPermissions(CONTEXT, arrayOf(Manifest.permission.REQUESTED_PERMISSION), REQUEST_CODE) } }
Java
if (ContextCompat.checkSelfPermission( CONTEXT, Manifest.permission.REQUESTED_PERMISSION) == PackageManager.PERMISSION_GRANTED) { // You can use the API that requires the permission. performAction(...); } else if (ActivityCompat.shouldShowRequestPermissionRationale( this, Manifest.permission.REQUESTED_PERMISSION)) { // In an educational UI, explain to the user why your app requires this // permission for a specific feature to behave as expected, and what // features are disabled if it's declined. In this UI, include a // "cancel" or "no thanks" button that lets the user continue // using your app without granting the permission. showInContextUI(...); } else { // You can directly ask for the permission. requestPermissions(CONTEXT, new String[] { Manifest.permission.REQUESTED_PERMISSION }, REQUEST_CODE); }
หลังจากที่ผู้ใช้ตอบกลับกล่องโต้ตอบสิทธิ์ของระบบแล้ว ระบบจะดำเนินการต่อไปนี้
เรียกใช้การใช้งาน onRequestPermissionsResult()
ของแอป ระบบจะส่งต่อให้ผู้ใช้
การตอบกลับกล่องโต้ตอบสิทธิ์ ตลอดจนรหัสคำขอที่คุณกำหนด
ดังที่แสดงในข้อมูลโค้ดต่อไปนี้
Kotlin
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { when (requestCode) { PERMISSION_REQUEST_CODE -> { // If request is cancelled, the result arrays are empty. if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) { // Permission is granted. Continue the action or workflow // in your app. } else { // Explain to the user that the feature is unavailable because // the feature requires a permission that the user has denied. // At the same time, respect the user's decision. Don't link to // system settings in an effort to convince the user to change // their decision. } return } // Add other 'when' lines to check for other // permissions this app might request. else -> { // Ignore all other requests. } } }
Java
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch (requestCode) { case PERMISSION_REQUEST_CODE: // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Permission is granted. Continue the action or workflow // in your app. } else { // Explain to the user that the feature is unavailable because // the feature requires a permission that the user has denied. // At the same time, respect the user's decision. Don't link to // system settings in an effort to convince the user to change // their decision. } return; } // Other 'case' lines to check for other // permissions this app might request. } }
ขอสิทธิ์เข้าถึงตำแหน่ง
เมื่อคุณขอสิทธิ์เข้าถึงตำแหน่ง ให้ทำตามแนวทางปฏิบัติแนะนำเดียวกับ สำหรับสิทธิ์รันไทม์อื่นๆ หรือไม่ ความแตกต่างที่สำคัญอย่างหนึ่งเกี่ยวกับสิทธิ์เข้าถึงตำแหน่งคือ มีสิทธิ์หลายอย่างที่เกี่ยวข้องกับตำแหน่ง สิทธิ์ที่คุณ ทั้งนี้ขึ้นอยู่กับข้อกำหนดสถานที่ตั้งสำหรับ Use Case ของแอป
ตำแหน่งเบื้องหน้า
หากแอปมีฟีเจอร์ที่แชร์หรือได้รับข้อมูลตำแหน่งเท่านั้น ครั้งเดียว หรือตามระยะเวลาที่กำหนดไว้ ฟีเจอร์นั้นจะต้องอยู่เบื้องหน้า การเข้าถึงตำแหน่ง ตัวอย่างมีดังต่อไปนี้
- ภายในแอปนำทาง ฟีเจอร์ช่วยให้ผู้ใช้ดูเส้นทางแบบเลี้ยวต่อเลี้ยวได้ เส้นทาง
- ในแอปรับส่งข้อความ ฟีเจอร์ช่วยให้ผู้ใช้แชร์ตําแหน่งปัจจุบันของตนเองได้ กับผู้ใช้รายอื่น
ระบบจะพิจารณาว่าแอปของคุณกำลังใช้ตําแหน่งในเบื้องหน้าหากฟีเจอร์ของ แอปของคุณเข้าถึงตำแหน่งปัจจุบันของอุปกรณ์ด้วยตำแหน่งใดตำแหน่งหนึ่งต่อไปนี้ สถานการณ์:
- คุณจะเห็นกิจกรรมที่เป็นของแอป
แอปของคุณกำลังใช้บริการที่ทำงานอยู่เบื้องหน้า เมื่อบริการที่ทำงานอยู่เบื้องหน้า ระบบจะเพิ่มการรับรู้ของผู้ใช้โดยแสดงการแจ้งเตือนตลอดเวลา แอปของคุณยังคงมีสิทธิ์เข้าถึงเมื่อวางในเบื้องหลัง เช่น เมื่อแอป ผู้ใช้กดปุ่มหน้าแรกบนอุปกรณ์หรือหมุนจอแสดงผลของอุปกรณ์ ปิดอยู่
ใน Android 10 (API ระดับ 29) ขึ้นไป คุณต้องประกาศเบื้องหน้า ประเภทบริการ
location
ดังที่แสดงในข้อมูลโค้ดต่อไปนี้ ในเวอร์ชันก่อนหน้า ของ Android ขอแนะนำให้คุณประกาศบริการที่ทำงานอยู่เบื้องหน้าประเภทนี้<!-- Recommended for Android 9 (API level 28) and lower. --> <!-- Required for Android 10 (API level 29) and higher. --> <service android:name="MyNavigationService" android:foregroundServiceType="location" ... > <!-- Any inner elements go here. --> </service>
คุณประกาศความจำเป็นในเบื้องหน้าเมื่อแอปขอตำแหน่ง
ACCESS_COARSE_LOCATION
หรือสิทธิ์
ACCESS_FINE_LOCATION
สิทธิ์ตามที่แสดงในข้อมูลโค้ดต่อไปนี้
<manifest ... > <!-- Include this permission any time your app needs location information. --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- Include only if your app benefits from precise location access. --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> </manifest>
ตำแหน่งในเบื้องหลัง
แอปต้องการสิทธิ์เข้าถึงตำแหน่งในเบื้องหลังหากฟีเจอร์ภายในแอป จะแชร์ตำแหน่งกับผู้ใช้คนอื่นๆ อย่างต่อเนื่องหรือใช้การกำหนดเขตพื้นที่เสมือน API ดังตัวอย่างต่อไปนี้
- ภายในแอปการแชร์ตำแหน่งของครอบครัว ฟีเจอร์ช่วยให้ผู้ใช้อย่างต่อเนื่อง แชร์ตำแหน่งกับสมาชิกในครอบครัว
- ภายในแอป IoT ฟีเจอร์นี้ช่วยให้ผู้ใช้สามารถกำหนดค่าอุปกรณ์ในบ้านได้ ที่จะปิดเมื่อผู้ใช้ออกจากบ้านไปและเปิดอีกครั้งเมื่อ ผู้ใช้กลับถึงบ้าน
ระบบจะพิจารณาว่าแอปของคุณใช้ตําแหน่งในเบื้องหลังหากเข้าถึง ตําแหน่งปัจจุบันของอุปกรณ์ในสถานการณ์อื่นๆ นอกเหนือจากที่อธิบายไว้ใน ตำแหน่งเบื้องหน้า ความแม่นยำของตำแหน่งในเบื้องหลังคือ เหมือนกับความแม่นยำของตำแหน่งเบื้องหน้า ซึ่งขึ้นอยู่กับ สิทธิ์เข้าถึงตำแหน่งที่แอปประกาศ
ใน Android 10 (API ระดับ 29) ขึ้นไป คุณต้องประกาศ
ACCESS_BACKGROUND_LOCATION
สิทธิ์ในไฟล์ Manifest ของแอปเพื่อขอตำแหน่งในเบื้องหลัง
เข้าถึงขณะรันไทม์ ในเวอร์ชันก่อนหน้านี้ของ
Android เมื่อแอปเข้าถึงตำแหน่งในเบื้องหน้า แอปจะทำโดยอัตโนมัติ
จะได้รับสิทธิ์เข้าถึงตำแหน่งในเบื้องหลังด้วย
<manifest ... > <!-- Required only when requesting background location access on Android 10 (API level 29) and higher. --> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> </manifest>
จัดการการปฏิเสธสิทธิ์
หากผู้ใช้ปฏิเสธคำขอสิทธิ์ แอปของคุณควรช่วยให้ผู้ใช้เข้าใจ ผลกระทบจากการปฏิเสธสิทธิ์ โดยเฉพาะอย่างยิ่ง แอปของคุณควรสร้าง ผู้ใช้ทราบถึงฟีเจอร์ที่ใช้งานไม่ได้เนื่องจากไม่มีสิทธิ์ เมื่อคุณดำเนินการดังกล่าว โปรดคำนึงถึงแนวทางปฏิบัติแนะนำต่อไปนี้
ชี้นำความสนใจของผู้ใช้ ไฮไลต์ส่วนที่เฉพาะเจาะจงใน UI ของแอป ที่มีฟังก์ชันการทำงานที่จำกัดเพราะแอปของคุณไม่มี สิทธิ์ ตัวอย่างสิ่งที่คุณจะทำได้มีดังต่อไปนี้
- แสดงข้อความที่จะปรากฏผลการค้นหาหรือข้อมูลของสถานที่
- แสดงปุ่มอื่นที่มีไอคอนและสีข้อผิดพลาด
ใช้คำที่เฉพาะเจาะจง อย่าแสดงข้อความทั่วไป แต่ให้ระบุให้ชัดเจนว่า ไม่พร้อมใช้งานเนื่องจากแอปของคุณไม่มีสิทธิ์ที่จำเป็น
อย่าบล็อกอินเทอร์เฟซผู้ใช้ กล่าวคือ อย่าแสดง ข้อความเตือนแบบเต็มหน้าจอที่ป้องกันไม่ให้ผู้ใช้ใช้แอปของคุณต่อ เลย
ในขณะเดียวกัน แอปควรเคารพการตัดสินใจของผู้ใช้ในการปฏิเสธ สิทธิ์ เริ่มตั้งแต่ Android 11 (API ระดับ 30) เป็นต้นไป หากผู้ใช้แตะปฏิเสธสำหรับ สิทธิ์ที่เฉพาะเจาะจงมากกว่า 1 ครั้งตลอดอายุการติดตั้งแอป ในอุปกรณ์ ผู้ใช้จะไม่เห็นกล่องโต้ตอบสิทธิ์ของระบบหากแอปของคุณ ขอสิทธิ์นั้นอีกครั้ง การดำเนินการของผู้ใช้บอกเป็นนัยว่า "อย่าถามอีก" เปิด เวอร์ชันก่อนหน้า ผู้ใช้จะเห็นกล่องโต้ตอบสิทธิ์ของระบบในแต่ละครั้งที่ แอปขอสิทธิ์ เว้นแต่ผู้ใช้จะเลือก "ไม่ต้องถาม" ไว้ก่อนหน้านี้ อีกครั้ง" ช่องทำเครื่องหมายหรือตัวเลือก
หากผู้ใช้ปฏิเสธคำขอสิทธิ์มากกว่า 1 ครั้ง จะถือว่าเป็นการดำเนินการถาวร ปฏิเสธ เป็นเรื่องสำคัญมากที่ต้องแสดงข้อความแจ้งผู้ใช้เกี่ยวกับสิทธิ์เมื่อจำเป็นเท่านั้น การเข้าถึงคุณลักษณะบางอย่าง มิฉะนั้นคุณอาจสูญเสียความสามารถไปโดยไม่ตั้งใจ เพื่อขอสิทธิ์อีกครั้ง
ในบางสถานการณ์ การอนุญาตอาจถูกปฏิเสธโดยอัตโนมัติ โดยที่ไม่มี ผู้ใช้ดำเนินการใดๆ (อาจมีการให้สิทธิ์ โดยอัตโนมัติด้วย) โปรดอย่าทึกทักเอาเองเกี่ยวกับระบบอัตโนมัติ พฤติกรรมของคุณ ทุกครั้งที่แอปของคุณต้องการเข้าถึงฟังก์ชันการทำงานที่ต้องมี ให้ตรวจสอบว่าแอปของคุณยังคงได้รับสิทธิ์นั้นอยู่
เพื่อมอบประสบการณ์ที่ดีที่สุดแก่ผู้ใช้เมื่อขอแอป โปรดดูแนวทางปฏิบัติแนะนำเกี่ยวกับสิทธิ์ของแอปด้วย
ตรวจสอบสถานะการปฏิเสธขณะทดสอบและแก้ไขข้อบกพร่อง
ใช้เพื่อระบุว่าแอปถูกปฏิเสธสิทธิ์อย่างถาวรหรือไม่ (สำหรับการแก้ไขข้อบกพร่อง และวัตถุประสงค์ในการทดสอบ) ให้ใช้คำสั่งต่อไปนี้
adb shell dumpsys package PACKAGE_NAME
โดย PACKAGE_NAME คือชื่อแพ็กเกจที่จะตรวจสอบ
เอาต์พุตของคำสั่งมีส่วนที่มีลักษณะเช่นนี้
... runtime permissions: android.permission.POST_NOTIFICATIONS: granted=false, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED] android.permission.ACCESS_FINE_LOCATION: granted=false, flags=[ USER_SET|USER_FIXED|USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED] android.permission.BLUETOOTH_CONNECT: granted=false, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED] ...
สิทธิ์ที่ผู้ใช้ปฏิเสธ 1 ครั้งจะมีการแจ้งว่าไม่เหมาะสมโดย USER_SET
สิทธิ์ที่ถูกปฏิเสธอย่างถาวรด้วยการเลือกปฏิเสธ 2 ครั้งคือ
รายงานโดย USER_FIXED
รีเซ็ตแฟล็กเหล่านี้เพื่อให้ผู้ทดสอบเห็นกล่องโต้ตอบคำขอระหว่างการทดสอบ เมื่อแก้ไขข้อบกพร่องของแอปเสร็จแล้ว โดยใช้คำสั่งต่อไปนี้
adb shell pm clear-permission-flags PACKAGE_NAME PERMISSION_NAME user-set user-fixed
PERMISSION_NAME คือชื่อของสิทธิ์ที่คุณต้องการ รีเซ็ต
หากต้องการดูรายการสิทธิ์ของแอป Android ทั้งหมด ให้ไปที่ permissions API หน้าอ้างอิง
สิทธิ์ครั้งเดียว
เริ่มตั้งแต่ Android 11 (API ระดับ 30) เมื่อใดก็ตามที่แอปขอสิทธิ์ เกี่ยวข้องกับตำแหน่ง ไมโครโฟน หรือกล้อง กล่องโต้ตอบสิทธิ์ที่แสดงต่อผู้ใช้ มีตัวเลือกที่เรียกว่าเฉพาะครั้งนี้ ดังที่แสดงในรูปที่ 2 หากผู้ใช้เลือกตัวเลือกนี้ ในกล่องโต้ตอบ แอปของคุณจะได้รับสิทธิ์แบบครั้งเดียวชั่วคราว
จากนั้น แอปของคุณจะสามารถเข้าถึงข้อมูลที่เกี่ยวข้องในช่วงระยะเวลาหนึ่งซึ่งขึ้นอยู่กับ ลักษณะการทำงานของแอปและการกระทำของผู้ใช้
- โดยแอปจะเข้าถึงข้อมูลได้ขณะที่ระบบแสดงกิจกรรมของแอป
- หากผู้ใช้ส่งแอปไปยังเบื้องหลัง แอปจะยังเข้าถึงแอปต่อไปได้ ข้อมูลเป็นระยะเวลาสั้นๆ
- หากคุณเปิดใช้บริการที่ทำงานอยู่เบื้องหน้าขณะแสดงกิจกรรม และผู้ใช้ จากนั้นย้ายแอปไปยังพื้นหลัง แอปจะยังคงเข้าถึงข้อมูลต่อไปได้ จนกว่าบริการที่ทำงานอยู่เบื้องหน้าจะหยุดลง
กระบวนการของแอปจะสิ้นสุดเมื่อมีการเพิกถอนสิทธิ์
หากผู้ใช้เพิกถอนสิทธิ์แบบครั้งเดียว เช่น ในการตั้งค่าระบบ แอปเข้าถึงข้อมูลไม่ได้ ไม่ว่าคุณจะเปิดใช้เบื้องหน้าหรือไม่ก็ตาม service. เช่นเดียวกับสิทธิ์อื่นๆ หากผู้ใช้เพิกถอนแอปของคุณ 1 ครั้ง ขั้นตอนของแอปจะสิ้นสุดลง
เมื่อผู้ใช้เปิดแอปของคุณในครั้งถัดไป และฟีเจอร์ในแอปของคุณขอสิทธิ์เข้าถึง ตำแหน่ง ไมโครโฟน หรือกล้อง ระบบจะแจ้งให้ผู้ใช้ขอสิทธิ์อีกครั้ง
รีเซ็ตสิทธิ์ที่ไม่ได้ใช้
Android มอบวิธีที่หลากหลายในการรีเซ็ตสิทธิ์รันไทม์ที่ไม่ได้ใช้ให้แก่ ค่าเริ่มต้น, สถานะถูกปฏิเสธ:
- API ที่คุณนำสิทธิ์เข้าถึงของแอปออกด้วยตนเองได้ สิทธิ์รันไทม์ที่ไม่ได้ใช้
- กลไกของระบบซึ่งจะ รีเซ็ตสิทธิ์ของแอปที่ไม่ได้ใช้
นำสิทธิ์เข้าถึงของแอปออก
ใน Android 13 (API ระดับ 33) ขึ้นไป คุณนำสิทธิ์เข้าถึงของแอปออกได้ สิทธิ์รันไทม์ที่แอปของคุณไม่ต้องใช้อีกต่อไป เมื่อคุณอัปเดตแอป ดำเนินการตามขั้นตอนนี้เพื่อให้ผู้ใช้มีแนวโน้มที่จะเข้าใจว่าทำไมแอปของคุณ จะยังคงขอสิทธิ์ที่เฉพาะเจาะจงต่อไป ความรู้นี้ช่วยสร้างความไว้วางใจให้กับผู้ใช้ ในแอปของคุณ
หากต้องการยกเลิกสิทธิ์เข้าถึงสิทธิ์รันไทม์ ให้ส่งชื่อสิทธิ์นั้น
เข้าสู่
revokeSelfPermissionOnKill()
หากต้องการนำสิทธิ์เข้าถึงกลุ่มสิทธิ์รันไทม์ออกพร้อมกัน ให้ส่ง
การรวบรวมชื่อสิทธิ์
revokeSelfPermissionsOnKill()
กระบวนการนำสิทธิ์ออกจะเกิดขึ้นไม่พร้อมกันและทำให้กระบวนการทั้งหมดหยุดทำงาน
ที่เชื่อมโยงกับ UID ของแอป
หากต้องการให้ระบบนำสิทธิ์เข้าถึงสิทธิ์ของแอปออก กระบวนการที่เชื่อมโยงกับแอปของคุณจะถูกยกเลิก เมื่อคุณเรียก API ระบบจะ เป็นตัวกำหนดว่าโฆษณาจะยุติกระบวนการเหล่านี้เมื่อใด โดยทั่วไป ระบบจะรอ จนกว่าแอปของคุณจะใช้เวลานานในการทำงานในเบื้องหลัง แทนที่จะเป็นเบื้องหน้า
เพื่อแจ้งผู้ใช้ว่าแอปของคุณไม่จำเป็นต้องเข้าถึงรันไทม์ที่เจาะจงอีกต่อไป แสดงกล่องโต้ตอบในครั้งถัดไปที่ผู้ใช้เปิดแอปของคุณ กล่องโต้ตอบนี้ สามารถรวมรายการสิทธิ์ได้
รีเซ็ตสิทธิ์ของแอปที่ไม่ได้ใช้โดยอัตโนมัติ
หากแอปกำหนดเป้าหมายเป็น Android 11 (API ระดับ 30) ขึ้นไปและไม่ได้ใช้งานสำหรับ 2-3 รายการ ระบบจะปกป้องข้อมูลผู้ใช้ด้วยการรีเซ็ตข้อมูลที่ละเอียดอ่อนโดยอัตโนมัติ สิทธิ์รันไทม์ที่ผู้ใช้ให้สิทธิ์แอปของคุณ ดูข้อมูลเพิ่มเติมในคำแนะนำ เกี่ยวกับการพักใช้งานแอป
ขอเป็นเครื่องจัดการเริ่มต้นหากจำเป็น
แอปบางแอปอาศัยสิทธิ์เข้าถึงข้อมูลที่ละเอียดอ่อนของผู้ใช้ซึ่งเกี่ยวข้องกับประวัติการโทร และข้อความ SMS หากต้องการขอสิทธิ์เฉพาะสำหรับประวัติการโทร และข้อความ SMS และเผยแพร่แอปไปยัง Play Store คุณจะต้องแจ้ง ผู้ใช้สามารถตั้งค่าแอปของคุณเป็นตัวแฮนเดิลเริ่มต้นสําหรับฟังก์ชันหลักของระบบก่อน ที่ขอสิทธิ์รันไทม์เหล่านี้
สําหรับข้อมูลเพิ่มเติมเกี่ยวกับตัวแฮนเดิลเริ่มต้น รวมถึงคําแนะนําเกี่ยวกับการแสดง ข้อความแจ้งของตัวแฮนเดิลเริ่มต้นแก่ผู้ใช้ โปรดดูคำแนะนำเกี่ยวกับสิทธิ์ที่ใช้เฉพาะใน ตัวแฮนเดิลเริ่มต้น
ให้สิทธิ์รันไทม์ทั้งหมดเพื่อวัตถุประสงค์ในการทดสอบ
วิธีให้สิทธิ์รันไทม์ทั้งหมดโดยอัตโนมัติเมื่อคุณติดตั้งแอปใน
โปรแกรมจำลองหรืออุปกรณ์ทดสอบ ให้ใช้ตัวเลือก -g
สำหรับ adb shell install
ดังที่แสดงในข้อมูลโค้ดต่อไปนี้
adb shell install -g PATH_TO_APK_FILE
แหล่งข้อมูลเพิ่มเติม
อ่านบทความต่อไปนี้เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับสิทธิ์
ดูข้อมูลเพิ่มเติมเกี่ยวกับการขอสิทธิ์ได้ที่ ตัวอย่างสิทธิ์
นอกจากนี้คุณยังดำเนินการตาม Codelab นี้ที่สาธิตให้เห็นถึงความเป็นส่วนตัวได้ดีที่สุด แนวทางปฏิบัติที่ดีที่สุด