Uprawnienia na platformie Xamarin.Android

Omówienie

Aplikacje systemu Android działają we własnej piaskownicy i ze względów bezpieczeństwa nie mają dostępu do niektórych zasobów systemowych ani sprzętu na urządzeniu. Użytkownik musi jawnie udzielić aplikacji uprawnień, zanim będzie mógł korzystać z tych zasobów. Na przykład aplikacja nie może uzyskać dostępu do GPS na urządzeniu bez jawnego uprawnienia od użytkownika. System Android zgłosi błąd Java.Lang.SecurityException , jeśli aplikacja spróbuje uzyskać dostęp do chronionego zasobu bez uprawnień.

Uprawnienia są deklarowane w AndroidManifest.xml przez dewelopera aplikacji podczas tworzenia aplikacji. System Android ma dwa różne przepływy pracy w celu uzyskania zgody użytkownika na te uprawnienia:

  • W przypadku aplikacji przeznaczonych dla systemu Android 5.1 (poziom interfejsu API 22) lub niższego żądanie uprawnień wystąpiło podczas instalowania aplikacji. Jeśli użytkownik nie udzielił uprawnień, aplikacja nie zostanie zainstalowana. Po zainstalowaniu aplikacji nie ma możliwości odwołania uprawnień z wyjątkiem odinstalowania aplikacji.
  • Począwszy od systemu Android 6.0 (poziom 23 interfejsu API), użytkownicy mieli większą kontrolę nad uprawnieniami; mogą udzielać lub odwoływać uprawnienia, o ile aplikacja jest zainstalowana na urządzeniu. Ten zrzut ekranu przedstawia ustawienia uprawnień dla aplikacji Kontakty Google. Wyświetla listę różnych uprawnień i umożliwia użytkownikowi włączanie lub wyłączanie uprawnień:

Ekran Przykładowe uprawnienia

Aplikacje systemu Android muszą sprawdzać w czasie wykonywania, aby sprawdzić, czy mają uprawnienia dostępu do chronionego zasobu. Jeśli aplikacja nie ma uprawnień, musi wysyłać żądania przy użyciu nowych interfejsów API dostarczonych przez zestaw SDK systemu Android, aby użytkownik udzielił uprawnień. Uprawnienia są podzielone na dwie kategorie:

  • Uprawnienia normalne — są to uprawnienia, które stanowią niewielkie zagrożenie bezpieczeństwa dla bezpieczeństwa lub prywatności użytkownika. System Android 6.0 automatycznie udziela normalnych uprawnień w momencie instalacji. Aby uzyskać pełną listę normalnych uprawnień, zapoznaj się z dokumentacją systemu Android.
  • Niebezpieczne uprawnienia — w przeciwieństwie do normalnych uprawnień niebezpieczne uprawnienia to te, które chronią zabezpieczenia lub prywatność użytkownika. Muszą one zostać jawnie przyznane przez użytkownika. Wysyłanie lub odbieranie wiadomości SMS jest przykładem akcji wymagającej niebezpiecznego uprawnienia.

Ważne

Kategoria, do którego należy uprawnienie, może ulec zmianie w czasie. Możliwe, że uprawnienie, które zostało skategoryzowane jako "normalne" uprawnienie, może zostać podniesione w przyszłych poziomach interfejsu API do niebezpiecznych uprawnień.

Niebezpieczne uprawnienia są dalej podzielone na grupy uprawnień. Grupa uprawnień będzie zawierać uprawnienia, które są logicznie powiązane. Gdy użytkownik udziela uprawnień jednemu członkowi grupy uprawnień, system Android automatycznie udziela uprawnień wszystkim członkom tej grupy. Na przykład STORAGE grupa uprawnień przechowuje uprawnienia WRITE_EXTERNAL_STORAGE i READ_EXTERNAL_STORAGE . Jeśli użytkownik udziela uprawnień do READ_EXTERNAL_STORAGEusługi , WRITE_EXTERNAL_STORAGE uprawnienie zostanie automatycznie przyznane w tym samym czasie.

