Requesting Runtime Permissions in Android Marshmallow

With over 130 unique permissions available to Android developers, it's hard to know exactly which ones to specify. Worse yet, information technology's non simply scary for your app's users to see merely how many permissions you crave, only it'southward increasingly hard to explicate why yous need so many permissions. Android Marshmallow introduces an entirely new spin on application permissions in an endeavor to not only simplify permissions, but also to reduce the number of permissions needed.

Android M Permissions

Normal Permissions

Marshmallow attempts to flip the script on permissions by having a pre-defined listing of normal permissions that are automatically granted at installation time and which users can never revoke (exactly how permissions work today). All other permissions are not marked as normal and require that developers asking permission manually from their users. These operate similarly to iOS'south permission system and tin be revoked later on.

Simplified Permissions

Traditionally, when developing an Android application, it was required to specify each and every permission needed when calling a specific API. This meant that if you needed to apply the GPS to get the user'southward location, it was required to specify the ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION permissions. Permission Groups attempt to simplify permissions that are performing similar operations, such every bit Location, Contacts, Phone, Sensors, SMS, and Storage. An app group currently bundles together anywhere between one and seven permissions into a single permission group. This means you tin request all of the permissions in a group in a single go!

permissions_check

If you utilise whatsoever of the permissions found in one of the permission groups, or a permission that is non specified equally normal, then it's required to follow the new period to request a permission from your user.

Permission Workflow

In the past, the just thing that was required for developers was to check a check box in your project settings for the permissions the app needed. While this part of the app gear up is the same, you must comprise a way to asking any not-normal permissions from your users and disable application functionality based on their response. I have attempted to visualize the new workflow here so you can follow forth every bit I walk you pace-by-pace through determining the GPS location using my Geolocator Plugin for Xamarin.

Android Permissions Workflow

Getting Started

It's of import to make up one's mind which permissions are required and which have been upgraded to the new permission groups. In this instance, the Geolocator Plugin requires both fine and coarse location permissions, which have been grouped into android.permission-grouping.LOCATION. It'southward still necessary to add these two permissions in the AndroidManifest.xml, but the use of these permissions is only requested at runtime, not during install, on Android Marshmallow and above.

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

Alternatively, you can open your Android project options and check these 2 permissions under Android Application.

Permissions

Gear up Target SDK

Notice that in the projection settings in a higher place that the Target SDK is set to API 23+. It must manually be overridden and NOT gear up to "utilize compile".

Cheque the SDK Version

Runtime permissions are an Android Marshmallow feature. This means that if the user is on an older version of Android, in that location'southward no need to phone call any of the new runtime permission workflows. Information technology's unproblematic to check the SDK version before making the phone call to an API by using the Build.Version.SdkInt enum.

async Chore TryGetLocationAsync() {   if ((int)Build.VERSION.SdkInt < 23)   {     await GetLocationAsync();     render;   }    expect GetLocationPermissionAsync(); }        

Now, allow's implement the GetLocationPermissionAsync method for Marshmallow and use the new runtime permissions. The first thing to do is to define the unabridged permission group that the app needs access to likewise equally a unique identifier to be used when requesting permission.

          readonly cord [] PermissionsLocation =      {       Manifest.Permission.AccessCoarseLocation,       Manifest.Permission.AccessFineLocation     };  const int RequestLocationId = 0;        

Check if Permission Granted

Users now have the ability to revoke runtime permissions whenever they desire. This means that yous tin can't assume the app has access to the permission, even if it had been granted previously. Yous can check to see if permission is still granted by calling a new method on the Context called CheckSelfPermission(cord permission). This method returns an integer specifying permission granted or denied.

If permission has already been granted, and then information technology's time to telephone call our Geolocator, but we must handle the denied state on first run or if the permission has been revoked.

const cord permission = Manifest.Permission.AccessFineLocation; if (CheckSelfPermission(permission) == (int)Permission.Granted) {   expect GetLocationAsync();   render; }  //need to asking permission        

Optionally Display Rationale

It'due south best practise to explicate to users the need for a specific permission before it'due south time to actually request it. If the application is a turn-by-turn directions map application, there's probably no demand to tell the user why the Location permission is needed. Even so, a user may be confused as to why Location is needed in a photo application, for instance, so it's good to prompt the user. Additionally, the ShouldShowRequestPermissionRationale(string permission) method tin be called to determine if the permission asking was denied by the user previously. If this method returns true, then it's about likely the perfect time to tell the user exactly why the permission is needed before requesting it over again.

