Poproś o uprawnienia czasu działania

Każda aplikacja na Androida działa w piaskownicy z ograniczonym dostępem. Jeśli Twoja aplikacja musi korzystać z zasobów lub informacji poza własnym piaskownicy, możesz zadeklarować uprawnienie do użycia na czas działania i skonfigurować prośbę o uprawnienia, która zapewnia ten dostęp. Te czynności są częścią procesu korzystania z uprawnień.

Jeśli zadeklarujesz jakiekolwiek niebezpieczne uprawnienia, a 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 deklarujesz żadnych niebezpiecznych uprawnień lub aplikacja jest zainstalowana na urządzeniu z Androidem w wersji 5.1 (poziom interfejsu API 22) lub starszej, uprawnienia są przyznawane automatycznie i nie musisz wykonywać pozostałych czynności opisanych na tej stronie.

Zasady podstawowe

Podstawowe zasady dotyczące wysyłania próśb o przyznanie uprawnień w czasie działania są następujące:

  • Proś o pozwolenie w kontekście, gdy użytkownik zacznie korzystać z funkcji, która go wymaga.
  • Nie blokuj użytkownika. Zawsze udostępniaj opcję anulowania ścieżki edukacyjnej w interfejsie użytkownika, np. ścieżki, która wyjaśnia, dlaczego aplikacja prosi o przyznanie uprawnień.
  • Jeśli użytkownik nie wyrazi zgody na uprawnienia wymagane przez daną funkcję lub wycofa udzieloną zgodę, przeprowadź łagodną degradację aplikacji, jednocześnie umożliwiając użytkownikowi dalsze korzystanie z niej. Możesz 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ń pomaga systemowi ograniczyć liczbę okien dialogowych systemu wyświetlanych użytkownikowi, gdy aplikacja prosi o powiązane ze sobą uprawnienia.

Proces dotyczący prośby o uprawnienia

Zanim zadeklarujesz uprawnienia w aplikacji i poprosisz o uprawnienia w czasie działania, zdecyduj, czy Twoja aplikacja ich potrzebuje. Możesz realizować wiele przypadków użycia w aplikacji, takich jak robienie zdjęć, wstrzymywanie odtwarzania multimediów i wyświetlanie odpowiednich reklam, bez konieczności deklarowania jakichkolwiek 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 użytkownika aplikacji tak, aby określone działania w niej były powiązane z konkretnymi uprawnieniami w czasie wykonywania. Poinformuj użytkowników, które działania mogą wymagać od nich udzielenia Twojej aplikacji dostępu do prywatnych danych.
  3. Zaczekaj, aż użytkownik wywoła w aplikacji zadanie lub działanie, które wymaga dostępu do określonych prywatnych danych użytkownika. W tym momencie aplikacja może poprosić o uprawnienia wymagane do uzyskania dostępu do tych danych.
  4. Sprawdź, czy użytkownik przyznał już środowisko wykonawcze wymagane przez Twoją aplikację. Jeśli tak, aplikacja ma dostęp do prywatnych danych użytkownika. Jeśli nie, przejdź do następnego.

    Za każdym razem, gdy wykonujesz działanie wymagające uprawnienia, musisz sprawdzić, czy je masz.

  5. Sprawdź, czy aplikacja powinna uzasadnić, wyjaśniając, dlaczego aplikacja wymaga przyznania określonego uprawnienia w czasie działania aplikacji. Jeśli system uzna, że Twoja aplikacja nie powinna wyświetlać uzasadnienia, przejdź bezpośrednio do następnego kroku, nie wyświetlając elementu interfejsu.

    Jeśli jednak system ustali, że aplikacja powinna podać uzasadnienie, podaj je użytkownikowi w elemencie interfejsu. W tej części uzasadnienia wyjaśnij, do jakich danych ma dostęp Twoja aplikacja i jakie korzyści może ona przynieść użytkownikowi, jeśli ten przyzna uprawnienia w czasie działania. Gdy użytkownik zaakceptuje 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 aplikacji nie przyznano już uprawnień

Aby sprawdzić, czy użytkownik zezwolił na dostęp do określonych danych, prześlij te dane do metody ContextCompat.checkSelfPermission(). Ta metoda zwraca wartość PERMISSION_GRANTED lub PERMISSION_DENIED, w zależności od tego, czy aplikacja ma uprawnienia.

Wyjaśnij, dlaczego Twoja aplikacja potrzebuje tego uprawnienia

