Poproś o uprawnienia czasu działania

Każda aplikacja na Androida działa w piaskownicy o ograniczonym dostępie. Jeśli Twoja aplikacja musi używać zasobów lub informacji poza własną piaskownicą, możesz zadeklarować uprawnienia czasu działania i skonfigurować prośbę o przyznanie takiego dostępu. Te kroki są częścią procesu korzystania z uprawnień.

Jeśli zadeklarujesz niebezpieczne uprawnienia i Twoja aplikacja jest zainstalowana na urządzeniu z Androidem 6.0 (poziom interfejsu API 23) lub nowszym, musisz poprosić o niebezpieczne uprawnienia w czasie działania, wykonując czynności opisane w tym przewodniku.

Jeśli nie zadeklarujesz żadnych niebezpiecznych uprawnień lub jeśli Twoja aplikacja jest zainstalowana na urządzeniu z Androidem 5.1 (poziom interfejsu API 22) lub starszym, uprawnienia zostaną przyznane automatycznie i nie musisz wykonywać żadnych pozostałych czynności na tej stronie.

Podstawowe zasady

Podstawowe zasady żądania uprawnień w czasie działania są następujące:

  • Poproś o uprawnienie w kontekście, gdy użytkownik zacznie korzystać z funkcji, która go wymaga.
  • Nie blokuj użytkownika. Zawsze udostępniaj opcję anulowania edukacyjnego przepływu w interfejsie, np. procesu, który wyjaśnia uzasadnienie prośby o uprawnienia.
  • Jeśli użytkownik odmówi przyznania uprawnienia, którego potrzebuje funkcja, lub wycofaj takie uprawnienia, płynnie uporządkuj aplikację, aby użytkownik mógł nadal z niej korzystać. Spróbuj na przykład wyłączyć funkcję, która wymaga tych uprawnień.
  • Nie zakładaj żadnego działania systemu. Nie zakładaj na przykład, że uprawnienia znajdują się w tej samej grupie uprawnień. Grupa uprawnień po prostu pomaga systemowi zminimalizować liczbę okien dialogowych wyświetlanych użytkownikowi, gdy aplikacja prosi o ściśle powiązane uprawnienia.

Przepływ pracy związany z żądaniem uprawnień

Zanim zadeklarujesz uprawnienia w czasie działania i poprosić o uprawnienia w czasie działania, sprawdź, czy aplikacja jest do tego potrzebna. Możesz w niej wykonywać wiele przypadków użycia, takich jak robienie zdjęć, wstrzymywanie odtwarzania multimediów i wyświetlanie odpowiednich reklam bez konieczności deklarowania uprawnień.

Jeśli stwierdzisz, że aplikacja musi zadeklarować uprawnienia w czasie działania i poprosić o uprawnienia w czasie działania, wykonaj te czynności:

  1. W pliku manifestu aplikacji zadeklaruj uprawnienia, których może ona żądać.
  2. Zaprojektuj interfejs aplikacji w taki sposób, aby konkretne działania w aplikacji były powiązane z określonymi uprawnieniami w czasie działania. Poinformuj użytkowników, które działania mogą wymagać przyznania aplikacji uprawnień dostępu do ich prywatnych danych.
  3. Poczekaj, aż użytkownik wywoła w Twojej aplikacji działanie, które wymaga dostępu do określonych prywatnych danych użytkownika. Wtedy aplikacja może poprosić o uprawnienia w czasie działania wymagane do uzyskania dostępu do tych danych.
  4. Sprawdź, czy użytkownik przyznał już środowisko wykonawcze wymagane przez Twoją aplikację. Aplikacja ma wtedy dostęp do prywatnych danych użytkownika. Jeśli nie, przejdź do następnego.

    Musisz sprawdzić, czy masz odpowiednie uprawnienia za każdym razem, gdy wykonujesz operację, która je wymaga.

  5. Sprawdź, czy aplikacja powinna uzasadnić, wyjaśniając, dlaczego aplikacja wymaga przyznania określonego uprawnienia w czasie działania aplikacji. Jeśli system ustali, że aplikacja nie powinna podawać uzasadnienia, przejdź od razu do następnego kroku, bez wyświetlania elementu interfejsu.

    Jeśli jednak system ustali, że aplikacja powinna podać uzasadnienie, podaj je użytkownikowi w elemencie interfejsu. W tym uzasadnieniu wyjaśnij wyraźnie, do jakich danych próbuje uzyskać dostęp aplikacja i jakie korzyści może zapewnić użytkownikowi, jeśli przyzna uprawnienia w czasie działania aplikacji. Gdy użytkownik potwierdzi uzasadnienie, przejdź do następnego kroku.

  6. Poproś o uprawnienia w czasie działania, które są wymagane przez aplikację do uzyskania dostępu do prywatnych danych użytkownika. System wyświetli prośbę o przyznanie uprawnień w czasie działania, np. na stronie przeglądu uprawnień.

  7. Sprawdź odpowiedź użytkownika – czy przyznał on, czy odmówił uprawnienia w czasie działania aplikacji.

  8. Jeśli użytkownik przyznał Twojej aplikacji odpowiednie uprawnienia, możesz uzyskać dostęp do prywatnych danych użytkownika. Jeśli użytkownik odmówił przyznania uprawnień, stopniowo pogorszyj działanie aplikacji, aby udostępniała użytkownikom funkcje bez korzystania z informacji chronionych przez to uprawnienie.