if (ShouldShowRequestPermissionRationale(permission)) {   //Explicate to the user why we need to read the contacts   Snackbar.Make(layout, "Location access is required to show coffee shops nearby.", Snackbar.LengthIndefinite)           .SetAction("OK", five => RequestPermissions(PermissionsLocation, RequestLocationId))           .Testify();   return; }        

Additional Info

Request Permission

Finally, it's time to asking the permission and handle the permission request with the RequestPermission(cord[] permissions, int requestCode) method. This method will return right abroad and prompt the user for the specified permission(s). Here's what the full workflow to enquire for the location permission looks similar:

async Chore GetLocationPermissionAsync() {   //Bank check to see if any permission in our grouping is available, if one, so all are   const string permission = Manifest.Permission.AccessFineLocation;   if (CheckSelfPermission(permission) == (int)Permission.Granted)   {     look GetLocationAsync();     return;   }    //demand to request permission   if (ShouldShowRequestPermissionRationale(permission))   {     //Explain to the user why nosotros demand to read the contacts     Snackbar.Make(layout, "Location access is required to evidence coffee shops nearby.", Snackbar.LengthIndefinite)             .SetAction("OK", 5 => RequestPermissions(PermissionsLocation, RequestLocationId))             .Show();     return;   }   //Finally request permissions with the list of permissions and Id   RequestPermissions(PermissionsLocation, RequestLocationId); }        

Ask for Permission

Handle Permission Request

After the user has granted or denied the permission asking, it's time to handle the response and plow on or off the functionality. This can be accomplished by overriding the OnRequestPermissionsResult in the Activity where the permission was requested. This method returns the result code (the ane specified when requesting permission) and a result of granted or denied:

public override async void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults) {   switch (requestCode)   {     case RequestLocationId:     {       if (grantResults[0] == Permission.Granted)       {         //Permission granted         var snack = Snackbar.Make(layout, "Location permission is available, getting lat/long.", Snackbar.LengthShort);         snack.Bear witness();                                      look GetLocationAsync();       }       else       {         //Permission Denied :(         //Disabling location functionality         var snack = Snackbar.Make(layout, "Location permission is denied.", Snackbar.LengthShort);         snack.Bear witness();       }     }     break;   } }        

Get Geolocation!

Finally, if we have the granted permissions, it's fourth dimension to get the location of the device:

async Task GetLocationAsync() {    textLocation.Text = "Getting Location";   endeavor   {     var locator = CrossGeolocator.Electric current;     locator.DesiredAccuracy = 100;     var position = await locator.GetPositionAsync(20000);        textLocation.Text = cord.Format("Lat: {0}  Long: {one}", position.Latitude, position.Longitude);   }   catch (Exception ex)   {     textLocation.Text = "Unable to get location: " + ex.ToString();   } }        

Backwards Compatibility

Be aware that the APIs I covered in this blog are new in Android 6.0 Marshmallow, which means you lot should but telephone call them on devices running SDK 23 or college. To simplify the process of checking runtime permissions, the Android Support v4 and v13 libraries take been updated in Revision 23 (currently in pre-release), which includes ContextCompat.CheckSelfPermission() for checking permissions. Additionally, both ActivityCompat and FragmentCompat have an added RequestPermissions() and ShouldShowRequestPermissionRationale() method, which means we can actually remove the original SDK check, which turns our total code into:

async Job GetLocationCompatAsync() {   const cord permission = Manifest.Permission.AccessFineLocation;   if (ContextCompat.CheckSelfPermission(this, permission) == (int)Permission.Granted)   {     wait GetLocationAsync();     render;   }    if (ActivityCompat.ShouldShowRequestPermissionRationale(this, permission))   {     //Explain to the user why we demand to read the contacts     Snackbar.Brand(layout, "Location access is required to show coffee shops nearby.", Snackbar.LengthIndefinite)             .SetAction("OK", v => ActivityCompat.RequestPermissions(this, PermissionsLocation, RequestLocationId))             .Testify();        return;   }      ActivityCompat.RequestPermissions(this, PermissionsLocation, RequestLocationId);  }        

Larn More

To larn more nearly getting started with Android Marshmallow (currently in Preview) exist sure to read through the getting started documentation and browse total samples of the latest features of Marshmallow, which includes runtime permissions. In improver to the bachelor Marshmallow samples, I've also provided this location sample using the Geolocator Plugin on my GitHub.