บริการ Google Play และสิทธิ์รันไทม์

ตั้งแต่ Android 6.0 Marshmallow เป็นต้นมา Android ใช้รูปแบบสิทธิ์ที่ช่วยให้กระบวนการติดตั้งแอปและอัปเดตอัตโนมัติมีประสิทธิภาพมากขึ้น มีการขอสิทธิ์ในระหว่างรันไทม์แทนที่จะเป็นก่อนการติดตั้งแอป นอกจากนี้ ผู้ใช้ยังเลือกปฏิเสธสิทธิ์บางอย่างได้ด้วย หากต้องการให้ผู้ใช้มีความยืดหยุ่นเช่นนี้ คุณต้องตรวจสอบว่าแอปทำงานตามที่คาดไว้เมื่อผู้ใช้เปิดหรือปิดใช้สิทธิ์ที่เฉพาะเจาะจง

บริการ Google Play เองมีสิทธิ์รันไทม์ที่ผู้ใช้เลือกปฏิเสธแยกต่างหากจากสิทธิ์ที่แอปของคุณขอโดยเฉพาะได้ บริการ Google Play จะขอสิทธิ์ทั้งหมดที่จำเป็นต่อการรองรับ API โดยอัตโนมัติ อย่างไรก็ตาม แอปของคุณยังคงควรตรวจสอบและขอสิทธิ์รันไทม์ ตามความจำเป็น รวมถึงจัดการข้อผิดพลาดอย่างเหมาะสมในกรณีที่ผู้ใช้ปฏิเสธ ไม่ให้ Google Play Services มีสิทธิ์ที่จำเป็นสำหรับ API ที่แอปของคุณใช้

แนวทางปฏิบัติที่ดีคือการจัดการความคาดหวังของผู้ใช้ในการตั้งค่าสิทธิ์ ที่รันไทม์อาจต้องใช้ แนวทางปฏิบัติแนะนำต่อไปนี้จะช่วยให้คุณหลีกเลี่ยง ปัญหาที่อาจเกิดขึ้นได้

ข้อกำหนดเบื้องต้น

คุณจะต้องประกาศสิทธิ์ในไฟล์ AndroidManifest.xml เช่น

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

หลักเกณฑ์

ยืนยันสิทธิ์ก่อนเรียกใช้ API

เมื่อประกาศ API ที่ต้องการใช้ในไฟล์ AndroidManifest.xml แล้ว ให้ตรวจสอบว่าคุณมีสิทธิ์ที่จำเป็นก่อนเรียกใช้ API ซึ่งทำได้โดยใช้วิธี checkSelfPermission ของ ActivityCompat หรือ ContextCompat

หากการเรียกใช้แสดงผลเป็นเท็จ แสดงว่าไม่ได้ให้สิทธิ์และคุณ ควรใช้ requestPermissions เพื่อขอสิทธิ์ การตอบกลับคำขอนี้จะ แสดงใน Callback ซึ่งคุณจะเห็นในขั้นตอนถัดไป

เช่น

Kotlin

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED) {
            // Request Permissions Now
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                REQUEST_LOCATION_PERMISSION_CODE)
    } else {
        // permission has been granted, continue as usual
        val locationResult = LocationServices
            .getFusedLocationProviderClient(this /* Context */)
            .lastLocation
    }

Java

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED) {
        // Request Permissions Now
        ActivityCompat.requestPermissions(
            this,
            new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
            REQUEST_LOCATION_PERMISSION_CODE);
    } else {
        // permission has been granted, continue as usual
        Task locationResult = LocationServices
            .getFusedLocationProviderClient(this /** Context */)
            .getLastLocation();
    }

ใช้การเรียกกลับเพื่อขอสิทธิ์

หากผู้ใช้ไม่ได้ให้สิทธิ์ที่แอปของคุณต้องการ คุณควรเรียกใช้เมธอด requestPermissions เพื่อขอให้ผู้ใช้ให้สิทธิ์ ระบบจะบันทึกการตอบกลับจากผู้ใช้ในแฮนเดิลการเรียกกลับ onRequestPermissionsResult แอปของคุณควร ใช้ฟังก์ชันนี้และตรวจสอบค่าที่ส่งคืนเสมอ เนื่องจากคำขออาจถูกปฏิเสธหรือยกเลิก นอกจากนี้ คุณยังขอและตรวจสอบสิทธิ์หลายรายการพร้อมกันได้ด้วย ตัวอย่างต่อไปนี้จะตรวจสอบสิทธิ์เพียงรายการเดียว

