1. Authority Mechanism

Basic series: Android permission request mechanism, the logic is relatively simple, but the code to use, is particularly boring. And as the version changes, some permission requests will also change.

Permissions are meant to protect the privacy of Android users. Every Android runs in a sandbox with limited access. Whenever an application needs to use resources or information outside its sandbox, it must request corresponding permissions, such as dial-up and memory access.

In API22 and below, Android permissions are requested at install time, that is, when apK is installed, the required permissions are listed. If you agree, the installation is done; if you disagree, the installation is quit. Starting with API23 (Android6.0), Android began to use the run-time permission mechanism, ready-to-request. A SecurityException is thrown if the operation is performed without permission

1.1 Permission Type Division

Permission API reference page

1.1.1 Permission Levels

Permissions are classified into several protection levels, which directly affect whether you need to apply for runtime permissions.

Permissions are as follows:

  1. Common permissions, operations that have little impact on user privacy or risk, such as Internet permissions. This type of permission is automatically granted by the app after the application manifest is declared
  2. Dangerous permissions that may affect user privacy, such as reading contacts or reading and writing stored files. You need to apply for these permissions.
  3. The signature permission is granted only when the same signature file is declared.
  4. Special privileges,SYSTEM_ALERT_WINDOWWRITE_SETTINGSSuch permissions are special. If the user needs them, the user must send an intent requesting user authorization after the application manifest declaration, jump to the setting interface, and allow the user manually
Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
intent.setData(uri);
startActivityForResult(intent, 2);
Copy the code

For details about the type of permission, see the Permission API reference page

1.1.2 permissions set

Any permission can belong to a certain permission group. If an application has been granted another dangerous permission in the same permission group, the system grants the permission immediately without pop-up application box. If an application has previously requested and been granted READ_CONTACTS permission, and then requests WRITE_CONTACTS, the system automatically grants that permission

Android10 You can obtain permissions by the following methods:

context.packageManager.getPermissionInfo(permission, 0)
Copy the code

Android10 and above, remove permission group query, can only maintain a dangerous permission mapping table (the following code transferred from Guo Shen) :

/ * * * Based on this link https://developer.android.com/about/versions/10/privacy/changes#permission-groups-removed
 * Since Android Q, we can not get the permission group name by permission name anymore.
 * So we need to keep a track of relationship between permissions and permission groups on every Android release since Android Q.