Przed zażądaniem co najmniej jednego uprawnienia najlepszym rozwiązaniem jest dostarczenie uzasadnienia, dlaczego aplikacja wymaga uprawnień przed zażądaniem uprawnienia. Gdy użytkownik zrozumie uzasadnienie, aplikacja może zażądać uprawnień od użytkownika. Dzięki zrozumieniu uzasadnienia użytkownik może podjąć świadomą decyzję, jeśli chce udzielić uprawnienia i zrozumieć konsekwencje, jeśli nie.

Cały przepływ pracy sprawdzania i żądania uprawnień jest nazywany sprawdzaniem uprawnień w czasie wykonywania i można go podsumować na poniższym diagramie:

Wykres blokowy sprawdzania uprawnień w czasie wykonywania

Biblioteka obsługi systemu Android przywraca niektóre z nowych interfejsów API w celu uzyskania uprawnień do starszych wersji systemu Android. Te interfejsy API z systemem Backported automatycznie sprawdzają wersję systemu Android na urządzeniu, dlatego nie jest konieczne przeprowadzenie sprawdzania poziomu interfejsu API za każdym razem.

W tym dokumencie omówiono sposób dodawania uprawnień do aplikacji platformy Xamarin.Android oraz sposobu, w jaki aplikacje przeznaczone dla systemu Android 6.0 (poziom 23 interfejsu API) lub wyższego poziomu powinny wykonywać sprawdzanie uprawnień w czasie wykonywania.

Uwaga

Istnieje możliwość, że uprawnienia sprzętu mogą mieć wpływ na sposób filtrowania aplikacji przez sklep Google Play. Jeśli na przykład aplikacja wymaga uprawnień do aparatu, sklep Google Play nie wyświetli aplikacji w Sklep Google Play na urządzeniu, na którym nie zainstalowano aparatu.

Wymagania

Zdecydowanie zaleca się, aby projekty Xamarin.Android zawierały pakiet NuGet Xamarin.Android.Support.Compat . Ten pakiet będzie backportować określone interfejsy API do starszych wersji systemu Android, zapewniając jeden wspólny interfejs bez konieczności ciągłego sprawdzania wersji systemu Android, na którym działa aplikacja.

Żądanie uprawnień systemowych

Pierwszym krokiem podczas pracy z uprawnieniami systemu Android jest zadeklarowanie uprawnień w pliku manifestu systemu Android. Należy to zrobić niezależnie od poziomu interfejsu API, którego dotyczy aplikacja.

Aplikacje przeznaczone dla systemu Android 6.0 lub nowszego nie mogą zakładać, że ponieważ użytkownik udzielił uprawnień w pewnym momencie w przeszłości, uprawnienie będzie prawidłowe przy następnym uruchomieniu. Aplikacja przeznaczona dla systemu Android 6.0 musi zawsze wykonywać sprawdzanie uprawnień środowiska uruchomieniowego. Aplikacje przeznaczone dla systemu Android 5.1 lub starszego nie muszą wykonywać sprawdzania uprawnień w czasie wykonywania.

Uwaga

Aplikacje powinny żądać tylko wymaganych uprawnień.

Deklarowanie uprawnień w manifeście

Uprawnienia są dodawane do AndroidManifest.xml z elementem uses-permission . Jeśli na przykład aplikacja ma zlokalizować pozycję urządzenia, wymaga uprawnień do lokalizacji w dobrym stanie i kursie. Do manifestu są dodawane następujące dwa elementy:

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

