Android dynamic rights management

preface:

During the continuous upgrading of the Android system, the development of Android applications also has different changes. For permissions, Android 6 In systems above 0, runtime permission check is introduced. Runtime permission is divided into normal permission and dangerous permission. When our App calls an api requiring dangerous permission, we need to apply for permission from the system. The system will pop up a dialog box for users to perceive. Only after the user authorizes, can the App call the api normally.
All current permission categories can be referenced https://developer.android.google.cn/reference/android/Manifest.permission?hl=zh-cn
If you determine that your application must access restricted data or perform restricted operations to implement a use case, please declare the corresponding permissions. Some permissions are automatically granted when users install applications, which are called installation permissions. Other permissions require the application to further request permissions at runtime. Such permissions are called runtime permissions.

Figure 1 Summary workflow diagram of using permissions in Android.

Permission classification

  • Install time permissions

    Figure 2 The installation time permission list of an app displayed in an app store.
    Figure 2 shows the installation permission list of an application. The figure on the right shows a pop-up dialog box with two options: allow and deny.

During installation, the permission grants the application limited access to restricted data, and allows the application to perform restricted operations that have minimal impact on the system or other applications. If you declare the installation permission in the application, the system will automatically grant the application the corresponding permission when the user installs your application. The app store will display the permission notification during installation to users when they view the application details page, as shown in Figure 2.

Android provides multiple installation time permission subtypes, including normal permission and signature permission.

  • General permissions

Such permissions allow access to data beyond the application sandbox and perform operations beyond the application sandbox. However, these data and operations pose little risk to user privacy and operations on other applications.

The system assigns "normal" protection level to normal permissions, as shown in the permissions API reference document page.

  • Signing authority

When an application declares the signing permission defined by other applications, if two applications sign with the same certificate, the system will grant the permission to the former during installation. Otherwise, the system cannot grant this permission to the former.
Version compatible

  • Runtime permissions

A pop-up dialog box with 2 options: allow and deny.
Runtime permissions, also known as dangerous permissions, grant applications additional access to restricted data and allow applications to perform restricted operations that have a more serious impact on the system and other applications. Therefore, you need to request runtime permission in the application before you can access restricted data or perform restricted operations. When the application requests the runtime permission, the system will display the runtime permission prompt, as shown in Figure 3.

Figure 3 System permission prompt displayed when the application requests run-time permission.

Many runtime permissions access user private data, which is a special kind of restricted data that contains potentially sensitive information. For example, location information and contact information belong to user private data.

The system assigns a "dangerous" protection level to runtime permissions, as shown in the permissions API reference document page.
This chapter mainly describes the application of runtime permission.

  • special competencies

Special permissions correspond to specific application operations. Only platform and original equipment manufacturers (OEMs) can define special permissions. In addition, if the platform and OEM want to prevent someone from performing particularly powerful operations (such as drawing through other applications), special permissions are usually defined.

The special application access permission page in system settings contains a group of operations that users can switch. Many of these operations are implemented in the form of special permissions.

Each special permission has its own implementation details. For instructions on using each special permission, visit the permissions API reference documentation page. The system assigns "appop" protection level to special permissions.

Apply for permission

  • basic principle

The basic principles of requesting permission at run time are as follows:

When the user starts to interact with the function requiring relevant permission, he / she requests permission in the specific use context.
Do not prevent users from using the app. Always provide the option for the user to cancel the permission related guidance interface process.
If the user denies or revokes the permission required by a function, please demote your application appropriately so that the user can continue to use your application (possibly by disabling the function requiring permission).
Don't make any assumptions about system behavior. For example, suppose some permissions appear in the same permission group. The function of permission group is to help the system reduce the number of system dialog boxes displayed to users as much as possible when applying multiple permissions closely related to requests.

  • Request permission

Application permissions are based on system security functions. The best practice is to associate runtime permissions with specific operations and postpone them as far as possible to request permissions in the use case process of the application. For example, if the application allows users to send voice messages to others, wait until the user has navigated to the message screen and pressed the send voice message button before requesting permission. After the user presses this button, the application will request permission to use the microphone.
Registration authority
To declare the permissions that the application may request, please add corresponding elements to the manifest file of the application. For example, an application that needs to access a camera should add the following line of code to the list:

<manifest ...>
    <uses-permission android:name="android.permission.CAMERA"/>
    <application ...>
        ...
    </application>
</manifest>

Application process

  • In the manifest file of the application, declare that the application may need the requested permission.

  • Design the user experience of the application to associate specific operations in the application with specific runtime permissions. You should let users know what actions might require them to grant access to their private data to your application.

  • Wait for the user to call the task or operation in the application that needs to access the private data of a specific user. At that time, your application can request the runtime permissions required to access the corresponding data.

  • Check whether the user has granted the runtime permissions required by the application. If authorized, your app can access the user's private data. If not, proceed to the next step.
    Each time you perform an operation that requires this permission, you must check whether you have this permission.

  • Check whether your application should show the user the reason why your application needs the user to grant specific runtime permissions. If the system determines that your application should not display reasons, please continue to the next step directly without displaying interface elements.
    However, if the system determines that your application should display a reason, please display the reason to the user in the interface element, clearly stating what data your application is trying to access and what benefits the application can provide to the user after obtaining runtime permission. After the user confirms the reason, please continue to the next step.

  • Request the runtime permissions your app needs to access the user's private data. The system displays runtime permission prompts, such as those displayed on the permission overview page.

  • Check the user's response and they may choose to agree or refuse to grant runtime permissions.

  • If the user grants permission to your application, you can access the user's private data. If the user refuses to grant the permission, please appropriately reduce the application experience so that the application can provide functions to the user without obtaining the information protected by the permission.

    Figure 1 illustrates the workflows and decision groups associated with this process
    targetSDK

native method

Android system provides us with basic permission application methods for Android development, including

  • Determine whether the app has been granted permission

Use the system method contextcompat Checkselfpermission() and pass in the permission to check. Depending on whether your application has corresponding permissions, this method will return PERMISSION_GRANTED or PERMISSION_DENIED.

  • Explain why permission is required

If contextcompat The checkselfpermission() method returns PERMISSION_DENIED, shouldshowrequestpermissionrational() can be called. This method is called directly in activity and fragment. If this method returns true, please display the guidance interface to the user, which explains why the function you want to enable requires specific permissions.

  • Request permission

After the user views the guidance interface or the return value of shouldshowrequestpermissionrational () indicates that you do not need to display the guidance interface this time, you can request permission. The user will see the system permissions dialog box and can choose whether to grant specific permissions to your application.
ActivityCompat.requestPermissions(activity, permissions, requestCode);
As always, you can manage the request code in the permission request process and include it in your permission callback logic.

Open source framework

Due to the complexity of Android dynamic permission application and more code, there are many open source frameworks to help us develop. We can learn the use of open source frameworks.

  1. EasyPermission

Why mention this library first? Its GitHub address is: https://github.com/googlesamples/easypermissions .
Officially, the most deadly. The code example demo is shown below. In fact, there are still many codes, but because there are many official considerations, there must be no problem in the process. Moreover, the compatibility between android support and Android x is fully considered, but the customizability is not so high. Because there are many native methods, they rely on onActivityResult and onRequestPermissionsResult, resulting in too much code.

public class MainActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks,EasyPermissions.RationaleCallbacks{
    private static final int RC_CAMERA_PERM = 123;
    private static final int RC_LOCATION_CONTACTS_PERM = 124;

    @AfterPermissionGranted(RC_CAMERA_PERM)
    public void cameraTask() {
        EasyPermissions.requestPermissions(
            this,
            getString(R.string.rationale_camera),
            RC_CAMERA_PERM,
            Manifest.permission.CAMERA);
    }

    @AfterPermissionGranted(RC_LOCATION_CONTACTS_PERM)
    public void locationAndContactsTask() {
        EasyPermissions.requestPermissions(
            this,
            getString(R.string.rationale_location_contacts),
            RC_LOCATION_CONTACTS_PERM,
            LOCATION_AND_CONTACTS);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }

    @Override
    public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
        Log.d(TAG, "onPermissionsGranted:" + requestCode + ":" + perms.size());
    }

    @Override
    public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
        if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
            new AppSettingsDialog.Builder(this).build().show();
        }
    }
}
  1. XXPermissions
    Chain call mode, and in addition to the native dependencies onActivityResult and onRequestPermissionsResult, the number of Activity and fragment codes is reduced. github address: https://github.com/getActivity/XXPermissions
    And it adapts to the compatibility of each Android version and the application of version related permissions. Its claimed highlights are:
  • The first and only permission request framework adapted to Android 11
  • The first and only permission request framework for all Android versions
  • Simple and easy to use: chain call is adopted, and only one sentence of code is needed
  • Touching volume: the function is the most complete in the similar framework, but the volume is the smallest
  • Adapt to extreme situations: no matter how severe the environment is, the framework is still strong
  • Downward compatibility attribute: new permissions can be applied normally in the old system, and the framework will automatically adapt without the need for the caller to adapt
  • Automatic error detection: if a low-level error occurs, the framework will actively throw an exception to the caller (judge only under Debug and kill the Bug in the cradle)
    A table is made to compare many other permission databases to prove their advantages. It is up to you to decide whether to use it or not.

    The code examples used are as follows:
XXPermissions.with(this)
        // Request installation package permission
        //.permission(Permission.REQUEST_INSTALL_PACKAGES)
        // Apply for suspended window permission
        //.permission(Permission.SYSTEM_ALERT_WINDOW)
        // Request notification column permission
        //.permission(Permission.NOTIFICATION_SERVICE)
        // Apply for system setting permission
        //.permission(Permission.WRITE_SETTINGS)
        // Request a single permission
        .permission(Permission.RECORD_AUDIO)
        // Request multiple permissions
        .permission(Permission.Group.CALENDAR)
        .request(new OnPermissionCallback() {

            @Override
            public void onGranted(List<String> permissions, boolean all) {
                if (all) {
                    toast("Successfully obtained recording and calendar permissions");
                } else {
                    toast("Some permissions were obtained successfully, but some permissions were not granted normally");
                }
            }

            @Override
            public void onDenied(List<String> permissions, boolean never) {
                if (never) {
                    toast("Permission is permanently denied. Please grant recording and calendar permission manually");
                    // If it is permanently rejected, jump to the application permission system setting page
                    XXPermissions.startPermissionActivity(MainActivity.this, permissions);
                } else {
                    toast("Failed to obtain recording and calendar permissions");
                }
            }
        });

  1. PermissionX

github address: https://github.com/guolindev/PermissionX
The first thing you should remember about this library is the author, Guo Lin (the first line of code). Have you read his book.
As a great God, its open source library is certainly worth using.
This library also uses chained calling, which is one step in place, and also removes the dependence on the native interface in easypermission. Users only need to use the following code, and encapsulates the interface for prompting users and opening settings. The UI can be customized, and is compatible with some new system permissions. A direct application interface is set, which can be called directly, It reduces the user's customization of special dangerous permissions.

PermissionX.init(activity)
    .permissions(Manifest.permission.READ_CONTACTS, Manifest.permission.CAMERA, Manifest.permission.CALL_PHONE)
    .onExplainRequestReason { scope, deniedList ->
        scope.showRequestReasonDialog(deniedList, "Core fundamental are based on these permissions", "OK", "Cancel")
    }
    .onForwardToSettings { scope, deniedList ->
        scope.showForwardToSettingsDialog(deniedList, "You need to allow necessary permissions in Settings manually", "OK", "Cancel")
    }
    .request { allGranted, grantedList, deniedList ->
        if (allGranted) {
            Toast.makeText(this, "All permissions are granted", Toast.LENGTH_LONG).show()
        } else {
            Toast.makeText(this, "These permissions are denied: $deniedList", Toast.LENGTH_LONG).show()
        }
    }
  1. RxPermissions
    Many people are used to RXjava and RXAndroid. They have a special preference for this kind of responsive programming. If there is a demand, someone will provide it. If not, it is your chance to become famous.
    github address: https://github.com/tbruyelle/RxPermissions
    An example of its use is also attached here. Those who need RX can choose:
rxPermissions
    .requestEachCombined(Manifest.permission.CAMERA,
             Manifest.permission.READ_PHONE_STATE)
    .subscribe(permission -> { // will emit 1 Permission object
        if (permission.granted) {
           // All permissions are granted !
        } else if (permission.shouldShowRequestPermissionRationale)
           // At least one denied permission without ask never again
        } else {
           // At least one denied permission with ask never again
           // Need to go to the settings
        }
    });
  1. PermissionsDispatcher
    It has to be said that there are annotation processing methods everywhere. Today, with the popularity of various annotation frameworks, the dynamic permission library is also inseparable from the open source library of annotation method, which has the advantage of more concise code.
    github address: https://github.com/permissions-dispatcher/PermissionsDispatcher
    However, this annotation has a disadvantage that each time you use it, you need to annotate the corresponding pop-up prompt or open the system setting method? Because I didn't use it, I won't comment much. It's OK, not as I thought. However, it has to be said that it is a very distinctive framework and an indispensable category in our development and use habits.
    Code examples are as follows:
@RuntimePermissions
class MainActivity : AppCompatActivity(), View.OnClickListener {

    @NeedsPermission(Manifest.permission.CAMERA)
    fun showCamera() {
        supportFragmentManager.beginTransaction()
                .replace(R.id.sample_content_fragment, CameraPreviewFragment.newInstance())
                .addToBackStack("camera")
                .commitAllowingStateLoss()
    }

    @OnShowRationale(Manifest.permission.CAMERA)
    fun showRationaleForCamera(request: PermissionRequest) {
        showRationaleDialog(R.string.permission_camera_rationale, request)
    }

    @OnPermissionDenied(Manifest.permission.CAMERA)
    fun onCameraDenied() {
        Toast.makeText(this, R.string.permission_camera_denied, Toast.LENGTH_SHORT).show()
    }

    @OnNeverAskAgain(Manifest.permission.CAMERA)
    fun onCameraNeverAskAgain() {
        Toast.makeText(this, R.string.permission_camera_never_askagain, Toast.LENGTH_SHORT).show()
    }
}

Other frameworks are not listed one by one. Many are still very characteristic.

Jetpack

jetpack unifies the Jianghu.
The main purpose of the previous support package and the current Android X and jetpack packages is to unify the development mode and avoid more and more frameworks in the market. Are you convinced? The advantages are also significant, but the official can only give you the most core improvements. For some attached benefits, the official may not do it. This is also the advantage of other open source frameworks, such as the background permission of Android 11, which requires various condition detection.
In fact, this is not a special permission library. With the expansion of the application, onActivityResult callback methods are nested, seriously coupled and difficult to maintain. Android discards startActivityForResult and onActivityResult methods.
If the jetpack Library of the new activity and fragment is used, the Activity Results API is the officially recommended way for activity and fragment to obtain data.

implementation 'androidx.activity:activity:1.2.0-beta01'
implementation 'androidx.fragment:fragment:1.3.0-beta01'

Although it is not specifically open for applying for permission, it also provides a new method for applying for permission.
Create a new Contract class, which inherits from activityresultcontract < I, O >, where I is the input type and O is the output type. Two methods need to be implemented, createIntent and parseResult. The input type I is used as the parameter of createIntent and the output type O is used as the return value of parseResult method. In the following example, the input and output types are String:
Google predefines many contracts and basically thinks of all the usage scenarios you can think of. They are all defined in the class ActivityResultContracts. There are the following contracts:

request_permission.setOnClickListener {
    requestPermission.launch(permission.CAMERA)
}

request_multiple_permission.setOnClickListener {
    requestMultiplePermissions.launch(
        arrayOf(
            permission.BLUETOOTH,
            permission.READ_CONTACTS,
            permission.ACCESS_FINE_LOCATION
        )
    )
}
// Request individual permissions
private val requestPermission =
    registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
        // Do something if permission granted
        if (isGranted) toast("Permission is granted")
        else toast("Permission is denied")
    }

// Request a set of permissions
private val requestMultiplePermissions =
    registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions : Map<String, Boolean> ->
        // Do something if some permissions granted or denied
        permissions.entries.forEach {
            // Do checking here
        }                                                                             
}

Similarly, there is no dependency on onActivityResult and onRequestPermissionsResult.

summary

Android permissions are constantly changing. Each new version of Android will have new permissions and new usage methods. In short, for the sake of user privacy and security, the dynamic permission library will continue to develop and update. In the future, there must be better open source libraries, You can also learn from the existing framework library and develop a more suitable dynamic library according to the needs of your company.
Limited level, study together.

Keywords: Android

Added by snowrhythm on Fri, 24 Dec 2021 16:56:30 +0200