AOP programming_ Conceptual basis of Android elegant permission framework

Posted by virva on Wed, 02 Feb 2022 03:28:29 +0100

Special invited author of enjoy learning class: Lao Gu
Reprint, please state the source!

preface

The last large series of articles was called "hand-in-hand explanation", which lasted for 10 months, and produced more than 20 blog articles. The explanations were detailed. Almost every article provided detailed explanation of the principle, provided a runnable github Demo, and focused on the disassembly of key places in the Demo. I believe that every peer who reads the article in detail will gain something. However, although the explanation is detailed, there is a lack of in-depth excavation of technology.

Starting today, we will open up a new topic: professional skills of mobile architects in simple terms, with the goal of becoming an architect step by step, detailing the most direct use value of an architect's skills, horizontal peripheral knowledge and in-depth professional technology

The most direct use value: I'm most afraid to see an article on the Internet. The full text is tall at the beginning, which makes people feel out of reach. However, it doesn't show how the technology is landing and what effect it will have after landing. When an article is written, it is necessary to take the reader into the author's world in the most acceptable way, rather than pretending to be high above all living beings. Therefore, the beginning of the article must be the most direct demonstration of the landing effect of technology. Provide a runnable Demo that allows readers to try it for themselves.

The core of a technology is an independent technology, but as an auxiliary technology, it is inevitable that other technologies can exist. The core technology needs to be detailed, but the surrounding technology also needs to be explained. The towering trees rise from the ground without the soil as their attachment. Explain the surrounding knowledge in concise language and provide the correct research direction of these knowledge. It is also a step that can not be ignored by a responsible blogger.

In depth professional technology: the most taboo to do technology is to taste it. If you go a little deeper, you will quit. On the one hand, it is not conducive to understanding the underlying implementation. In the long run, you will always be a technical white and can't become a master; Second, it is not conducive to long-term memory. No matter how strong the memory is, the technical details will be blurred for a long time. However, if you go deep into the kernel and understand the principle, you will never deviate in the general direction of technology. As a man who wants to be an architect, even if he can't remember so many details, he can't grasp the general direction wrong. Therefore, it is necessary to deepen the technology.

Text outline

  1. Demo address

  2. Technical Inventory involved in this paper

  3. About Android permissions

  4. Writing method of permission request for primary / intermediate / advanced android Development

  5. Detailed explanation of AOP elegant permission framework

    gradle configuration

    Java code

  6. AOP idea and common AOP framework

  7. In depth principle research of AspectJ AOP framework

text

1.Demo address

Demo address: https://github.com/18598925736/GracefulPermissionFramework/tree/dev_aspectJ

2. Technical Inventory involved in this paper

The following is suitable for developers with certain Android development years. You can understand the demo code of this article only after you have at least a basic understanding of the following technical points

  • java annotation Foundation

The @ symbol is widely used as an annotation mark in java code. Annotations have a variety of purposes, but they are basically marked for special processing in the source code period, compilation period, or run-time. Annotations have their own specific syntax and API s.

  • Gradle plug-in Foundation

Gradle is a project construction framework in android studio, which is used to integrate and compile android source code projects into apk. You can customize the gradle plug-in, or you can reference the gradle plug-in published by others to add your own logic to the project construction process.

  • Java reflection Foundation

java reflection. Some classes or methods that are inconvenient to use directly can be used by reflection. Reflection is usually used in frame design and hook technology.

  • Android rights Basics

The focus of this article is to write the code of permission application gracefully. If you want to understand this article, you can't know nothing about permission.

  • AOP aspect oriented programming idea

Aspect oriented programming is one of the important means of code decoupling. See below for more information.

3. About Android permissions

The issue of permissions has been a stumbling block since the advent of Android. The first batch of people who made Android could easily obtain user information at that time, including contacts, including SMS content, including call records. It can be said that Android's criticized security problems originated from this. At the code level, developers only need to declare the required permissions in the manifest file according to the permission description of the Android official website, so that they can access the required data in the code type. There are many kinds of permissions, more than hundreds of permissions, which are applicable to different scenarios. You can't write them down, and generally don't need to write them down.

Go to the official website when necessary https://developer.android.com/reference/android/Manifest.permission.html Just find it

