preface

Hello, I’m the light source.

Since Android6.0, Android’s permission mode has changed a bit, from giving the user a list at install time to dynamically applying for permission at run time. This is an important change for Android developers.

Before discussing this issue, we need to check the target version of the project. If it is 23 or above, it must be adapted to the new permission mode. For those under 23, you will still be able to apply for all permissions at install – even so, Android 6.0 and above users can still disable some of your permissions in their Settings. When permissions are turned off, your application will not crash, but it will return a value of null or 0.

Here are some best practices from the Android website, with a quick translation and a few corrections if there are any.

The body of the

Apps can easily flood users with permission requests. If users find that the app affects their use or are concerned about the misuse of users’ personal information, they may stop using the app or delete it completely. The following best practices can help you avoid this poor user experience.

Use Intents first

In many cases, you can choose between two ways to accomplish tasks for your app. You can have your app request permission to do the action itself, or you can have your app use intent to let other apps do the job.

For example, if your app needs to take pictures with the CAMERA in the device, your app can request CAMERA permission to use the CAMERA component directly, and then your app will use the CAMERA component interface to control the CAMERA and take pictures. This method gives your app full control over the photography process and lets you incorporate the camera UI into your app.

However, if you don’t need such complete control, you can use ACTION_IMAGE_CAPTURE Intent to request images. When you send the intent, the system asks the user to select a camera app (if there is no default camera app already). When the user takes a photo with the selected camera app, it returns the photo back to your app’s onActivityResult() method.

Similarly, if you need to make a call, read or write a user’s address book, etc., you can do so by creating an intent that is appropriate, or by requesting permission to access the appropriate component directly. Both have advantages and disadvantages.

If you use permissions:

  • Your app has complete control over the user experience while doing this. But such broad controls add complexity to the task, because you need to design the appropriate UI yourself.
  • Users tend to do permissions only once, either at runtime or at the start of installation, after which your app can operate without additional permissions from the user. However, if the user does not have permission or cancels later, your app will never be able to do this.

If you use intent:

  • You don’t need to design the UI for this operation. The app that handles the Intent provides a UI. However, this means that you have no control over this part of the user experience. Users might be dealing with apps you don’t know anything about.
  • If the user does not have a default application to handle the operation, the system asks the user to select one. If the user does not specify a default processing, an additional selection dialog box pops up each time the operation is performed.

Apply for only required permissions

You’re forcing the user to make a decision every time you ask for permission, so you should reduce the number of times you make those requests. If the user is running Android 6.0 or later, the app must interrupt the user to request permission every time the user uses a feature in the app that requires permission. If the user is using the system before 6.0, the user must allow each permission when installing the app. Users may decide to stop installing your app if the permissions list is too long or looks inappropriate. Because of all this, you’d better reduce the number of permissions you apply for.

Don’t overwhelm users

Users using Android6.0 or later will need authorization to run the app. If you throw a bunch of permissions at users at once, you’ll overwhelm them and delete your app. So you should only ask for permission when necessary.

In some cases, one or more permissions are absolutely necessary to your app, and it makes sense to ask for them at app launch. Let’s say you make a photography app that uses a camera. When users start the app for the first time, they are naturally not surprised to ask for permission for the camera. But if the app also has the ability to share images from the user’s contacts, you shouldn’t get READ_CONTACTS permission when you first start the app. Instead, you should wait until the user uses the “share” feature to request permission.

Explain why you need access

The permissions dialog is displayed when you call requestPermissions() to indicate what permissions your app requires, but does not say why. In some cases, users get confused. It’s a good idea to explain to the user why your app needs these permissions before calling requestPermissions().

For example, a photo app might require a location service to geotagged images. An average user might not understand that an image can contain location information, and then wonder why a camera app would need to know where he is. So in this case, it’s a good idea for the app to tell the user about the feature before calling requestPermissions().

A good way to inform the user is to incorporate these permission requests into the app boot. The app boot can introduce the features of the app in turn, and while doing so, explain what permissions are required. For example, the camera app boot could demonstrate the “share photos through address book” feature, telling the user that they need to authorize the app to see the user’s address book. The app can then call requestPermissions() to request a read of the address book. Of course, not all users will follow the instructions, so you’ll still need to check and request permission in your daily use of the app.