Istnieje możliwość zadeklarowania uprawnień przy użyciu obsługi narzędzi wbudowanych w program Visual Studio:

  1. Kliknij dwukrotnie pozycję Właściwości w Eksplorator rozwiązań i wybierz kartę Manifest systemu Android w okno Właściwości:

    Wymagane uprawnienia na karcie Manifest systemu Android

  2. Jeśli aplikacja nie ma jeszcze AndroidManifest.xml, kliknij pozycję Nie znaleziono AndroidManifest.xml. Kliknij, aby dodać jeden, jak pokazano poniżej:

    Brak komunikatu AndroidManifest.xml

  3. Wybierz wszystkie uprawnienia wymagane przez aplikację z listy Wymagane uprawnienia i zapisz:

    Wybrane przykładowe uprawnienia APARATU

Rozszerzenie Xamarin.Android automatycznie doda pewne uprawnienia w czasie kompilacji do kompilacji debugowania. Ułatwi to debugowanie aplikacji. W szczególności dwa istotne uprawnienia to INTERNET i READ_EXTERNAL_STORAGE. Te automatycznie ustawione uprawnienia nie będą widoczne na liście Wymagane uprawnienia . Kompilacje wydania używają jednak tylko uprawnień jawnie ustawionych na liście Wymagane uprawnienia .

W przypadku aplikacji przeznaczonych dla systemu Android 5.1 (poziom 22 interfejsu API) lub niższego nie ma nic więcej, co należy zrobić. Aplikacje, które będą uruchamiane w systemie Android 6.0 (interfejs API 23 poziom 23) lub nowszym, powinny przejść do następnej sekcji dotyczącej sposobu przeprowadzania kontroli uprawnień czasu wykonywania.

Kontrole uprawnień środowiska uruchomieniowego w systemie Android 6.0

Metoda ContextCompat.CheckSelfPermission (dostępna w bibliotece obsługi systemu Android) służy do sprawdzania, czy udzielono określonego uprawnienia. Ta metoda zwróci wyliczenie Android.Content.PM.Permission , które ma jedną z dwóch wartości:

  • Permission.Granted – Udzielono określonego uprawnienia.
  • Permission.Denied — Określone uprawnienie nie zostało przyznane.

Ten fragment kodu jest przykładem sprawdzania uprawnień aparatu w działaniu:

if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.Camera) == (int)Permission.Granted) 
{
    // We have permission, go ahead and use the camera.
} 
else 
{
    // Camera permission is not granted. If necessary display rationale & request.
}

Najlepszym rozwiązaniem jest informowanie użytkownika o tym, dlaczego uprawnienia są niezbędne dla aplikacji, aby można było podjąć świadomą decyzję o udzieleniu uprawnienia. Przykładem może być aplikacja, która wykonuje zdjęcia i tagi geograficzne. Użytkownik jest jasne, że uprawnienia aparatu są niezbędne, ale może nie być jasne, dlaczego aplikacja wymaga również lokalizacji urządzenia. Uzasadnienie powinno wyświetlić komunikat, aby pomóc użytkownikowi zrozumieć, dlaczego uprawnienie do lokalizacji jest pożądane i że wymagane jest uprawnienie do aparatu.

Metoda ActivityCompat.ShouldShowRequestPermissionRationale służy do określania, czy uzasadnienie powinno być wyświetlane użytkownikowi. Ta metoda zwróci wartość true , jeśli powinno zostać wyświetlone uzasadnienie dla danego uprawnienia. Ten zrzut ekranu przedstawia przykład paska przekąskowego wyświetlanego przez aplikację, który wyjaśnia, dlaczego aplikacja musi znać lokalizację urządzenia:

Uzasadnienie lokalizacji

Jeśli użytkownik udzieli uprawnienia, należy wywołać metodę ActivityCompat.RequestPermissions(Activity activity, string[] permissions, int requestCode) . Ta metoda wymaga następujących parametrów:

  • activity — jest to działanie, które żąda uprawnień i ma zostać poinformowane przez system Android o wynikach.
  • permissions — lista żądanych uprawnień.
  • requestCode — wartość całkowita używana do dopasowania wyników żądania uprawnień do wywołania RequestPermissions . Ta wartość powinna być większa niż zero.