Okno z uprawnieniami wyświetlane przez system podczas wywołania requestPermissions() informuje o tym, jakie uprawnienia potrzebuje aplikacja, ale nie podaje powodu. W niektórych przypadkach może to być dla użytkownika zaskakujące. 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 używasz tylko części wywołań interfejsu API należących do grupy uprawnień, warto wyraźnie określić, 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.

W pewnych okolicznościach warto też informować użytkowników o dostępie do danych wrażliwych w czasie rzeczywistym. 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 przyznanie uprawnień, aby coś działało w aplikacji, ale użytkownik nie rozumie powodu, dla którego potrzebujesz tych uprawnień, znajdź sposób na poinformowanie go o tym.

Jeśli metoda ContextCompat.checkSelfPermission() zwraca PERMISSION_DENIED, wywołaj shouldShowRequestPermissionRationale(). Jeśli ta metoda zwraca wartość true, wyświetl użytkownikowi instrukcje. W tym interfejsie opisz, dlaczego funkcja, którą chce włączyć użytkownik, wymaga określonego uprawnienia.

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

Prośba o uprawnienia

Gdy użytkownik wyświetli interfejs edukacyjny lub gdy wartość zwracana przez shouldShowRequestPermissionRationale() wskazuje, że nie musisz wyświetlać interfejsu edukacyjnego, poproś o pozwolenie. Użytkownicy widzą okno z uprawnieniami systemowymi, w którym mogą zdecydować, czy udzielić aplikacji określonego uprawnienia.

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 kontraktu RequestPermission upraszcza logikę, dlatego jest to zalecane rozwiązanie, jeśli 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 żądaniem uprawnień, dodaj w pliku build.gradle modułu te zależności:

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

Poniżej znajdziesz instrukcje korzystania z umowy RequestPermission. Proces jest prawie taki sam w przypadku umowy RequestMultiplePermissions.

  1. W logice inicjalizacji aktywności lub fragmentu prześlij implementację ActivityResultCallback do wywołania registerForActivityResult(). ActivityResultCallback określa, jak aplikacja ma reagować na odpowiedź użytkownika na prośbę o przyznanie uprawnień.

    Zachowaj odwołanie do wartości zwracanej przez funkcję registerForActivityResult(), która jest typu ActivityResultLauncher.

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

    Po wywołaniu funkcji launch() wyświetla się okno uprawnień systemowych. Gdy użytkownik dokona wyboru, system asynchronicznie wywoła implementację ActivityResultCallback zdefiniowaną w poprzednim kroku.

    Uwaga: aplikacja nie może dostosować okna dialogowego, 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 mogli łatwiej zrozumieć, dlaczego funkcja aplikacji wymaga określonych uprawnień. Możesz na przykład zmienić tekst przycisku, który włącza daną funkcję.

    Ponadto tekst w oknie uprawnień systemowych odnosi się do grupy uprawnień powiązanej z uprawnieniem, którego dotyczy Twoje żądanie. Ta grupowanie uprawnień zostało zaprojektowane z myślą o łatwości obsługi systemu, a Twoja aplikacja nie powinna polegać na tym, że uprawnienia znajdują się w określonej 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 pokazuje zalecany proces sprawdzania uprawnień i w razie potrzeby prośby o ich przyznanie przez 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 zezwalać systemowi na zarządzanie kodem prośby o uprawnienia, możesz samodzielnie zarządzać kodem prośby o uprawnienia. Aby to zrobić, dodaj kod prośby do rozmowy z requestPermissions().

Ten fragment kodu pokazuje, jak poprosić o przyznanie 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 odpowiedź użytkownika na okno z prośbą o uprawnienia, a także zdefiniowany przez Ciebie kod żądania, jak w tym fragmencie 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.
    }
}

Prośba 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ń. Jedną z ważnych różnic w przypadku uprawnień dotyczących lokalizacji jest to, że system obejmuje wiele uprawnień związanych z lokalizacją. Wymagania dotyczące lokalizacji i sposób ich zgłaszania zależą od wymagań dotyczących lokalizacji w przypadku danego przypadku użycia aplikacji.

Lokalizacja na pierwszym planie

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

  • W aplikacji do nawigacji funkcja ta umożliwia użytkownikom wyświetlanie szczegółowych wskazówek dojazdu.
  • W aplikacji do obsługi wiadomości funkcja umożliwia użytkownikom udostępnianie bieżącej lokalizacji innemu użytkownikowi.