Rysunek 1 przedstawia przepływ pracy i zbiór decyzji związanych z tym procesem:

Rysunek 1. Diagram przedstawiający przepływ pracy deklarowania i wysyłania żądań uprawnień czasu działania w Androidzie.

Sprawdzanie, czy aplikacja otrzymała już to uprawnienie

Aby sprawdzić, czy użytkownik przyznał Twojej aplikacji określone uprawnienie, przekaż je do metody ContextCompat.checkSelfPermission(). Ta metoda zwraca PERMISSION_GRANTED lub PERMISSION_DENIED w zależności od tego, czy aplikacja ma odpowiednie uprawnienia.

Wyjaśnij, dlaczego Twoja aplikacja potrzebuje tych uprawnień

Okno uprawnień wyświetlane przez system po wywołaniu funkcji requestPermissions() zawiera informacje o uprawnieniach, których potrzebuje Twoja aplikacja, ale bez podania przyczyny. W niektórych przypadkach użytkownicy mogą zauważyć łamigłówkę. Zanim wywołasz funkcję requestPermissions(), warto wyjaśnić użytkownikowi, dlaczego Twoja aplikacja potrzebuje uprawnień.

Badania pokazują, że użytkownicy znacznie chętniej otrzymują prośby o przyznanie uprawnień, jeśli wiedzą, do czego są potrzebna aplikacja (np. czy są potrzebne do obsługi głównej funkcji aplikacji lub wyświetlania reklam). Jeśli więc korzystasz tylko z części wywołań interfejsu API należących do grupy uprawnień, warto jawnie wskazać, których uprawnień używasz i dlaczego. Jeśli na przykład używasz tylko przybliżonej lokalizacji, poinformuj o tym użytkownika w opisie aplikacji lub w artykułach pomocy na jej temat.

W pewnych warunkach warto też w czasie rzeczywistym informować użytkowników o dostępie do danych wrażliwych. Gdy na przykład używasz kamery lub mikrofonu, dobrze jest poinformować o tym użytkownika za pomocą ikony powiadomień w aplikacji lub na pasku powiadomień (jeśli aplikacja działa w tle), aby nie wyglądało na to, że gromadzisz dane podejrzanie.

Jeśli musisz poprosić o uprawnienia, aby coś w aplikacji zadziałało, ale powód nie jest jasny dla użytkownika, znajdź sposób, aby poinformować go, dlaczego potrzebujesz najbardziej newralgicznych uprawnień.

Jeśli metoda ContextCompat.checkSelfPermission() zwraca PERMISSION_DENIED, wywołaj shouldShowRequestPermissionRationale(). Jeśli ta metoda zwraca wartość true, wyświetl użytkownikowi interfejs edukacyjny. Opisz w tym interfejsie, dlaczego funkcja, którą użytkownik chce włączyć, wymaga określonych uprawnień.

Jeśli aplikacja prosi o uprawnienia związane z lokalizacją, mikrofonem lub aparatem, warto wyjaśnić, dlaczego potrzebuje dostępu do tych informacji.

Poproś o uprawnienia