The following is a summary of the development history of Android and major changes in the permission system.

  • Android 1.0 - Android 5.0/5.1 App developers only need to declare permissions in the manifest file, which will be granted automatically during installation.

  • Since Android 6.0, Google has divided all permissions into two categories, ordinary permissions, that is, they still only need to be declared in the list file. The other is dangerous permission, which involves user privacy. In addition to the declaration in the list file, it also needs to be applied dynamically when the App is started. In addition, Google also provides the conceptual difference between permission group and permission, and puts some permissions with similar functions in one group. When you apply for one of them, In fact, other permissions of this group are applied by default. Although this approach allows you to write one less permission, Google still recommends that you write the required permission completely, because Google will change the permission group on the day when it is not guaranteed. At that time, there will be compatibility problems in the code, which is not necessary, and it is also a good habit to write the required permission completely.

    The following figure shows all dangerous permissions and permission groups.

  • There has been another major change since Android Q. From the process of adapting Android Q, it is found that
    1. Two permissions of the storage permission group, READ_EXTERNAL_STORAGE / WRITE_ETERNAL_STORAGE does not need dynamic application (but it still needs to be declared in the list file), because Q system enables sandbox mechanism. App does not need any permission to access its own directory. If you want to access places outside the directory of app, you need to apply for READ_EXTERNAL_STORAGE / WRITE_ETERNAL_STORAGE these two permissions.
    2. When the device is running in the background, it needs to use location information and dynamically apply for permission. Q introduces access_ BACKGROUND_ The purpose of the new permission of location is to restrict the background process from obtaining user location information quietly. This permission will be granted by default if it is running in a system below Q (not included), but it must be applied if it is above Q.
    3. For other changes, see the official website, https://developer.android.google.cn/about/versions/10/privacy/changes?hl=zh-tw.
  • Another troublesome problem is that if you run my Demo, you will find that the effect may be completely different on many models. Take two extreme examples: Android 6 0 version of mumu simulator, many permissions will be granted by default, such as location information permission. In addition, on some Huawei mobile phones, some permissions will be rejected by default. Every time you apply, the user has permanently rejected it. This is because mobile phone manufacturers or simulator manufacturers have deeply customized Google's native Android system and changed the relevant code of permission. Therefore, to deal with this problem, it is necessary to adapt a variety of models.

4. Writing method of permission request for primary / intermediate / advanced android Development

In fact, there are some restrictions on permissions, which are relatively simple. The only thing we need to pay special attention to is the dynamic permission application after 6.0. Its processing method is:

The main process is transformed into code and displayed:

AndroidManifest.xml

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

Java code

    /**
     * Apply for permission
     */
    protected void requestPermission(String[] permissions, int requestCode) {
        // Check that you already have these permissions
        if (PermissionUtil.hasSelfPermissions(this, permissions)) {
            Log.e(TAG, "Activity,requestPermission: All permissions are already available,No application required");
        } else {
            // Start requesting permission
            ActivityCompat.requestPermissions(this, permissions, requestCode);
        }
    }
    /**
     * Processing callback
     *
     * @param requestCode
     * @param permissions
     * @param grantResults
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (PermissionUtil.verifyPermissions(grantResults)) {//Check whether the permissions are granted
            granted(requestCode);
        } else {
            // Show tips
            if (PermissionUtil.shouldShowRequestPermissionRationale(this, permissions)) {
                //Shouldshowrequestpermissionrational this method is to check whether the permission is permanently rejected...
                //If you reject with, false will be returned here. If you reject for the first time, true will be returned

                // Cancel permission
                denied(requestCode);
            } else {
                // Permission denied
                deniedForever(requestCode);
            }
        }
    }

Apply for permission above activitycompat Requestpermissions and processing callback onRequestPermissionsResult are where developers need to code manually.

The same is the above logic. The processing methods of junior / intermediate / advanced developers are quite different.

  • primary

A complete commercial project is bound to involve many activities, fragments, ordinary Java classes, etc. specific permissions need to be used in many places. If we search onRequestPermissionsResult with ctrl+H, we find the following scenarios:

The same callback method has appeared 25 times in the project Moreover, the code of permission application, which is not directly related to the business, is also embedded in the business code. OK, I won't say much here.

(PS: actually, this is the code of my own company. I don't know why... Maybe there are too many staff changes in the company, and future generations are too lazy to change the structure)

  • intermediate

    PS: Reference https://github.com/18598925736/GracefulPermissionFramework/tree/dev

Intermediate development, as a programmer with certain working experience, knows how to optimize the code and reduce the maintenance cost. Then he is likely to find that the permission application is basically based on Activity and Fragment. As long as the code redundancy here is solved, he will write this

public abstract class BaseActivity extends AppCompatActivity implements IPermissionCallback {
    protected static final String TAG = "BaseActivity";

    /**
     * Apply for permission
     */
    protected void requestPermission(String[] permissions, int requestCode) {
        // Check that you already have these permissions
        if (PermissionUtil.hasSelfPermissions(this, permissions)) {
            Log.e(TAG, "Activity,requestPermission: All permissions are already available,No application required");
        } else {
            // Start requesting permission
            ActivityCompat.requestPermissions(this, permissions, requestCode);
        }
    }

    /**
     * Request feedback
     *
     * @param requestCode
     * @param permissions
     * @param grantResults
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (PermissionUtil.verifyPermissions(grantResults)) {//Check whether the permissions are granted
            granted(requestCode);
        } else {
            // Show tips
            if (PermissionUtil.shouldShowRequestPermissionRationale(this, permissions)) {
                //Shouldshowrequestpermissionrational this method is to check whether the permission is permanently rejected... If you reject with, false will be returned here. If you reject for the first time, true will be returned
                // Cancel permission
                denied(requestCode);
            } else {
                // Permission denied
                deniedForever(requestCode);
            }
        }
    }


}
public abstract class BaseFragment extends Fragment implements IPermissionCallback {

    protected static final String TAG = "BaseFragment";

    /**
     * Apply for permission
     */
    protected void requestPermission(String[] permissions, int requestCode) {
        // Do you already have these permissions
        if (PermissionUtil.hasSelfPermissions(getActivity(), permissions)) {
            Log.e(TAG, "Activity,requestPermission: All permissions are already available,No application required");
        } else {
            // Start requesting permission
            ActivityCompat.requestPermissions(getActivity(), permissions, requestCode);
        }
    }

    /**
     * Request feedback
     *
     * @param requestCode
     * @param permissions
     * @param grantResults
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (PermissionUtil.verifyPermissions(grantResults)) {//Check whether the permissions are granted
            granted(requestCode);
        } else {
            // Show tips
            if (PermissionUtil.shouldShowRequestPermissionRationale(getActivity(), permissions)) {
                //Shouldshowrequestpermissionrational this method is to check whether the permission is permanently rejected... If you reject with, false will be returned here. If you reject for the first time, true will be returned
                // Cancel permission
                denied(requestCode);
            } else {
                // Permission denied
                deniedForever(requestCode);
            }
        }
    }
}

Then, the same IPermissionCallback interface is used to process the possible results of applying for permission (user agrees, user rejects, and user permanently rejects)

/**
 * Permission application result interface
 */
