• Permissions — Part 1
  • The Nuggets translation Project
  • Translator: Hugo Xie
  • Proofread by BOBO, Markzhai

Due to the introduction of a new permissions model by Marshmallow (Android 6.0), Android developers need to take a different approach to obtaining Android permissions. In this series, we will explain how to handle requests for permissions from a technical perspective and how to provide a smooth user experience.





Before we get bogged down, it’s important to clarify one of two situations in which an application must claim permissions: those permissions are central to how the application runs — if it doesn’t claim those permissions, the application won’t work. For example, for a camera app,CAMERAPermissions are part of the core functionality, and a camera app is useless if it can’t take pictures. However, there may be other features, such as marking images with locations (neededACCESS_FINE_LOCATIONPermissions), which is a nice feature, but applications can run without location permissions.

So for the next series of articles, and to get everyone ready to start making apps, you need to apply for the following two permissionsRECORD_AUDIO and MODIFY_AUDIO_SETTINGS. In order to get those permissions, as we always do, you need to be inManifestThe document states that they.

AndroidManifest.xml




  
  

  

    

    
      
        

        
      
    
  


Copy the code

Since API1\ this has become a standard way to request permissions in Android. However, from targetSdkVersion 23 or later, we also need to request the permissions we need at run time. This is important because many developers have simply set targetSdkVersion to the latest in their examples, and then found their applications crashed because they didn’t implement the necessary code to request permissions during application execution. The problem is that once you release an app with a target API of 23 to Google Play, then you can’t replace it with an APK with an earlier target API. Another thing worth mentioning at this point is that there are already libraries designed to simplify the process of requesting permissions at run time. These libraries vary in code quality and effectiveness, but I feel it’s important to understand the underlying process before using this type of library, otherwise you may run into problems because you don’t really know what the library you’re using actually does. This is the main motivation for this series of articles. We need these two permissions to actually fall into two different categories: RECORD_AUDIO is considered a high-risk permission, and MODIFY_AUDIO_SETTINGS is considered a normal permission. High-risk permissions may compromise security or privacy; Although a normal permission is given to access resources outside the application domain, the user has little or no privacy risk. Normal permissions are automatically granted by the system, while high-risk permissions need to be explicitly granted to your application during operation.

The first thing we need to do is this part of the process to determine if we’ve got the permissions we need. In API 23, a new method is added to Context to check whether a particular permission has been granted.

However, instead of accessing the Context directly, it is now recommended to use ContextCompat, including your own apI-level check: permissionChecker.java

class PermissionsChecker { private final Context context; public PermissionsChecker(Context context) { this.context = context; } public boolean lacksPermissions(String... permissions) { for (String permission : permissions) { if (lacksPermission(permission)) { return true; } } return false; } private boolean lacksPermission(String permission) { return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_DENIED; }}Copy the code

This is actually pretty straightforward — the ContextCompat#checkSelfPermission method is easy to understand, Unauthorized returns the PackageManager. PERMISSION_DENIED has authorized returns PackageManager. PERMISSION_GRANTED. I added some further logic to the app to do just that: detect any unauthorised but necessary permissions.

It’s worth reiterating what ContextCompat can do for us here. CheckSelfPermission () when running on devices that did not support the new run permission model before Marshmallow (Android6.0) (permissions were implicitly granted on older systems) The packagemanger.permission_granted method always returns packagemanger.permission_granted. Because of the Manifest declaration, we only need to call a method that runs on all versions of the system, and we don’t need to write any API-level checks in our own code.

We created a concrete class for this purpose because we will need to do these checks in all activities in the app in the future, so separating the checking logic from the activity reduces repetitive code and improves maintainability.

So in practice in our Activity, we can simply call it a list of permissions requested by the Activity.

MainActivity.java

public class MainActivity extends AppCompatActivity { private static final String[] PERMISSIONS = new String[] {Manifest.permission.RECORD_AUDIO, Manifest.permission.MODIFY_AUDIO_SETTINGS}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); PermissionsChecker checker = new PermissionsChecker(this); if (checker.lacksPermissions(PERMISSIONS)) { Snackbar.make(toolbar, R.string.no_permissions, Snackbar.LENGTH_INDEFINITE).show(); }..}}Copy the code

It’s very simple in practice.

Effect on devices prior to Marshamllow (Android ID 6.0) :

But we haven’t dealt with the missing permissions for Marshamllow (Android 6.0) and later versions — just showing a Snackbar:

Requesting missing permissions is a very complex process that we’ll cover in the next article.

The source code for this article is available here.