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 wyraźnego zezwolenia od użytkownika. System Android zgłosi błąd Java.Lang.SecurityException , jeśli aplikacja pró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 22 interfejsu API) 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ń:

Sample Permissions screen

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 udostępnianych przez zestaw ANDROID SDK, 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 być 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 sklasyfikowane jako "normalne" uprawnienie, może zostać podniesione w przyszłych poziomach interfejsu API do niebezpiecznego uprawnienia.

Niebezpieczne uprawnienia są dalej podzielone na grupy uprawnień. Grupa uprawnień będzie przechowywać 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ń zawiera uprawnienia WRITE_EXTERNAL_STORAGE i READ_EXTERNAL_STORAGE . Jeśli użytkownik udziela uprawnień do READ_EXTERNAL_STORAGEelementu , WRITE_EXTERNAL_STORAGE uprawnienie zostanie automatycznie przyznane w tym samym czasie.

Przed zażądaniem co najmniej jednego uprawnienia najlepszym rozwiązaniem jest podanie uzasadnienia, dlaczego aplikacja wymaga uprawnienia przed zażądaniem uprawnienia. Gdy użytkownik zrozumie uzasadnienie, aplikacja może zażądać uprawnień od użytkownika. Rozumiejąc uzasadnienie, 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 znany jako sprawdzanie uprawnień w czasie wykonywania i można go podsumować na poniższym diagramie:

Run-time permission check flow chart

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 powrotem będą automatycznie sprawdzać wersję systemu Android na urządzeniu, więc 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 są przeznaczone dla systemu Android 6.0 (poziom 23 interfejsu API) lub nowszego, powinny wykonywać sprawdzanie uprawnień w czasie wykonywania.

Uwaga

Możliwe, ż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 będzie wyświetlać aplikacji w Sklepie Google Play na urządzeniu, które nie ma zainstalowanego aparatu fotograficznego.

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órej 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, że 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ć położenie urządzenia, wymaga on uprawnień do lokalizacji kursów i kursów. 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" />

Można zadeklarować uprawnienia przy użyciu obsługi narzędzi wbudowanej 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:

    Required permissions in the Android Manifest tab

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

    No AndroidManifest.xml message

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

    Example CAMERA permissions selected

Platforma Xamarin.Android automatycznie doda pewne uprawnienia w czasie kompilacji do debugowania kompilacji. 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ą wyświetlane 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ą działać w systemie Android 6.0 (interfejs API 23 poziom 23) lub nowszym, powinny przejść do następnej sekcji dotyczącej sposobu przeprowadzania kontroli uprawnień w czasie wykonywania.

Testy uprawnień środowiska uruchomieniowego w systemie Android 6.0

Metoda ContextCompat.CheckSelfPermission (dostępna w bibliotece pomocy technicznej 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 – Nie udzielono określonego uprawnienia.

Ten fragment kodu jest przykładem sprawdzania uprawnień Aparat 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 dla aplikacji niezbędne jest uprawnienie, aby można było podjąć świadomą decyzję o przyznaniu uprawnień. Przykładem może być aplikacja, która wykonuje zdjęcia i tagi geograficzne. Użytkownikowi jest jasne, że wymagane jest uprawnienie aparatu, 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 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:

Rationale for location

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 ma być wyświetlane uzasadnienie uprawnień. Jeśli uzasadnienie ma być pokazane, pasek przekąskowy jest wyświetlany 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ń:

Permssion Dialog

Po zakończeniu pracy użytkownika 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 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.