Gdy użytkownik wyświetli interfejs edukacyjny lub zwracana wartość shouldShowRequestPermissionRationale() wskazuje, że nie musisz wyświetlać interfejsu edukacyjnego, poproś o odpowiednie uprawnienia. Użytkownicy widzą okno uprawnień systemu, w którym mogą wybrać, czy przyznać aplikacji określone uprawnienie.

W tym celu skorzystaj z umowy RequestPermission dostępnej w bibliotece AndroidaX, w której zezwalasz systemowi na zarządzanie kodem prośby o uprawnienia za Ciebie. Korzystanie z umowy RequestPermission upraszcza logikę, dlatego jest to zalecane rozwiązanie, gdy jest to możliwe. W razie potrzeby możesz też samodzielnie zarządzać kodem żądania w ramach prośby o uprawnienia i uwzględnić ten kod w logice wywołania zwrotnego uprawnień.

Zezwalaj systemowi na zarządzanie kodem prośby o uprawnienia

Aby umożliwić systemowi zarządzanie kodem żądania powiązanym z prośbą o uprawnienia, dodaj zależności od tych bibliotek w pliku build.gradle modułu:

Następnie możesz używać jednej z tych klas:

Poniżej znajdziesz instrukcje korzystania z umowy RequestPermission. W przypadku umowy RequestMultiplePermissions proces jest niemal taki sam.

  1. W logice inicjowania aktywności lub fragmentu przekaż implementację ActivityResultCallback do wywołania registerForActivityResult(). ActivityResultCallback określa, w jaki sposób aplikacja postępuje z odpowiedzią użytkownika na prośbę o uprawnienia.

    Zapisz odwołanie do wartości zwróconej przez registerForActivityResult(), która jest typu ActivityResultLauncher.

  2. Aby w razie potrzeby wyświetlić okno uprawnień systemowych, wywołaj metodę launch() w instancji ActivityResultLauncher zapisanej w poprzednim kroku.

    Po wywołaniu funkcji launch() pojawi się okno uprawnień systemowych. Gdy użytkownik dokona wyboru, system asynchronicznie wywoła Twoją implementację ActivityResultCallback, którą zdefiniowano w poprzednim kroku.

    Uwaga: aplikacja nie może dostosować okna, które pojawia się po wywołaniu funkcji launch(). Aby podać użytkownikowi więcej informacji lub kontekst, zmień interfejs aplikacji tak, aby użytkownicy wiedzieli, dlaczego dana funkcja wymaga określonych uprawnień. Możesz na przykład zmienić tekst na przycisku, który włącza tę funkcję.

    Poza tym tekst w oknie uprawnień systemu odwołuje się do grupy uprawnień powiązanej z żądanym uprawnieniem. To grupowanie uprawnień jest zaprojektowane z myślą o łatwości obsługi systemu. Aplikacja nie powinna korzystać z uprawnień znajdujących się w konkretnej grupie uprawnień lub poza nią.

Ten fragment kodu pokazuje, jak obsługiwać odpowiedź dotyczącą uprawnień:

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

Ten fragment kodu ilustruje zalecany proces sprawdzania uprawnień, a w razie potrzeby proszenia o nie do użytkownika:

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

Samodzielne zarządzanie kodem prośby o uprawnienia

Zamiast zezwalania systemowi na zarządzanie kodem prośby o uprawnienia możesz samodzielnie zarządzać kodem prośby o uprawnienia. Aby to zrobić, umieść kod żądania w wywołaniu funkcji requestPermissions().

Ten fragment kodu pokazuje, jak poprosić o uprawnienia za pomocą kodu żądania:

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

Gdy użytkownik odpowie w oknie uprawnień systemowych, system wywoła implementację onRequestPermissionsResult() w aplikacji. System przekazuje w odpowiedzi użytkownika do okna uprawnień, a także zdefiniowany przez Ciebie kod żądania, zgodnie z tym fragmentem kodu:

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

Poproś o dostęp do lokalizacji

Gdy prosisz o dostęp do lokalizacji, postępuj zgodnie z tymi samymi sprawdzonymi metodami co w przypadku innych uprawnień środowiska wykonawczego. Ważna różnica dotycząca dostępu do lokalizacji polega na tym, że system obejmuje wiele uprawnień związanych z lokalizacją. To, które uprawnienia chcesz uzyskać i w jaki sposób o nie prosisz, zależą od wymagań dotyczących lokalizacji w danym przypadku użycia aplikacji.

Lokalizacja na pierwszym planie