Kotlin

    fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array,
        grantResults: IntArray
    ) {
        if (requestCode == REQUEST_LOCATION_PERMISSION_CODE) {
            if (grantResults.singleOrNull() == PackageManager.PERMISSION_GRANTED) {
               // We can now safely use the API we requested access to
               val locationResult: Task = LocationServices
                    .getFusedLocationProviderClient(this /* Context */)
                    .lastLocation // Request the last known location.
            } else {
                // Permission was denied or request was cancelled
            }
        }
    }

Java

    public void onRequestPermissionsResult(int requestCode,
                                            String[] permissions,
                                            int[] grantResults) {
        if (requestCode == REQUEST_LOCATION_PERMISSION_CODE) {
            if(grantResults.length == 1
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // We can now safely use the API we requested access to
                Task locationResult = LocationServices
                    .getFusedLocationProviderClient(this /** Context */)
                    .getLastLocation(); // Request the last known location.
            } else {
                // Permission was denied or request was cancelled
            }
        }
    }

แสดงเหตุผลในการขอสิทธิ์

หากสิทธิ์ที่แอปขอมีความจำเป็นต่อฟีเจอร์หลักของแอป และผู้ใช้เคยปฏิเสธคำขอสิทธิ์มาก่อน แอปควรแสดงคำอธิบายเพิ่มเติมก่อนขอสิทธิ์อีกครั้ง ผู้ใช้ มีแนวโน้มที่จะให้สิทธิ์มากขึ้นเมื่อเข้าใจว่าทำไมจึงต้องมีสิทธิ์ และประโยชน์ที่ผู้ใช้จะได้รับในทันที

ในกรณีนี้ คุณควรโทรหา shouldShowRequestPermissionRationale ก่อนโทรหา requestPermissions หากฟังก์ชันนี้แสดงผลเป็น จริง คุณควรสร้าง UI เพื่อแสดงบริบทเพิ่มเติมสำหรับ สิทธิ์

ตัวอย่างเช่น โค้ดอาจมีลักษณะดังนี้

Kotlin

    private const val REQUEST_LOCATION_PERMISSION_CODE = 2
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED) {
        // Check Permissions Now
        if ActivityCompat.shouldShowRequestPermissionRationale(
            this,
            Manifest.permission.ACCESS_FINE_LOCATION
        ) {
            // Display UI and wait for user interaction
        } else {
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                REQUEST_LOCATION_PERMISSION_CODE)
        }
    } else {
        // Permission has already been granted, continue as usual
        val locationResult: Task = LocationServices
            .getFusedLocationProviderClient(this /* Context */)
            .lastLocation
    }

Java

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED) {
        // Check Permissions Now
        private static final int REQUEST_LOCATION_PERMISSION_CODE = 2;
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.ACCESS_FINE_LOCATION)) {
            // Display UI and wait for user interaction
        } else {
            ActivityCompat.requestPermissions(
                this, new String[]{Manifest.permission.LOCATION_FINE},
                REQUEST_LOCATION_PERMISSION_CODE);
        }
    } else {
        // permission has been granted, continue as usual
        Task locationResult = LocationServices
            .getFusedLocationProviderClient(this /** Context */)
            .getLastLocation();
    }

การเรียก API ของบริการ Google Play จะแสดงกล่องโต้ตอบโดยอัตโนมัติ (หากมีการสร้างอินสแตนซ์ไคลเอ็นต์ด้วย Activity) หรือการแจ้งเตือนในถาดระบบ (หากมีการสร้างอินสแตนซ์ไคลเอ็นต์ด้วย Context) ซึ่งผู้ใช้สามารถแตะเพื่อเริ่ม Intent การแก้ปัญหาการให้สิทธิ์ได้ ระบบจะจัดคิวการโทรและลองอีกครั้งเมื่อได้รับ สิทธิ์