System uznaje, że aplikacja używa lokalizacji na pierwszym planie, jeśli jej funkcja uzyskuje dostęp do bieżącej lokalizacji urządzenia w jednym z tych przypadków:

  • Widoczna jest aktywność należąca do Twojej aplikacji.
  • Aplikacja uruchamia usługę na pierwszym planie. Gdy usługa na pierwszym planie jest uruchomiona, system informuje o tym użytkownika, wyświetlając stałe powiadomienie. Aplikacja zachowuje dostęp, gdy jest uruchomiona w tle, np. gdy użytkownik naciśnie przycisk ekranu głównego na urządzeniu lub wyłączy jego wyświetlacz.

    W przypadku Androida 10 (poziom interfejsu API 29) i wyższych należy zadeklarować typ usługi na pierwszym planie location, jak pokazano w tym fragmencie kodu. W wersjach Androida wyższych niż 14 zadeklaruj ten typ 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 API do tworzenia geoogrodzenia. Oto kilka przykładów:

  • Funkcja dostępna w aplikacji do udostępniania lokalizacji w grupie rodzinnej pozwala użytkownikom na bieżąco udostępniać lokalizację członkom grupy rodzinnej.
  • W aplikacji IoT funkcja umożliwia użytkownikom konfigurowanie urządzeń domowych w taki sposób, aby wyłączały się, gdy użytkownik wyjdzie z domu, i włączały się, gdy wróci.

System uznaje, że aplikacja korzysta z lokalizacji w tle, jeśli uzyskuje dostęp do bieżącej lokalizacji urządzenia w sytuacji innej niż opisana w sekcji Lokalizacja na pierwszym planie. Dokładność lokalizacji w tle jest taka sama jak dokładność lokalizacji na pierwszym planie, która zależy od deklarowanych przez aplikację uprawnień dostępu do lokalizacji.

W przypadku Androida w wersji 10 (poziom interfejsu API 29) lub nowszej musisz zadeklarować uprawnienie ACCESS_BACKGROUND_LOCATION w pliku manifestu aplikacji, aby móc w czasie działania poprosić o dostęp do lokalizacji w tle. W starszych wersjach Androida, gdy aplikacja uzyska dostęp do lokalizacji na pierwszym planie, automatycznie uzyska też dostęp do lokalizacji w tle.

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

Odmowa przyznania uprawnień

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

  • Zwracaj uwagę użytkownika. Wyróżnij konkretny element interfejsu aplikacji, w którym funkcje są ograniczone z powodu braku wymaganych uprawnień. Przykłady działań, które możesz wykonać:

    • wyświetlać komunikat w miejscu, w którym powinny być widoczne wyniki lub dane funkcji;
    • wyświetlać 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 wymaganych uprawnień.

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

Jednocześnie aplikacja powinna respektować decyzję użytkownika o odmowie udzielenia uprawnień. Od Androida 11 (poziom interfejsu API 30) jeśli użytkownik więcej niż raz podczas instalacji aplikacji na urządzeniu kliknie Odrzuć w przypadku określonego uprawnienia, nie zobaczy okna uprawnień systemowych, jeśli aplikacja ponownie poprosi o to uprawnienie. Działania użytkownika wskazują, że nie chce, abyśmy pytali ponownie. W poprzednich wersjach użytkownicy widzieli okno uprawnień systemowych za każdym razem, gdy aplikacja prosiła o uprawnienia, chyba że wcześniej zaznaczyli pole wyboru „Nie pytaj ponownie”.

Jeśli użytkownik odrzuci prośbę o przyznanie uprawnień więcej niż raz, będzie to traktowane jako trwała odmowa. Bardzo ważne jest, aby prosić użytkowników o przyznanie uprawnień tylko wtedy, gdy potrzebują dostępu do konkretnej funkcji. W przeciwnym razie możesz przypadkowo utracić możliwość ponownego wysłania prośby o przyznanie uprawnień.

W niektórych sytuacjach zgoda może zostać odrzucona automatycznie, bez udziału użytkownika. (uprawnienia mogą być też przyznawane automatycznie). Nie należy zakładać niczego na temat automatycznego zachowania. Za każdym razem, gdy aplikacja potrzebuje dostępu do funkcji wymagającej uprawnienia, sprawdź, czy nadal masz przyznane to uprawnienie.

Aby zapewnić użytkownikom jak najlepsze wrażenia podczas prośby o uprawnienia aplikacji, zapoznaj się też ze sprawdzonymi metodami dotyczącymi uprawnień aplikacji.