Jeśli aplikacja zawiera funkcję, która udostępnia lub odbiera informacje o lokalizacji tylko raz lub przez określony czas, wymaga ona dostępu do lokalizacji na pierwszym planie. Oto kilka przykładów:

  • Funkcja w aplikacji do nawigacji umożliwia użytkownikom otrzymywanie szczegółowych wskazówek dojazdu.
  • W aplikacji do obsługi wiadomości funkcja pozwala użytkownikom udostępniać bieżącą lokalizację innemu użytkownikowi.

System uznaje aplikację za używaną na pierwszym planie, jeśli jakaś funkcja uzyskuje dostęp do bieżącej lokalizacji urządzenia w jednej z tych sytuacji:

  • Widoczna jest aktywność należąca do Twojej aplikacji.
  • Twoja aplikacja działa na pierwszym planie. Gdy usługa na pierwszym planie jest uruchomiona, system informuje użytkowników o tym, wyświetlając trwałe powiadomienie. Aplikacja zachowuje dostęp, gdy jest działająca w tle, na przykład gdy użytkownik naciśnie przycisk ekranu głównego na urządzeniu lub wyłączy wyświetlacz.

    W Androidzie 10 (poziom interfejsu API 29) i nowszych musisz zadeklarować typ usługi na pierwszym planie o wartości location, jak pokazano w poniższym fragmencie kodu. We wcześniejszych wersjach Androida zalecamy zadeklarowanie tego typu usługi na pierwszym planie.

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

Deklarujesz potrzebę dostępu do lokalizacji na pierwszym planie, gdy Twoja aplikacja prosi o uprawnienie ACCESS_COARSE_LOCATION lub ACCESS_FINE_LOCATION, jak pokazano w tym fragmencie:

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

Lokalizacja w tle

Aplikacja wymaga dostępu do lokalizacji w tle, jeśli jej funkcja stale udostępnia lokalizację innym użytkownikom lub korzysta z interfejsu Geofencing API. Oto kilka przykładów:

  • Funkcja dostępna w aplikacji do udostępniania lokalizacji w grupie rodzinnej pozwala użytkownikom stale udostępniać lokalizację członkom grupy rodzinnej.
  • Funkcja w aplikacji IoT umożliwia użytkownikom skonfigurowanie urządzeń domowych w taki sposób, że wyłączają się, gdy użytkownik wychodzi z domu, i włączają ponownie, gdy użytkownik wraca do domu.

System uznaje, że aplikacja używa lokalizacji w tle, jeśli uzyskuje dostęp do bieżącej lokalizacji urządzenia w sytuacjach innych niż opisane w sekcji dotyczącej lokalizacji na pierwszym planie. Dokładność lokalizacji w tle jest taka sama jak dokładność lokalizacji na pierwszym planie, która zależy od zadeklarowanych przez aplikację uprawnień do lokalizacji.

W Androidzie 10 (poziom interfejsu API 29) i nowszych musisz zadeklarować uprawnienie ACCESS_BACKGROUND_LOCATION w pliku manifestu aplikacji, aby w czasie działania aplikacji prosić o dostęp do lokalizacji w tle. We wcześniejszych wersjach Androida aplikacja automatycznie uzyskuje również dostęp do lokalizacji w tle, gdy otrzymuje dostęp do lokalizacji na pierwszym planie.

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

Obsługa odmowy uprawnień

Jeśli użytkownik odmówi przyznania uprawnień, aplikacja powinna pomagać użytkownikom w zrozumieniu konsekwencji odmowy przyznania uprawnień. W szczególności aplikacja powinna informować użytkowników o funkcjach, które nie działają z powodu braku uprawnień. Podczas wykonywania tych czynności pamiętaj o tych sprawdzonych metodach:

  • Kieruj uwagę użytkownika. Wyróżnij część interfejsu aplikacji, która ma ograniczoną funkcjonalność, ponieważ aplikacja nie ma wymaganych uprawnień. Oto co możesz zrobić:

    • Pokaż komunikat, w którym pojawiły się wyniki lub dane obiektu.
    • Wyświetl inny przycisk z ikoną i kolorem błędu.
  • Unikaj ogólników. Nie wyświetlaj ogólnego komunikatu. Zamiast tego wyjaśnij, które funkcje są niedostępne, ponieważ aplikacja nie ma odpowiednich uprawnień.

  • Nie blokuj interfejsu użytkownika. Inaczej mówiąc, nie wyświetlaj na pełnym ekranie komunikatu z ostrzeżeniem, który uniemożliwia użytkownikom dalsze korzystanie z Twojej aplikacji.

