0 . Preface
recently interned at the Institute, I am responsible for maintaining Android Mobile forensics project android client, we have clients that reflect our app android6.0 No response, Debug found SD The card read and write permission is denied. But obviously in androidmanifest.xml Declared in the file. I got a lot of data to find out. android6.0
Note: When running a program, ask the user for certain permissions (later in detail) because we know that the customer APP Do not click "Deny", so my implementation of this feature is limited to the first part of the article to do the dead loop until the user agrees to authorize the permission, because of course the lowest cost to meet the customer's needs best, but the real development, need to deal with a lot of things, I also did not scratch, the back will using the Onrequestpermissionsresult callback method, Shouldshowrequestpermissionrationale method and so on, can avoid a lot of user distress situation. This will be explained in detail later.
I also spent a full two days to understand and summarize the whole process of the compatible Android6.0 Rights management mechanism, and also to make it easy for us to encounter similar problems and less detours.
1 . Android 6.0 New rights management mechanism
Android 6.0 Marshmallow version, the system Some dangerous levels of permissions , when running those targetsdkversion set to at and the at the above application and when these permissions are required, a ask the user whether to grant permissions . If you do not ask to use these permissions directly, an exception log similar to java.lang.SecurityException:Permission denial appears .
Applicationtargetsdkversionif not set to atversion or above, the system will still use the old rule: when installed, give theappall the permissions that were requested. It does not affect the normal use of the previous application, but6.0later, the user can<Set-Permissions>will be in theAPPSome of the permissionsManual Shutdown, at which time the user is forbidden permissionAPIthe interface return value isNULLor0, we can preventApp Crash.
If the app is running, manually shut down the permissions in the settings, it will be crash directly.
2 . List of dangerous permissions
The previously mentioned hazard level permissions are of particular concern to us, because they require special handling before they are used.
There is a concept of a permission group, any one of the permissions in the same group is authorized, and the other permissions are automatically authorized.
For example, once Write_external_storage have been authorized, APP And Then there's the Read_external_storage permissions.
3 . Android 6.0 active request permission at runtime
3.1 detection and application permissions
The following example shows the read/write SD card examples of use can be resolved using the following methods:
public boolean ISGRANTEXTERNALRW (activity activity) { if (Build.VERSION.SDK_INT >= build.version_codes. M && activity.checkselfpermission ( Manifest.permission.WRITE_EXTERNAL_STORAGE)! = packagemanager.permission_granted) { activity.requestpermissions (new string[]{ Manifest.permission.READ_ External_storage, Manifest.permission.WRITE_EXTERNAL_STORAGE }, 1); Return false;//first opens the app and performs a permission check, although it returns false, but the method for requesting permission has been called } return true;//not the first time you open the app and perform a permission check. Or Android version under 6.0}
It is to be explained here that the methods of checking and applying for permissions are Activity.checkselfpermission () and activity.requestpermissions respectively, and the two methods are API New in the.
activity.checkselfpermission () used primarily to detect whether a permission has been granted, method returns a value of Packagemanager.permission_denied or packagemanager.permission_granted . When returning to DENIED , a request for authorization is required.
activity.requestpermissions The method is asynchronous, the first parameter is a A string array of permissions to request , the second parameter is Requestcode , mainly used to detect when callbacks are . The first parameter can be passed into the mactivity. It doesn't seem to pass.
can be from the method name requestpermissions and the second parameter shows that it is Support One-time application for multiple permissions , the system will use the dialog box ask the user for authorization individually.
Then, when you need to use this permission , make the following call.
Boolean isgrant= ISGRANTEXTERNALRW (mactivity); if (isgrant) { //business logic} while (!isgrant) { try { thread.sleep ()} catch (Interruptedexception e) { E . Printstacktrace ();} Isgrant = ISGRANTEXTERNALRW (MACT); if (isgrant) { //business logic }}
This is because the return value of the ISGRANTEXTERNALRW method that we write is only the state that determines when the permission is checked at the beginning , so if it is the first time the app is opened, it returns false, and the permission is applied (if the user agrees), Call again this method returns True, enters the logic code, and finally jumps out of the while loop. If the user has been authorized, then the logic code will go directly. Here the rogue is, if the user has been not agree, will always return false, we will block in the while loop, after a second to continue to apply until the user agrees. Obviously it's not friendly enough.
So Google to prevent this situation, when the user refused authorization, the next pop-up window can be checked "no longer remind." If this option is checked by the user. The next time you request requestpermissions for this permission , the dialog box will not pop up, and the system would call back directly callback method that processes the return result of the request Onrequestpermissionsresult, the callback result is the last user's choice.
3.2 processing permission request callback
@Overridepublic void Onrequestpermissionsresult (int requestcode, String permissions[], int[] grantresults) { Switch (requestcode) { Case 1: { //User de-authorization this array is empty, if you apply for two permissions at the same time, then grantresults length is 2, record your application results of two permissions respectively if (Grantresults.length > 0 && grantresults[0] = = packagemanager.permission_granted) { //business logic } else { //authorization denied, no longer function based on this permission } return; Other case processing request callback for other permissions }}
The method of handling the application callback above has been written very clearly. There is the option to call back the method regardless of whether or not the user clicks on it (don't forget that the user has rejected and checked "no reminders").
3.3 using the Shouldshowrequestpermissionrationale method
The problem comes, if the second time to request permission to the user is denied, and the user tick "no longer remind", then each time we need to use this permission will be rejected directly, and will not pop up the dialog box. The app does nothing to create a poor user experience. So this situation requires us to deal with it. At this time we can use the Shouldshowrequestpermissionrationale method. First look at the return value of the method.
Therefore, we do permission detection in the callback function , if return denied, call the above method, return False, the popup dialog to guide the user to manually open the permissions, to avoid the user's actions triggered the permission request mechanism (has been rejected and checked no longer remind or manually shut down permissions), But there was no embarrassment of responding. And because we have previously asked the user for authorization, there is no first case in the table.
So just add the following code to the Else code snippet of the callback code above.
if (!mactivity.shouldshowrequestpermissionrationale (this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { User has completely rejected, or manually closed permissions//Open this dialog box to ease the embarrassment ... Alertdialog dialog = new Alertdialog.builder (this). Setmessage ("Do not turn on this permission will not work properly, please open it manually in Settings!") "). Setpositivebutton (" OK ", new Dialoginterface.onclicklistener () { @Override public void OnClick (Dialoginterface dialog, int which) { Finish (); }}). Setnegativebutton ("Cancel", new Dialoginterface.onclicklistener () {@Override public void OnClick (dialoginterface dialog, int which) {finish (); }}). Create (); Dialog.show (); Return }else{//user has been refused and always uncheck "no more reminders"//toast remind you can}
When permissions are required, simply execute code similar to the following check and request permissions (note that you are replacing Contentcompat):
if (Build.VERSION.SDK_INT >= build.version_codes. M && contextcompat.checkselfpermission (context, Manifest.permission.WRITE_EXTERNAL_STORAGE)! = packagemanager.permission_granted) { activitycompat.requestpermissions (context, new string[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE}, Request_code); } else { //do the stuff that requires permission ...}
Android Development--android 6.0 Rights Management mechanism detailed