Usługi Google Play i uprawnienia w czasie wykonywania

Od Androida 6.0 Marshmallow system używa modelu uprawnień, który usprawnia proces instalowania aplikacji i automatycznego aktualizowania. Uprawnienia są wymagane w czasie działania, a nie przed instalacją aplikacji. Dodatkowo użytkownicy mogą odmówić udzielenia określonych uprawnień. Aby zapewnić użytkownikom taką elastyczność, musisz się upewnić, że aplikacja działa zgodnie z oczekiwaniami, gdy użytkownik włączy lub wyłączy określone uprawnienie.

Usługi Google Play mają uprawnienia w czasie działania, które użytkownicy mogą odrzucać niezależnie od uprawnień, o które prosi aplikacja. Usługi Google Play automatycznie uzyskują wszystkie uprawnienia potrzebne do obsługi interfejsów API. Aplikacja powinna jednak w miarę potrzeby sprawdzać uprawnienia w czasie działania i prosić o nie oraz odpowiednio obsługiwać błędy w przypadku, gdy użytkownik odmówił usługom Google Play uprawnień wymaganych przez interfejs API, którego używa aplikacja.

Dobrą praktyką jest zarządzanie oczekiwaniami użytkownika w ramach ustawiania uprawnień, których może wymagać środowisko uruchomieniowe. Te sprawdzone metody pomogą Ci uniknąć potencjalnych problemów.

Wymagania wstępne

Uprawnienia musisz zadeklarować w pliku AndroidManifest.xml. Na przykład:

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

Wytyczne

Sprawdzanie uprawnień przed wywołaniem interfejsów API

Po zadeklarowaniu interfejsów API, których chcesz używać w pliku AndroidManifest.xml, sprawdź, czy masz wymagane uprawnienia, zanim wywołasz interfejs API. Można to zrobić za pomocą metody checkSelfPermission ActivityCompat lub ContextCompat.

Jeśli wywołanie zwróci wartość false, oznacza to, że uprawnienia nie zostały przyznane. Aby je zażądać, użyj metody requestPermissions. Odpowiedź na to jest zwracana w wywołaniu zwrotnym, które zobaczysz w następnym kroku.

Na przykład:

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();
    }

Zaimplementuj wywołanie zwrotne prośby o zgodę

Jeśli użytkownik nie przyznał aplikacji wymaganych uprawnień, należy wywołać metodę requestPermissions, aby poprosić użytkownika o ich przyznanie. Odpowiedź użytkownika jest rejestrowana w pobraniu onRequestPermissionsResult. Aplikacja powinna to uwzględnić i zawsze sprawdzać wartości zwracane, ponieważ prośba może zostać odrzucona lub anulowana. Możesz też poprosić o kilka uprawnień jednocześnie i je sprawdzić – poniższy przykład sprawdza tylko jedno uprawnienie.

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
            }
        }
    }

Pokaż uzasadnienie dotyczące uprawnień

Jeśli uprawnienia, o które prosi aplikacja, są niezbędne do działania jej głównych funkcji, a użytkownik odmówił wcześniej przyznania uprawnień, aplikacja powinna wyświetlić dodatkowe wyjaśnienie, zanim poprosi o nie ponownie. Użytkownicy chętniej udzielają uprawnień, gdy rozumieją, dlaczego są one potrzebne i jakie korzyści z nich wynikają.

W takim przypadku przed wywołaniem requestPermissions należy wywołać shouldShowRequestPermissionRationale. Jeśli zwróci wartość true, musisz utworzyć interfejs użytkownika, aby wyświetlić dodatkowy kontekst uprawnienia.

Twój kod może wyglądać np. tak:

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();
    }

Wywołania interfejsu API usług Google Play automatycznie wyświetlają okno dialogowe (jeśli klient jest instancją interfejsu Activity) lub powiadomienie na pasku systemowym (jeśli klient jest instancją interfejsu Context), które użytkownik może kliknąć, aby rozpocząć działanie dotyczące rozwiązywania problemów z uprawnieniami. Pozwolenie na dostęp do danych będzie wiązało się z umieszczeniem połączeń w kolejce i ponownym próbowaniem połączenia.