Jednocześnie aplikacja powinna uwzględniać decyzję użytkownika o odmowie przyznania uprawnień. Począwszy od Androida 11 (poziom interfejsu API 30), jeśli użytkownik kliknie Odmów, aby otrzymać określone uprawnienie więcej niż raz w trakcie instalacji aplikacji na urządzeniu, nie zobaczy okna uprawnień systemowych, jeśli aplikacja ponownie poprosi o takie uprawnienia. Działanie użytkownika oznacza „nie pytaj ponownie”. W poprzednich wersjach użytkownicy widzieli okno uprawnień systemowych za każdym razem, gdy Twoja aplikacja prosiła o dane uprawnienie, chyba że zaznaczyli wcześniej pole lub opcję „Nie pytaj ponownie”.

Jeśli użytkownik kilka razy odmówi przyznania uprawnień, uznaje się to za trwałą odmowę. Pamiętaj, aby prosić użytkowników o uprawnienia tylko wtedy, gdy potrzebują dostępu do określonej funkcji. W przeciwnym razie możesz przypadkiem utracić możliwość ponownego wysyłania prośby o uprawnienia.

W niektórych sytuacjach dostęp może zostać zablokowany automatycznie, ale użytkownik nie podejmie żadnych działań. Uprawnienie może też zostać uznane automatycznie. Nie należy zakładać niczego w zachowaniu automatycznym. Za każdym razem, gdy aplikacja potrzebuje dostępu do funkcji, która wymaga uprawnień, sprawdź, czy aplikacja nadal je otrzymuje.

Zapoznaj się też ze sprawdzonymi metodami dotyczącymi uprawnień aplikacji, aby zapewnić użytkownikom najlepsze wrażenia.

Sprawdź stan odmowy podczas testowania i debugowania

Aby sprawdzić, czy aplikacja otrzymała trwałą odmowę uprawnień (na potrzeby debugowania i testowania), użyj tego polecenia:

adb shell dumpsys package PACKAGE_NAME

Gdzie PACKAGE_NAME to nazwa pakietu do sprawdzenia.

Wynik polecenia zawiera sekcje podobne do tych:

...
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]
...

Uprawnienia, które użytkownik odmówił raz, mają oznaczenie USER_SET. Uprawnienia, które zostały trwale odrzucone przez dwukrotny wybór Odmów, są oznaczone przez USER_FIXED.

Aby mieć pewność, że testerzy zobaczą okno żądania podczas testowania, po zakończeniu debugowania aplikacji zresetuj te flagi. Aby to zrobić, użyj polecenia:

adb shell pm clear-permission-flags PACKAGE_NAME PERMISSION_NAME user-set user-fixed

PERMISSION_NAME to nazwa uprawnienia, które chcesz zresetować.

Aby zobaczyć pełną listę uprawnień aplikacji na Androida, otwórz stronę z informacjami o uprawnieniach interfejsu API.

Jednorazowe zezwolenia

Opcja „Tylko tym razem” to drugi z 3 przycisków w oknie.
Rysunek 2. Okno systemowe, które pojawia się, gdy aplikacja poprosi o jednorazowe uprawnienia.

Począwszy od Androida 11 (poziom interfejsu API 30), za każdym razem, gdy aplikacja prosi o uprawnienia związane z lokalizacją, mikrofonem lub aparatem, okno uprawnień widoczne dla użytkownika zawiera opcję Tylko tym razem, jak widać na rysunku 2. Jeśli użytkownik wybierze tę opcję w oknie, aplikacja otrzyma tymczasowe uprawnienia jednorazowe.

Aplikacja ma wtedy dostęp do powiązanych danych przez czas zależny od zachowania aplikacji i działań użytkownika:

  • Aktywność w aplikacji jest widoczna, ale aplikacja ma dostęp do danych.
  • Jeśli użytkownik prześle aplikację do działania w tle, aplikacja może mieć dostęp do danych przez krótki czas.
  • Jeśli uruchomisz usługę na pierwszym planie, gdy aktywność jest widoczna, a użytkownik przeniesie aplikację w tle, aplikacja będzie miała dostęp do danych do momentu, aż usługa na pierwszym planie przestanie działać.