Ten fragment kodu jest przykładem dwóch omówionych metod. Najpierw należy sprawdzić, czy należy wyświetlić uzasadnienie uprawnień. Jeśli uzasadnienie ma być pokazane, to przekąska jest wyświetlana z uzasadnieniem. Jeśli użytkownik kliknie przycisk OK na pasku przekąskowym, aplikacja zażąda uprawnień. Jeśli użytkownik nie akceptuje uzasadnienia, aplikacja nie powinna kontynuować żądania uprawnień. Jeśli uzasadnienie nie jest wyświetlane, działanie zażąda uprawnienia:

if (ActivityCompat.ShouldShowRequestPermissionRationale(this, Manifest.Permission.AccessFineLocation)) 
{
    // Provide an additional rationale to the user if the permission was not granted
    // and the user would benefit from additional context for the use of the permission.
    // For example if the user has previously denied the permission.
    Log.Info(TAG, "Displaying camera permission rationale to provide additional context.");

    var requiredPermissions = new String[] { Manifest.Permission.AccessFineLocation };
    Snackbar.Make(layout, 
                   Resource.String.permission_location_rationale,
                   Snackbar.LengthIndefinite)
            .SetAction(Resource.String.ok, 
                       new Action<View>(delegate(View obj) {
                           ActivityCompat.RequestPermissions(this, requiredPermissions, REQUEST_LOCATION);
                       }    
            )
    ).Show();
}
else 
{
    ActivityCompat.RequestPermissions(this, new String[] { Manifest.Permission.Camera }, REQUEST_LOCATION);
}

RequestPermission można wywołać nawet wtedy, gdy użytkownik udzielił już uprawnień. Kolejne wywołania nie są konieczne, ale zapewniają użytkownikowi możliwość potwierdzenia (lub odwołania) uprawnienia. Po RequestPermission wywołaniu kontrolka jest przekazywana do systemu operacyjnego, co spowoduje wyświetlenie interfejsu użytkownika do akceptowania uprawnień:

Okno dialogowe Permssion

Po zakończeniu działania system Android zwróci wyniki do działania za pomocą metody wywołania zwrotnego . OnRequestPermissionResult Ta metoda jest częścią interfejsu ActivityCompat.IOnRequestPermissionsResultCallback , który musi zostać zaimplementowany przez działanie. Ten interfejs ma jedną metodę , OnRequestPermissionsResultktóra zostanie wywołana przez system Android w celu poinformowania działania o wyborach użytkownika. Jeśli użytkownik udzielił uprawnienia, aplikacja może przejść do przodu i użyć chronionego zasobu. Poniżej przedstawiono przykład sposobu implementacji OnRequestPermissionResult :

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
    if (requestCode == REQUEST_LOCATION) 
    {
        // Received permission result for camera permission.
        Log.Info(TAG, "Received response for Location permission request.");

        // Check if the only required permission has been granted
        if ((grantResults.Length == 1) && (grantResults[0] == Permission.Granted)) {
            // Location permission has been granted, okay to retrieve the location of the device.
            Log.Info(TAG, "Location permission has now been granted.");
            Snackbar.Make(layout, Resource.String.permission_available_camera, Snackbar.LengthShort).Show();            
        } 
        else 
        {
            Log.Info(TAG, "Location permission was NOT granted.");
            Snackbar.Make(layout, Resource.String.permissions_not_granted, Snackbar.LengthShort).Show();
        }
    } 
    else 
    {
        base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

Podsumowanie

W tym przewodniku omówiono sposób dodawania i sprawdzania uprawnień na urządzeniu z systemem Android. Różnice w sposobie działania uprawnień między starymi aplikacjami systemu Android (poziom < 23 interfejsu API) i nowymi aplikacjami systemu Android (poziom > 22 interfejsu API). Omówiono w nim sposób przeprowadzania kontroli uprawnień w czasie wykonywania w systemie Android 6.0.