* /
@TargetApi(Build.VERSION_CODES.Q) fun getPermissionMapOnQ(a) = mapOf(  Manifest.permission.READ_CALENDAR to Manifest.permission_group.CALENDAR,  Manifest.permission.WRITE_CALENDAR to Manifest.permission_group.CALENDAR,  Manifest.permission.READ_CALL_LOG to Manifest.permission_group.CALL_LOG,  Manifest.permission.WRITE_CALL_LOG to Manifest.permission_group.CALL_LOG,  Manifest.permission.PROCESS_OUTGOING_CALLS to Manifest.permission_group.CALL_LOG,  Manifest.permission.CAMERA to Manifest.permission_group.CAMERA,  Manifest.permission.READ_CONTACTS to Manifest.permission_group.CONTACTS,  Manifest.permission.WRITE_CONTACTS to Manifest.permission_group.CONTACTS,  Manifest.permission.GET_ACCOUNTS to Manifest.permission_group.CONTACTS,  Manifest.permission.ACCESS_FINE_LOCATION to Manifest.permission_group.LOCATION,  Manifest.permission.ACCESS_COARSE_LOCATION to Manifest.permission_group.LOCATION,  Manifest.permission.ACCESS_BACKGROUND_LOCATION to Manifest.permission_group.LOCATION,  Manifest.permission.RECORD_AUDIO to Manifest.permission_group.MICROPHONE,  Manifest.permission.READ_PHONE_STATE to Manifest.permission_group.PHONE,  Manifest.permission.READ_PHONE_NUMBERS to Manifest.permission_group.PHONE,  Manifest.permission.CALL_PHONE to Manifest.permission_group.PHONE,  Manifest.permission.ANSWER_PHONE_CALLS to Manifest.permission_group.PHONE,  Manifest.permission.ADD_VOICEMAIL to Manifest.permission_group.PHONE,  Manifest.permission.USE_SIP to Manifest.permission_group.PHONE,  Manifest.permission.ACCEPT_HANDOVER to Manifest.permission_group.PHONE,  Manifest.permission.BODY_SENSORS to Manifest.permission_group.SENSORS,  Manifest.permission.ACTIVITY_RECOGNITION to Manifest.permission_group.ACTIVITY_RECOGNITION,  Manifest.permission.SEND_SMS to Manifest.permission_group.SMS,  Manifest.permission.RECEIVE_SMS to Manifest.permission_group.SMS,  Manifest.permission.READ_SMS to Manifest.permission_group.SMS,  Manifest.permission.RECEIVE_WAP_PUSH to Manifest.permission_group.SMS,  Manifest.permission.RECEIVE_MMS to Manifest.permission_group.SMS,  Manifest.permission.READ_EXTERNAL_STORAGE to Manifest.permission_group.STORAGE,  Manifest.permission.WRITE_EXTERNAL_STORAGE to Manifest.permission_group.STORAGE,  Manifest.permission.ACCESS_MEDIA_LOCATION to Manifest.permission_group.STORAGE )  / * * * Thankfully Android R has no permission added or removed than Android Q. * / @TargetApi(Build.VERSION_CODES.R) fun getPermissionMapOnR(a) = getPermissionMapOnQ()  . val permissionGroup = when(currentVersion) {  Build.VERSION_CODES.Q -> {  getPermissionMapOnQ()[permission]  }  Build.VERSION_CODES.R -> {  getPermissionMapOnR()[permission]  }  else- > { val permissionInfo = context.packageManager.getPermissionInfo(permission, 0)  permissionInfo.group  }  } Copy the code

1.2 Permission Request Process

1.2.1 Permission Statement

The permissions required by the application must be declared in the application manifest androidmanifest.xml through

, such as reading and writing mobile phone storage, and using the Internet:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.snazzyapp">

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  <uses-permission android:name="android.permission.INTERNET" />   <application .> . </application> </manifest> Copy the code

For ordinary permissions, such as android. Permission. The INTERNET, in the application list, the statement can be automatically after this dangerous permissions for read/write phone storage space, you will need to request dynamically at runtime

1.2.2 Checking Permission Status

Every time dangerous permissions are needed, they should be checked and applied for. Users can revoke previously granted permissions at any time.

Check whether has awarded special privileges, could be used to transmit the permissions to ActivityCompat. CheckSelfPermission () method. Success will return PackageManager PERMISSION_GRANTED, failure is the PackageManager. PERMISSION_DENIED.

Application permission to have a more interesting way, it will prompt the developers, whether to need to show some bounced why want to apply for permission, so as to improve the human experiences of products: ActivityCompat. ShouldShowRequestPermissionRationale ()

This method returns true only when the user rejects the permission request and does not click “Ask no more”. When used in actual development, it can be used to determine whether the user has checked “no longer ask”, so as to jump to the setting interface, and the user can manually grant permission

1.2.3 Permission Request

(1) Traditional permission request:

Traditional permission requests are relatively cumbersome:

ActivityCompat.requestPermissions(
    this.    arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE),
    REQUEST_CODE
)
Copy the code

Call this method to request permission. The result of the permission is obtained by overriding the method:

override fun onRequestPermissionsResult(
    requestCode: Int.    permissions: Array<out String>,
 grantResults: IntArray ) {
  if(requestCode ! = REQUEST_CODE) {// Request code Determines whether it is a sent permission request  super.onRequestPermissionsResult(requestCode, permissions, grantResults)  return  }   for (i in permissions.indices) {  if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {  Log.e("Small new"."Obtain permission:${permissions[i]}")  }  } } Copy the code

Traditional permission request, is more cumbersome, can not be called chain, but also have to separate judgment, seriously reduce the code readability.

(2) new registerForActivityResult API request

Still, Fantessy happens to have an article about the new API: Bye! OnActivityResult! Hello, Activity Results API!

In response, Jetpack has a new permission request API (currently in beta) to simplify the request process ->

First declare dependencies:

    dependencies {
        
        // Java 
        implementation "Androidx. Activity: the activity: 1.2.0 - beta01"  
        implementation 'androidx. Fragments: fragments: 1.3.0 - beta01'
  // Kotlin  implementation "Androidx. Activity: activity - KTX: 1.2.0 - beta01"  implementation 'androidx. Fragments: fragments - KTX: 1.3.0 - beta01'   } Copy the code

Note:

  • Need to request a permission, useRequestPermission.
  • Need to request multiple permissions at the same time, useRequestMultiplePermissions.

Register ActivityResultCallback in the initialization logic of your Activity or Fragment. To retain registerForActivityResult () (type ActivityResultLauncher) as the return value of reference. Then call the launch() method of the saved ActivityResultLauncher instance where you need to apply.

.val requestPermissionLauncher =
    registerForActivityResult(RequestPermission()
    ) { isGranted: Boolean ->
        if (isGranted) {
 / / by  } else {  / / deny  }  }  . requestPermissionLauncher.launch(  Manifest.permission.WRITE_EXTERNAL_STORAGE) Copy the code

(3) Jump to the APP setting interface

When the user rejects the request and clicks “No more ask”, the application is directly returned after passing the above request. In this case, the user can only switch to the user-related Settings interface, and the user can manually click authorization

val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
val uri = Uri.fromParts("package".this.packageName, null)
intent.data = uri
startActivityForResult(intent, FORWARD_TO_SETTING_CODE)
Copy the code

Custom permissions

2.1 Application Scenarios

Custom permissions are generally used for exposed components to improve security. Android allows one application (client) to call components of another application (server). Then the server application must expose the corresponding component so that the client application can access it. For exposed components, permissions are not necessary, if the exposed component does not have permissions, then any other application can call the component, relatively insecure; If the component has requested permission, only the application that has that permission can invoke the component.

<activity android:name=".MainActivity"
    android:exported="true">
.Copy the code

For such undeclared permissions, any other app can start the activity (explicitly or implicitly).

//intent.setClassName(intent.setclassName)
intent.setClassName("com.cyq.clockout"."com.cyq.clockout.MainActivity")
Copy the code

If a third-party app starts an activity without permission, a permission failure exception will be thrown

<activity android:name=".MainActivity"
    android:exported="true"
    android:permission="com.cyq.TEST">
.Copy the code

2.2 Creating user-defined Rights

To create custom permissions, declare them in the app’s Androidmanifest.xml with the < Permission > element

<permission
    android:name="com.cyq.TEST"
    android:description="@string/des"
    android:label="@string/label"
 android:protectionLevel="dangerous"  android:permissionGroup="android.permission-group.LOCATION"/> Copy the code
  • Android :protectionLevel: level of declared permissions;

  • Android: permissionGroup: authority’s privilege group, in most cases, should be set up for android’s own standard system group (in android. The Manifest. Permission_group listed), but can also define your own privilege groups. Such as example using Android’s own position permissions set to do apply for, when access to apply for ActivityCompat. RequestPermissions, you will be prompted with the permissions associated set of box

  • You also need to provide labels and descriptions for permissions. These are users looking at the permission list (android:label) or details about individual permissions (android:description)String resource. Label is visible when viewing application permission Settings, while description is visible in the pop-up description box when clicking permission.

Graph: the tag


Chart:

Iii Reference Links

  1. Request app permissions
  2. Good bye! OnActivityResult! Hello, Activity Results API!

Thank you four ❤ ️

  1. If you find this post helpful, give it a thumbs up (👍).
  2. About error correction and suggestions: Welcome to share the record directly in the message (🌹)

– END –