Sprawdzanie stanu odmowy podczas testowania i debugowania

Aby sprawdzić, czy uprawnienia zostały trwale odrzucone (na potrzeby debugowania i testowania), użyj tego polecenia:

adb shell dumpsys package PACKAGE_NAME

Gdzie PACKAGE_NAME to nazwa pakietu do sprawdzenia.

Dane wyjściowe polecenia zawierają sekcje o takim wyglądzie:

...
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 odrzucił, są oznaczone ikoną USER_SET. Uprawnienia, które zostały trwale odrzucone po dwukrotnym wybraniu opcji Odrzuć, są oznaczone ikoną USER_FIXED.

Aby mieć pewność, że podczas testowania testerzy zobaczą okno z prośbą, zresetuj te flagi, gdy skończysz debugowanie aplikacji. 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ć.

Pełną listę uprawnień aplikacji na Androida znajdziesz na stronie z dokumentacją interfejsu API uprawnień.

Jednorazowe uprawnienia

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

Od Androida 11 (poziom API 30) za każdym razem, gdy aplikacja prosi o uprawnienia związane z lokalizacją, mikrofonem lub aparatem, wyświetlany użytkownikowi dialog uprawnień zawiera opcję Tylko tym razem, jak pokazano na rysunku 2. Jeśli użytkownik wybierze tę opcję w oknie dialogowym, Twoja aplikacja otrzyma tymczasowe jednorazowe uprawnienie.

Aplikacja może mieć dostęp do powiązanych danych przez okres czasu, który zależy od zachowania aplikacji i działań użytkownika:

  • Podczas gdy aktywność aplikacji jest widoczna, aplikacja może uzyskać dostęp do danych.
  • Jeśli użytkownik przeniesie aplikację na drugi plan, będzie ona 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ę, gdy uprawnienia zostaną cofnięte

Jeśli użytkownik cofnie jednorazowe uprawnienia, np. w ustawieniach systemu, Twoja aplikacja nie będzie mieć dostępu do danych, niezależnie od tego, czy uruchomisz usługę na pierwszym planie. Jeśli użytkownik wycofa jednorazowe uprawnienia aplikacji, proces aplikacji zostanie zakończony.

Gdy użytkownik otworzy aplikację, a jej funkcja będzie wymagać dostępu do lokalizacji, mikrofonu lub kamery, ponownie wyświetli się prośba o uprawnienia.

Zresetuj nieużywane uprawnienia

Android udostępnia kilka sposobów na przywrócenie domyślnego stanu odmowy nieużywanych uprawnień w czasie działania:

Usuwanie dostępu 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. Podczas aktualizowania aplikacji wykonaj ten krok, aby użytkownicy lepiej rozumieli, dlaczego aplikacja nadal prosi o określone uprawnienia. Dzięki temu zyskasz zaufanie użytkowników.

Aby usunąć dostęp do uprawnienia w czasie wykonywania, przekaż nazwę tego uprawnienia 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 zatrzymuje wszystkie procesy powiązane z identyfikatorem UID 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 aplikacja nie wymaga już dostępu do określonych uprawnień w czasie działania, wyświetl okno dialogowe, gdy użytkownik uruchomi aplikację. Okno może 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ś o ustawienie domyślnego modułu obsługi

Niektóre aplikacje wymagają dostępu do poufnych informacji użytkownika związanych z rejestrami połączeń i SMS-ami. Jeśli chcesz poprosić o uprawnienia dotyczące rejestru połączeń i SMS-ów oraz opublikować aplikację w Google Play, musisz poprosić użytkownika o ustawienie aplikacji jako domyślnego modułu obsługi głównej funkcji systemu, zanim poprosisz o uprawnienia w czasie działania.

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

Przyznaj wszystkie uprawnienia czasu działania na potrzeby testowania

Aby automatycznie przyznać wszystkie uprawnienia w czasie wykonywania podczas instalowania aplikacji na emulatorze lub urządzeniu testowym, użyj opcji -g w przypadku polecenia adb shell install, jak pokazano w tym fragmencie kodu:

adb shell install -g PATH_TO_APK_FILE

Dodatkowe materiały

Aby dowiedzieć się więcej o uprawnieniach, przeczytaj te artykuły:

Aby dowiedzieć się więcej o prośbach o uprawnienia, zapoznaj się z przykładami uprawnień.

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