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 żądania uprawnień w czasie działania aplikacji:

  • 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 okna edukacyjnego, np. okna z wyjaśnieniem, 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, że system działa w jakiś określony sposób. Nie zakładaj na przykład, że uprawnienia znajdują się w tej samej grupie uprawnień. Grupa uprawnień pomaga tylko systemowi zminimalizować liczbę okien dialogowych, które są wyświetlane 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, np. robić zdjęcia, wstrzymywać odtwarzanie multimediów i wyświetlać odpowiednie reklamy, bez deklarowania żadnych uprawnień.

Jeśli uznasz, że aplikacja musi deklarować uprawnienia i prosić o nie w czasie działania, wykonaj te czynności:

  1. W pliku manifestu aplikacji zadeklaruj uprawnienia, których może potrzebować.
  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 już przyznał uprawnienia wymagane przez Twoją aplikację. Jeśli tak, aplikacja może uzyskać 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 Twoja aplikacja powinna wyświetlać użytkownikowi uzasadnienie, dlaczego potrzebuje uprawnień w czasie działania. 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 system uzna, że Twoja aplikacja powinna wyświetlić uzasadnienie, pokaż je użytkownikowi w elementach 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. Wyślij prośbę o dostęp do danych, których aplikacja potrzebuje, aby uzyskać dostęp do prywatnych danych użytkownika. System wyświetla monit uprawnień w czasie wykonywania, np. taki jak na stronie podsumowania uprawnień.

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

  8. Jeśli użytkownik przyznał aplikacji uprawnienia, możesz uzyskać dostęp do prywatnych danych użytkownika. Jeśli użytkownik odmówi udzielenia uprawnień, łagodnie ogranicz funkcjonalność aplikacji, aby udostępnić użytkownikowi funkcje bez informacji chronionych przez te uprawnienia.

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

Rysunek 1. Diagram pokazujący proces deklarowania i proszenia o uprawnienia czasu działania na Androidzie.

Sprawdzanie, czy aplikacji nie przyznano już uprawnień

Aby sprawdzić, czy użytkownik zezwolił na dostęp do określonych danych, przekaż 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, jakie uprawnienia potrzebuje aplikacja, ale nie podaje powodu. W niektórych przypadkach może to być dla użytkownika zaskakujące. Zanim wywołasz metodę requestPermissions(), warto wyjaśnić użytkownikowi, dlaczego Twoja aplikacja potrzebuje tych uprawnień.

Badania pokazują, że użytkownicy chętniej udzielają uprawnień, jeśli wiedzą, do czego aplikacja ich potrzebuje, np. czy są one niezbędne do obsługi głównej funkcji aplikacji lub do 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ż poinformować użytkowników o dostępie do danych wrażliwych w czasie rzeczywistym. Jeśli na przykład aplikacja ma dostęp do aparatu lub mikrofonu, warto poinformować o tym użytkownika, umieszczając ikonę powiadomienia w aplikacji lub w panelu powiadomień (jeśli aplikacja działa w tle). Dzięki temu nie będzie wyglądać na to, że zbierasz dane potajemnie.

Jeśli musisz poprosić o przyznanie uprawnień, aby coś działało w aplikacji, ale powód nie jest jasny dla użytkownika, znajdź sposób na poinformowanie 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 instruktażowe UI. 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, wyjaśnij, 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.

Aby to zrobić, użyj RequestPermissionumowy zawartej w bibliotece AndroidX, w której zezwalasz systemowi na zarządzanie kodem prośby o uprawnienia. Korzystanie z kontraktu RequestPermission upraszcza logikę, dlatego jest to zalecane rozwiązanie, jeśli to możliwe. Jeśli to konieczne, możesz też sam zarządzać kodem zapytania w ramach prośby o uprawnienia i uwzględnić ten kod w logicznej funkcji wywołania w przypadku udzielenia uprawnień.

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

Z podanych niżej instrukcji dowiesz się, jak korzystać 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() w 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 zapewnić użytkownikom więcej informacji lub kontekstu, zmień interfejs aplikacji, aby ułatwić im zrozumienie, dlaczego dana funkcja potrzebuje określonego uprawnienia. Możesz na przykład zmienić tekst przycisku, który uruchamia 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łużyć 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 funkcja aplikacji uzyskuje dostęp do bieżącej lokalizacji urządzenia w jednym z tych przypadków:

  • Aktywność należąca do Twojej aplikacji jest widoczna.
  • 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 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 aplikacja prosi o ACCESS_COARSE_LOCATION lub ACCESS_FINE_LOCATION uprawnienia, jak pokazano w tym fragmencie kodu:

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

  • W aplikacji do udostępniania lokalizacji w grupie rodzinnej użytkownicy mogą stale udostępniać swoją lokalizację członkom grupy.
  • 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, 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ń 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 odrzuci prośbę o przyznanie uprawnień, aplikacja powinna pomóc mu zrozumieć konsekwencje takiej decyzji. 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ą błędu i kolorem;
  • 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. Innymi słowy, 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. W tym celu 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 przycisków w tym oknie.
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 kamerą, użytkownik zobaczy w oknie uprawnień opcję Tylko tym razem (patrz rys. 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 usługa na pierwszym planie zostanie uruchomiona, gdy aktywność jest widoczna, a użytkownik przeniesie aplikację do tła, aplikacja będzie mieć dostęp do danych do momentu zatrzymania usługi na pierwszym planie.

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

W Androidzie 13 (poziom API 33) lub nowszym możesz usunąć z aplikacji dostęp do uprawnień w czasie wykonywania, których aplikacja już nie potrzebuje. Wykonaj ten krok podczas aktualizowania aplikacji, 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 odebrać dostęp do grupy uprawnień w czasie wykonywania, prześlij zbiór nazw uprawnień do revokeSelfPermissionsOnKill(). Proces usuwania uprawnień odbywa się asynchronicznie i zatrzymuje wszystkie procesy powiązane z identyfikatorem UID aplikacji.

Aby system mógł usunąć uprawnienia aplikacji, wszystkie procesy powiązane z aplikacją muszą zostać zatrzymane. Gdy wywołujesz interfejs API, system decyduje, kiedy można bezpiecznie zakończyć te procesy. Zwykle system czeka, aż aplikacja przez dłuższy czas będzie działać 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 przeznaczona na Androida w wersji 11 (poziom interfejsu API 30) lub nowszej i nie jest używana przez kilka miesięcy, system chroni dane użytkownika, automatycznie resetując wrażliwe uprawnienia w czasie działania, które użytkownik przyznał aplikacji. Więcej informacji znajdziesz w przewodniku dotyczącym 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.

Przyznawanie wszystkich uprawnień 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 najlepsze praktyki dotyczące prywatności.