Proces aplikacji kończy się po anulowaniu uprawnień

Jeśli użytkownik cofnie jednorazowe uprawnienie, np. w ustawieniach systemu, aplikacja nie będzie miała dostępu do danych niezależnie od tego, czy uruchomiono usługę na pierwszym planie. Tak jak w przypadku każdego uprawnienia, jeśli użytkownik anuluje jednorazowe uprawnienie aplikacji, proces aplikacji się zakończy.

Gdy następnym razem użytkownik otworzy aplikację i jakaś funkcja poprosi o dostęp do lokalizacji, mikrofonu lub aparatu, ponownie wyświetli mu się prośba o pozwolenie.

Zresetuj nieużywane uprawnienia

Android udostępnia kilka sposobów na zresetowanie nieużywanych uprawnień czasu działania do ich domyślnego stanu (odrzuconego):

Usuń dostęp aplikacji

Na Androidzie 13 (poziom interfejsu API 33) i nowszych możesz usunąć dostęp aplikacji do uprawnień czasu działania, których już nie wymaga. Gdy zaktualizujesz aplikację, wykonaj ten krok, by użytkownicy mogli lepiej zrozumieć, dlaczego Twoja aplikacja nadal prosi o określone uprawnienia. Wiedza ta pomaga budować zaufanie użytkowników do Twojej aplikacji.

Aby usunąć dostęp do uprawnienia w czasie działania, przekaż jego nazwę do revokeSelfPermissionOnKill(). Aby jednocześnie usunąć dostęp do grupy uprawnień w czasie działania aplikacji, przekaż zbiór nazw uprawnień do usługi revokeSelfPermissionsOnKill(). Proces usuwania uprawnień odbywa się asynchronicznie i kończy wszystkie procesy powiązane z identyfikatorem UID Twojej aplikacji.

Aby system usunął dostęp aplikacji do uprawnień, wszystkie powiązane z nią procesy muszą zostać przerwane. Po wywołaniu interfejsu API system określa, kiedy można bezpiecznie zakończyć te procesy. Zazwyczaj system czeka, aż aplikacja spędzi dłuższy czas w tle, a nie na pierwszym planie.

Aby poinformować użytkownika, że Twoja aplikacja nie wymaga już dostępu do określonych uprawnień w czasie działania, przy następnym uruchomieniu aplikacji wyświetl okno. Może ono zawierać listę uprawnień.

Automatyczne resetowanie uprawnień nieużywanych aplikacji

Jeśli Twoja aplikacja jest kierowana na Androida 11 (poziom interfejsu API 30) lub nowszego i nie jest używana przez kilka miesięcy, system chroni dane użytkownika, automatycznie resetując poufne uprawnienia czasu działania przyznane aplikacji. Więcej informacji znajdziesz w przewodniku o hibernacji aplikacji.

W razie potrzeby poproś, aby została domyślnym modułem obsługi

Niektóre aplikacje potrzebują dostępu do poufnych danych użytkownika związanych z rejestrami połączeń i SMS-ami. Jeśli chcesz poprosić o uprawnienia dotyczące rejestrów połączeń i SMS-ów oraz opublikować aplikację w Sklepie Play, poproś użytkownika o ustawienie aplikacji jako domyślnego modułu obsługi podstawowej funkcji systemu, zanim poprosi o te uprawnienia w czasie działania.

Więcej informacji o domyślnych modułach obsługi, w tym wskazówki na temat wyświetlania użytkownikom promptów domyślnego modułu obsługi, znajdziesz w przewodniku na temat uprawnień używanych tylko w domyślnych modułach obsługi.

Przyznaj wszystkie uprawnienia czasu działania na potrzeby testowania

Aby automatycznie przyznawać wszystkie uprawnienia czasu działania podczas instalowania aplikacji w emulatorze lub na urządzeniu testowym, użyj opcji -g dla polecenia adb shell install, jak pokazano w tym fragmencie kodu:

adb shell install -g PATH_TO_APK_FILE

Dodatkowe materiały

Dodatkowe informacje o uprawnieniach znajdziesz w tych artykułach:

Więcej informacji o wysyłaniu próśb o uprawnienia znajdziesz w przykładach uprawnień.

Możesz też wykonać to ćwiczenie z programowania, które pokazuje sprawdzone metody ochrony prywatności.