Test both permission modes

Starting with Android 6.0, users grant or deny permissions when the app is running rather than when the app is installed, which leads you to test how the app performs under various conditions.

Prior to Android 6.0, you could reasonably assume that your app would always work and that it had all the permissions declared in the App Manifest. With the new access model, you can’t.

The following tips will help you verify permission related code issues for Android 6.0 and above.

  • Verify current app permissions and relevant code paths.

  • Test users use permissions to protect services and data.

  • Tests the combination of multiple permissions that are allowed or denied. For example, a CAMERA app might declare CAMERA, READ_CONTACTS, and ACCESS_FINE_LOCATION permissions in its manifest file. You should test each permission on and off to make sure your app handles all permissions gracefully. Remember that since Android 6.0 users can turn on or off permissions on any app, even those with the Targets API 22 or below.

  • Use adb tools to manage permissions from the command line:

    • Lists permissions and status in groups:

      $ adb shell pm list permissions -d -gCopy the code
    • To allow or deny one or more permissions:

      $ adb shell pm [grant|revoke] Copy the code
  • Analyze apps for services with permissions

Afterword.

These are the best practices from the Android website. In my opinion, this article focuses on best practices for permissions from a user experience perspective, and lacks practices at the code level, so it should be expanded.

Permission-specific code best practices

Step zero, declare the required permissions in the manifest file.

The first step is to check whether you have permissions.

API 23 or above all version
checkSelfPermission ContextCompat.checkSelfPermission()

Authorized functions return PERMISSION_GRANTED, otherwise PERMISSION_DENIED.

Second, check whether the application permission dialog box needs to be displayed. If there is no permission returned in the first step, we need to apply for permission, but before applying for permission, we need to display the dialog box to check whether the user has prohibited the application permission. If it is prohibited, the code in the third step will have no effect.

API 23 or above all version
shouldShowRequestPermissionRationale ActivityCompat.shouldShowRequestPermissionRationale / FragmentCompat.shouldShowRequestPermissionRationale

Return true or false, under 6.0 is always false, this need not be more explanation, under 6.0 there is no system default dialog box, definitely not pop.

Step 3, display a prompt box to apply for permission.

API 23 or above all version
requestPermissions ActivityCompat.requestPermissions/ FragmentCompat.requestPermissions()

After the request, will gain correction results in onRequestPermissionsResult method.

With the current Android distribution, the minimum recommended support is 4.0, so we can directly use the three methods in the compatibility library to work with all versions. Here is a simple requirement to write data to an SD card:

/ * * * * to the SD card inserted into the data/private void insertDataToSDCard () {if (ContextCompat. CheckSelfPermission (this, Manifest. Permission. WRITE_EXTERNAL_STORAGE) = = PackageManager. PERMISSION_GRANTED) {/ / have access to the SD card / / TODO write data} else { / / without permission, determine whether can play permissions apply for dialog Boolean shouldShow = ActivityCompat. ShouldShowRequestPermissionRationale (this, Manifest.permission.WRITE_EXTERNAL_STORAGE); If (shouldShow) {/ / application permissions ActivityCompat. RequestPermissions (this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_REQUEST_PERMISSION); } else {/ / are forbidden to display pop-up / / TODO dialog box to inform the user must open the permissions}}} @ Override public void onRequestPermissionsResult (int requestCode. @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == REQUEST_CODE_REQUEST_PERMISSION) { if (grantResults[0] == PackageManager. PERMISSION_GRANTED) {/ / permission granted to the SD card / / TODO write data} else {/ / permission denied / / TODO Displays a dialog telling the user that permissions must be turned on}}}Copy the code

Visible, through the compatibility library to do permission mode compatibility is quite simple and clear. For extensibility, the permission determination logic can be written as a generic utility class.

Finally, I recommend a third-party library hotchemi’s PermissionsDispatcher, which is also a good third-party library seen in Resources, if you are interested to have a look.

The resources

  1. Permissions Best Practices
  2. Android M’s new runtime permissions everything developers need to know