public interface IPermissionCallback {

    /**
     * Grant permission
     */
    void granted(int requestCode);

    /**
     * Refuse this time, but do not check "no more prompt in the future"
     */
    void denied(int requestCode);

    /**
     * Check "don't prompt again" and refuse
     */
    void deniedForever(int requestCode);
}

However, do we only need Activity and Fragment for permission application?

No, there may also be:

Service: for example, starting a service to play local music may require local storage permission. If you apply for permission at this time, how should the service apply for permission? After experiments, I found that service can't apply for permission because activitycompat The first parameter of the requestpermissions () method is Activity. In a service, you cannot directly obtain an Activity object.

Ordinary Java class: an ordinary Java tool class. Its function is to read and write files from the internal storage of the mobile phone. Then it needs local storage permission. How should it apply? You can come up with some folk remedies to solve this problem, but if you stay at the level of intermediate development, you can never give an elegant solution.

  • Senior Developer / Architect

    The detailed analysis will be written in the next chapter. Let's look at the code effect first:

    Activity:
    Fragment:
    Normal Java classes:Service:

Observe the same points of the codes in the above three figures:

Three custom annotations are used: @ permissionneed, @ permissiondenied, @ permissioncancel

  • @PermissionNeed modifies the java method after the user grants permission

  • @The PermissionDenied annotation modifies the java method after the user denies permission

  • @The PermissionCancel annotation modifies the java method after the user permanently rejects it

The three annotations are used in exactly the same way in Activity, Fragment, Service and ordinary Java classes. It can also be said that the processing method of senior developers / architects eliminates the differentiation of Activity, Fragment, Service and ordinary Java classes, achieves the universality of code call, and fundamentally solves the redundancy of dynamic permission application in business code.

Using this method, you no longer have to worry about the intersection of your business code and permission related code, so as to make the business code clearer.

The next article starts with Demo

If you like, please like, collect + pay attention~
Follow the account to see more previous content and get the updated information at the first time!
The modification is the java method after the user permanently rejects it

The three annotations are used in exactly the same way in Activity, Fragment, Service and ordinary Java classes. It can also be said that the processing method of senior developers / architects eliminates the differentiation of Activity, Fragment, Service and ordinary Java classes, achieves the universality of code call, and fundamentally solves the redundancy of dynamic permission application in business code.

Using this method, you no longer have to worry about the intersection of your business code and permission related code, so as to make the business code clearer.

The next article starts with Demo

If you like, please like, collect + pay attention~
Follow the account to see more previous content and get the updated information at the first time!

Topics: Java Interview Programmer