Każda aplikacja na Androida działa w piaskownicy z ograniczonym dostępem. Jeśli aplikacja musi używać zasobów lub informacji spoza własnego środowiska piaskownicy, możesz zadeklarować uprawnienia w czasie działania i skonfigurować prośbę o uprawnienia, która zapewnia taki dostęp. Te kroki są częścią przepływu pracy związanego z uprawnieniami.
Jeśli zadeklarujesz uprawnienia niebezpieczne, a aplikacja zostanie zainstalowana na urządzeniu z Androidem 6.0 (API na poziomie 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 aplikacja jest zainstalowana na urządzeniu z Androidem 5.1 (interfejs API na poziomie 22) lub starszym, uprawnienia są przyznawane automatycznie i nie musisz wykonywać żadnych pozostałych czynności opisanych na tej stronie.
Podstawowe zasady
Podstawowe zasady dotyczące proszenia o uprawnienia w czasie działania aplikacji:
- Poproś o uprawnienia w kontekście, gdy użytkownik zacznie korzystać z funkcji, która ich wymaga.
- Nie blokuj użytkownika. Zawsze udostępniaj opcję anulowania wzorca interfejsu edukacyjnego, np. wzorca wyjaśniającego powody prośby o uprawnienia.
- Jeśli użytkownik nie wyrazi zgody na uprawnienia wymagane przez daną funkcję lub wycofa udzieloną zgodę, przeprowadź łagodną degradację aplikacji, aby użytkownik mógł dalej z niej korzystać, na przykład wyłączając funkcję, która wymaga określonych uprawnień.
- Nie zakładaj, że system będzie działał w określony sposób. Nie zakładaj na przykład, że uprawnienia pojawiają się w tej samej grupie uprawnień. Grupa uprawnień pomaga jedynie systemowi zminimalizować liczbę okien dialogowych wyświetlanych użytkownikowi, gdy aplikacja prosi o przyznanie uprawnień, które są ze sobą ściśle powiązane.
Proces wysyłania prośby o uprawnienia
Zanim zadeklarujesz uprawnienia w czasie działania i poprosisz o nie w aplikacji, oceń, czy jest to konieczne. Wiele przypadków użycia w aplikacji, takich jak robienie zdjęć, wstrzymywanie odtwarzania multimediów i wyświetlanie trafnych reklam, można zrealizować bez deklarowania uprawnień.
Jeśli uznasz, że Twoja aplikacja musi deklarować uprawnienia w czasie działania i prosić o nie, wykonaj te czynności:
- Zadeklaruj uprawnienia, o które aplikacja może prosić, w pliku manifestu aplikacji.
- Zaprojektuj interfejs aplikacji tak, 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 prywatnych danych użytkownika.
- Poczekaj, aż użytkownik wywoła w aplikacji zadanie lub 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, które są wymagane do uzyskania dostępu do tych danych.
Sprawdź, czy użytkownik przyznał już
uprawnienia w czasie działania, których wymaga Twoja aplikacja. 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 operację wymagającą uprawnień, musisz sprawdzić, czy je masz.
Sprawdź, czy aplikacja powinna wyświetlić użytkownikowi uzasadnienie, dlaczego potrzebuje określonych uprawnień w czasie działania. Jeśli system stwierdzi, że aplikacja nie powinna wyświetlać uzasadnienia, przejdź bezpośrednio do następnego kroku, nie wyświetlając elementu interfejsu.
Jeśli jednak system stwierdzi, że aplikacja powinna wyświetlić uzasadnienie, przedstaw je użytkownikowi w elemencie interfejsu. W tym uzasadnieniu jasno wyjaśnij, do jakich danych aplikacja próbuje uzyskać dostęp i jakie korzyści może przynieść użytkownikowi, jeśli przyzna on uprawnienia w czasie działania. Gdy użytkownik potwierdzi, że zapoznał się z uzasadnieniem, przejdź do następnego kroku.
Poproś o uprawnienia w czasie działania aplikacji, których aplikacja potrzebuje, aby uzyskać dostęp do prywatnych danych użytkownika. System wyświetla wtedy prośbę o przyznanie uprawnień w czasie działania aplikacji, taką jak ta pokazana na stronie z omówieniem uprawnień.
Sprawdź odpowiedź użytkownika – czy przyznał uprawnienia w czasie działania, czy odmówił ich przyznania.
Jeśli użytkownik przyznał uprawnienia aplikacji, możesz uzyskać dostęp do jego prywatnych danych. Jeśli użytkownik odmówi przyznania uprawnień, zastosuj łagodną degradację wrażeń użytkownika aplikacji, aby zapewnić mu funkcjonalność bez informacji chronionych przez te uprawnienia.
Rysunek 1 przedstawia przepływ pracy i zestaw decyzji związanych z tym procesem:
Sprawdzanie, czy aplikacja ma już przyznane uprawnienia
Aby sprawdzić, czy użytkownik przyznał już aplikacji określone uprawnienie, przekaż je 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 uprawnień
Okno uprawnień wyświetlane przez system po wywołaniu metody requestPermissions() informuje, jakich uprawnień wymaga aplikacja, ale nie podaje powodu. W niektórych przypadkach może to być dla użytkownika niezrozumiałe. Przed wywołaniem metody requestPermissions() warto wyjaśnić użytkownikowi, dlaczego aplikacja potrzebuje uprawnień.
Badania pokazują, że użytkownicy znacznie chętniej wyrażają zgodę na prośby o uprawnienia, jeśli wiedzą, dlaczego aplikacja ich potrzebuje, np. czy uprawnienia są potrzebne do obsługi głównej funkcji aplikacji czy do wyświetlania reklam. Jeśli więc używasz tylko części wywołań interfejsu API, które należą do grupy uprawnień, wyraźnie określ, 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ż informować użytkowników o dostępie do danych wrażliwych w czasie rzeczywistym. Jeśli na przykład uzyskujesz dostęp do aparatu lub mikrofonu, poinformuj o tym użytkownika, używając ikony powiadomienia w aplikacji lub na pasku powiadomień (jeśli aplikacja działa w tle), aby nie wyglądało to tak, jakby dane były zbierane potajemnie.
Jeśli musisz poprosić o uprawnienia, aby funkcja działała, ale powód nie jest jasny dla użytkownika, znajdź sposób, aby wyjaśnić, dlaczego potrzebujesz uprawnień newralgicznych.
Jeśli metoda ContextCompat.checkSelfPermission() zwraca PERMISSION_DENIED, wywołaj shouldShowRequestPermissionRationale(). Jeśli ta metoda zwraca wartość true, wyświetl użytkownikowi interfejs edukacyjny. W tym interfejsie wyjaśnij, dlaczego funkcja, którą użytkownik chce włączyć, wymaga określonego uprawnienia.
Jeśli aplikacja prosi o uprawnienia związane z lokalizacją, mikrofonem lub aparatem, rozważ wyjaśnienie, dlaczego potrzebuje dostępu do tych informacji.
Wyślij prośbę o uprawnienia
Gdy użytkownik zobaczy interfejs edukacyjny lub wartość zwracana przez shouldShowRequestPermissionRationale() wskazuje, że nie musisz wyświetlać interfejsu edukacyjnego, poproś o uprawnienia. Użytkownicy zobaczą okno uprawnień systemowych, w którym mogą wybrać, czy chcą przyznać aplikacji określone uprawnienia.
Aby to zrobić, użyj kontraktu RequestPermission zawartego w bibliotece AndroidX, w którym zezwolisz systemowi na zarządzanie kodem prośby o uprawnienia. Korzystanie z kontraktu RequestPermission upraszcza logikę, dlatego jest to zalecane rozwiązanie, gdy tylko jest możliwe. W razie potrzeby możesz też samodzielnie zarządzać kodem żądania w ramach prośby o uprawnienia i uwzględnić go w logice wywołania zwrotnego uprawnień.
Zezwalanie 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:
androidx.activity, wersja 1.2.0 lub nowszaandroidx.fragmentw wersji 1.3.0 lub nowszej,
Możesz wtedy użyć jednej z tych klas:
- Aby poprosić o pojedyncze uprawnienie, użyj
RequestPermission. - Aby poprosić o kilka uprawnień jednocześnie, użyj
RequestMultiplePermissions.
Poniższe kroki pokazują, jak używać umowy RequestPermission. Proces jest prawie taki sam jak w przypadku umowy RequestMultiplePermissions.
W logice inicjowania aktywności lub fragmentu przekaż implementację
ActivityResultCallbackdo wywołaniaregisterForActivityResult().ActivityResultCallbackokreśla, jak aplikacja ma obsługiwać odpowiedź użytkownika na prośbę o uprawnienia.Zachowaj odwołanie do wartości zwracanej przez
registerForActivityResult(), która jest typuActivityResultLauncher.Aby w razie potrzeby wyświetlić okno uprawnień systemowych, wywołaj metodę
launch()w instancjiActivityResultLauncherzapisanej w poprzednim kroku.Po wywołaniu metody
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 metody
launch(). Aby przekazać użytkownikowi więcej informacji lub kontekstu, zmień interfejs aplikacji, aby ułatwić użytkownikom zrozumienie, dlaczego funkcja w aplikacji potrzebuje określonego uprawnienia. Możesz na przykład zmienić tekst na przycisku, który włącza tę funkcję.Tekst w oknie uprawnień systemowych odnosi się do grupy uprawnień powiązanej z uprawnieniem, o które prosisz. To grupowanie uprawnień ma na celu ułatwienie korzystania z systemu. Aplikacja nie powinna polegać na uprawnieniach znajdujących się w określonej grupie uprawnień lub poza nią.
Poniższy fragment kodu pokazuje, jak obsłużyć odpowiedź dotyczącą uprawnień:
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); }
Ten fragment kodu pokazuje zalecany proces sprawdzania uprawnień i proszenia użytkownika o ich przyznanie, gdy jest to konieczne:
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 pozwalać systemowi na zarządzanie kodem prośby o uprawnienia, możesz zarządzać nim samodzielnie. Aby to zrobić, dołącz kod żądania do wywołania requestPermissions().
Poniższy 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 na okno uprawnień systemowych, system wywoła implementację onRequestPermissionsResult() w aplikacji. System przekazuje odpowiedź użytkownika na okno uprawnień oraz zdefiniowany przez Ciebie kod żądania, jak pokazano 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. } }
Wysyłanie prośby 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ń w czasie działania aplikacji. Ważną różnicą w przypadku uprawnień dostępu do lokalizacji jest to, że system zawiera wiele uprawnień związanych z lokalizacją. To, o jakie uprawnienia prosisz i jak to robisz, zależy od wymagań dotyczących lokalizacji w przypadku użycia Twojej 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, ta funkcja wymaga dostępu do lokalizacji na pierwszym planie. Oto niektóre przykłady:
- W aplikacji do nawigacji funkcja umożliwia użytkownikom uzyskiwanie szczegółowych wskazówek dojazdu.
- W aplikacji do obsługi wiadomości dostępna jest funkcja, która umożliwia użytkownikom udostępnianie swojej bieżącej lokalizacji innym użytkownikom.
System uznaje, że aplikacja używa lokalizacji na pierwszym planie, jeśli funkcja aplikacji uzyskuje dostęp do bieżącej lokalizacji urządzenia w jednej z tych sytuacji:
- 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 działa w tle, np. gdy użytkownik naciśnie przycisk ekranu głównego na urządzeniu lub wyłączy wyświetlacz.
Na Androidzie 10 (poziom interfejsu API 29) i nowszych musisz zadeklarować typ usługi działającej na pierwszym planie jako
location, jak pokazano w tym fragmencie kodu. W przypadku wcześniejszych wersji Androida zalecamy zadeklarowanie tego typu usługi działającej 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 uprawnienie ACCESS_COARSE_LOCATION lub ACCESS_FINE_LOCATION, 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 Geofencing API. Oto kilka przykładów:
- W aplikacji do udostępniania lokalizacji w grupie rodzinnej funkcja umożliwia użytkownikom ciągłe udostępnianie lokalizacji członkom grupy rodzinnej.
- W aplikacji IoT dostępna jest funkcja, która umożliwia użytkownikom skonfigurowanie urządzeń domowych w taki sposób, aby wyłączały się, gdy użytkownik wychodzi z domu, i włączały się, gdy wraca.
System uznaje, że aplikacja używa lokalizacji w tle, jeśli uzyskuje ona dostęp do bieżącej lokalizacji urządzenia w dowolnej 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 uprawnień dostępu do lokalizacji zadeklarowanych przez aplikację.
Na Androidzie 10 (API na poziomie 29) i nowszych musisz zadeklarować uprawnienie ACCESS_BACKGROUND_LOCATION w pliku manifestu aplikacji, aby poprosić o dostęp do lokalizacji w tle w czasie działania aplikacji. W starszych wersjach Androida, gdy aplikacja uzyskuje dostęp do lokalizacji na pierwszym planie, automatycznie otrzymuje 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>
Obsługa odmowy przyznania uprawnień
Jeśli użytkownik odrzuci prośbę o uprawnienia, aplikacja musi pomóc mu zrozumieć konsekwencje tej decyzji. W szczególności aplikacja musi informować użytkowników o funkcjach, które nie działają z powodu braku uprawnień. Podczas tworzenia linków do firmy pamiętaj o tych sprawdzonych metodach:
- Zminimalizuj utratę funkcjonalności. Użytkownicy powinni mieć dostęp do aplikacji w takim zakresie, w jakim jest to możliwe bez wymaganych uprawnień. Jeśli funkcja działa przynajmniej w pewnym stopniu z dostępnymi danymi, nawet jeśli jest mniej skuteczna niż w przypadku przyznania uprawnień, najlepiej pozostawić ją włączoną.
Kieruj uwagę użytkownika. Wyróżnij konkretną część interfejsu aplikacji, w której funkcjonalność jest ograniczona, ponieważ aplikacja nie ma niezbędnych uprawnień. Przykłady możliwości:
- Wyświetl komunikat w miejscu, w którym powinny pojawić się wyniki lub dane funkcji.
- wyświetlić inny przycisk z ikoną błędu i odpowiednim kolorem;
Unikaj ogólników. Nie wyświetlaj ogólnego komunikatu. Zamiast tego jasno określ, które funkcje są niedostępne, ponieważ aplikacja nie ma niezbędnych uprawnień.
Nie blokuj interfejsu. Innymi słowy, nie wyświetlaj ostrzeżenia na pełnym ekranie, które uniemożliwia użytkownikom dalsze korzystanie z aplikacji.
Zaakceptuj preferencje użytkownika: możesz poinformować użytkowników, jak brak dostępu do żądanych uprawnień wpływa na funkcjonalność aplikacji, ale nie powinni oni czuć się zmuszeni do zmiany zdania. Poinformowanie użytkownika, że nie ma dostępu do wszystkich funkcji, gdy jest to uzasadnione (np. gdy próbuje użyć części aplikacji zablokowanej bez uprawnień), jest ważne, ale ciągłe przypominanie o tym nie jest wyrazem szacunku dla jego wyboru.
Przestrzeganie tych wytycznych może pomóc użytkownikom w zarządzaniu dostępem do ich prywatnych danych w sposób zgodny z ich wartościami. Brak akceptacji decyzji użytkowników dotyczących prywatności szkodzi zaufaniu i reputacji nie tylko Twojej aplikacji, ale też całego ekosystemu.
Dodatkowo, jeśli użytkownik kliknie „Odmów” w przypadku określonego uprawnienia więcej niż raz podczas okresu instalacji aplikacji na urządzeniu, nie zobaczy już systemowego okna uprawnień, gdy aplikacja ponownie poprosi o to uprawnienie. Działanie użytkownika oznacza „nie pytaj ponownie” i jest traktowane jako stała odmowa. Bardzo ważne jest, aby prosić użytkowników o uprawnienia tylko wtedy, gdy potrzebują dostępu do określonej funkcji. W przeciwnym razie możesz nieumyślnie utracić możliwość ponownego poproszenia o uprawnienia. W niektórych sytuacjach uprawnienia mogą zostać automatycznie odrzucone bez podejmowania przez użytkownika żadnych działań. (uprawnienia mogą być też przyznawane automatycznie). Ważne jest, aby nie zakładać niczego na temat automatycznego zachowania. Za każdym razem, gdy aplikacja musi uzyskać dostęp do funkcji, która wymaga uprawnień, sprawdź, czy aplikacja nadal ma te uprawnienia. Aby zapewnić użytkownikom jak najlepsze wrażenia podczas proszenia o uprawnienia aplikacji, zapoznaj się też ze sprawdzonymi metodami dotyczącymi uprawnień aplikacji.
Sprawdzanie stanu odmowy podczas testowania i debugowania
Aby sprawdzić, czy aplikacji trwale odmówiono uprawnień (na potrzeby debugowania i testowania), użyj tego polecenia:
adb shell dumpsys package PACKAGE_NAME
Gdzie PACKAGE_NAME to nazwa pakietu, który chcesz sprawdzić.
Dane wyjściowe polecenia zawierają sekcje, które wyglądają tak:
... 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 zostały raz odrzucone przez użytkownika, są oznaczone ikoną USER_SET.
Uprawnienia, które zostały trwale odrzucone przez dwukrotne wybranie opcji Odrzuć, są oznaczone ikoną USER_FIXED.
Aby mieć pewność, że testerzy zobaczą okno prośby 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ć.
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 zezwolenia
Począwszy od Androida 11 (poziom interfejsu API 30), gdy aplikacja prosi o uprawnienia związane z lokalizacją, mikrofonem lub aparatem, okno uprawnień wyświetlane dla użytkownika zawiera opcję Tylko tym razem, jak pokazano na rysunku 2. Jeśli użytkownik wybierze tę opcję w oknie, aplikacja otrzyma tymczasowe jednorazowe zezwolenie.
Aplikacja może wtedy uzyskać dostęp do powiązanych danych na okres, który zależy od jej działania i czynności użytkownika:
- Gdy aktywność aplikacji jest widoczna, aplikacja może uzyskiwać dostęp do danych.
- Jeśli użytkownik przeniesie aplikację na drugi plan, może ona nadal przez krótki czas uzyskiwać dostęp do danych.
- Jeśli uruchomisz usługę na pierwszym planie, gdy aktywność jest widoczna, a użytkownik przeniesie aplikację do tła, aplikacja będzie mogła nadal uzyskiwać dostęp do danych, dopóki usługa na pierwszym planie nie zostanie zatrzymana.
Proces aplikacji kończy się po cofnięciu uprawnień
Jeśli użytkownik unieważni jednorazowe zezwolenie, np. w ustawieniach systemowych, aplikacja nie będzie miała dostępu do danych, niezależnie od tego, czy usługa na pierwszym planie została uruchomiona. Podobnie jak w przypadku innych uprawnień, jeśli użytkownik wycofa jednorazowe uprawnienie aplikacji, jej proces zostanie zakończony.
Gdy użytkownik następnym razem otworzy aplikację, a funkcja w aplikacji poprosi o dostęp do lokalizacji, mikrofonu lub aparatu, użytkownik zostanie ponownie poproszony o przyznanie uprawnień.
Resetowanie nieużywanych uprawnień
Android oferuje kilka sposobów na zresetowanie nieużywanych uprawnień w czasie działania do domyślnego stanu odmowy:
- Interfejs API, za pomocą którego możesz aktywnie usunąć dostęp aplikacji do nieużywanych uprawnień w czasie działania.
- Mechanizm systemowy, który automatycznie resetuje uprawnienia nieużywanych aplikacji.
Usuwanie dostępu aplikacji
Na Androidzie 13 (API na poziomie 33) i nowszych możesz usunąć dostęp aplikacji do uprawnień w czasie działania, których już nie potrzebuje. Gdy aktualizujesz aplikację, wykonaj ten krok, aby użytkownicy lepiej rozumieli, dlaczego aplikacja nadal prosi o określone uprawnienia. Dzięki temu użytkownicy będą mieli większe zaufanie do Twojej aplikacji.
Aby usunąć dostęp do uprawnień w czasie działania, przekaż nazwę tych uprawnień do metody revokeSelfPermissionOnKill(). Aby jednocześnie usunąć dostęp do grupy uprawnień w czasie działania, przekaż kolekcję nazw uprawnień do metody revokeSelfPermissionsOnKill(). Proces usuwania uprawnień odbywa się asynchronicznie i powoduje zakończenie wszystkich procesów powiązanych z identyfikatorem UID aplikacji.
Aby system mógł usunąć uprawnienia aplikacji, wszystkie powiązane z nią procesy muszą zostać zakończone. Gdy wywołasz interfejs API, system określi, kiedy można bezpiecznie zakończyć te procesy. Zwykle system czeka, aż aplikacja będzie działać przez 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 przy następnym uruchomieniu aplikacji przez użytkownika. To okno może zawierać listę uprawnień.
Automatyczne resetowanie uprawnień nieużywanych aplikacji
Jeśli Twoja aplikacja jest przeznaczona 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 w czasie działania, które użytkownik przyznał aplikacji. Więcej informacji znajdziesz w przewodniku na temat hibernacji aplikacji.
W razie potrzeby poproś o ustawienie jako domyślny moduł 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 rejestrów połączeń i SMS-ów oraz opublikować aplikację w Sklepie Play, przed poproszeniem o te uprawnienia w czasie działania musisz poprosić użytkownika o ustawienie aplikacji jako domyślnego modułu obsługi podstawowej funkcji systemowej.
Więcej informacji o domyślnych modułach obsługi, w tym wskazówki dotyczące wyświetlania użytkownikom prośby o wybranie 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 w czasie działania aplikacji na potrzeby testów
Aby automatycznie przyznać wszystkie uprawnienia w czasie działania aplikacji podczas instalowania jej na emulatorze lub urządzeniu testowym, użyj opcji -g polecenia adb shell install, jak pokazano w tym fragmencie kodu:
adb shell install -g PATH_TO_APK_FILE
Dodatkowe materiały
Więcej informacji o uprawnieniach znajdziesz w tych artykułach:
Więcej informacji o prośbach o uprawnienia znajdziesz w przykładach uprawnień.
Możesz też wykonać to ćwiczenie, które przedstawia sprawdzone metody ochrony prywatności.