Today, the boss came to know about the project! After this sentence, there is no after! Left me alone in the wind messy!!

In fact, this demand boss in a long time ago said to develop, and then shelved! But the boss’s attitude today should be on the agenda! So there’s no way I can do it! Lest over a while overtime arrive very late, so take advantage of time loose, can tread on the pit tread first!! By sharing it with others, you can avoid wasting unnecessary time. Have a better weekend, spend time with my girlfriend!!


Special Statement:

Thanks to JavaNoober for asking!

The question is, right? What if AspectJ fails with Release?

At that time really give me ask meng force, this kind of check, this kind of Baidu, can not solve! Finally consulted the great god to just solve!!

First of all, I really do not understand the meaning of the configuration of this code, so there are corresponding problems, especially thank you for pointing out.

    if(! variant.buildType.isDebuggable()) { log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
        return
    }
Copy the code

The meaning of this code is only executed during Debug, if not Debug will return directly, so what? When you hit Release, of course it doesn’t work. All return!! Just get rid of this code.


This series of articles:

  • Requirement analysis of buried point in project
  • The application of AOP ideas
  • How to integrate AspectJ into your project (Difficulty 1)
  • AspectJ (difficulty 2)
  • The application of AOP in the project…

For readability, I’m going to break this series into several parts, because this will make the most of your fragmentation time and allow you to learn a point in fragmentation.

The first article focuses on the concept and integration of buried points in AOP. The second article focuses on some of the knowledge used in AspectJ; The third article focuses on other applications of AspectJ for projects.

1. Demand analysis of buried points in the project

1.1 First of all, what is buried point

The so-called buried point, Baidu Encyclopedia is so said! In fact, to be simple, is what I have done in the APP, let you know the operation, in fact, think very terrible, this if I go out wave, daughter-in-law will know!! See, all your actions are under control, used to generate portraits and all that… What a mess! So what do we programmers do? Like what statistics time, click what button, often go to what page… All right! The rest of the operation to see what you need, popular science here!

1.2 Common buried point schemes

I sorted out the corresponding content, and I found that buried points can be divided into:

  • Server level: Analysis is performed mainly through requests from the APP side
  • At the APP level: conduct corresponding analysis through buried points

As a mobile ape, it is natural to analyze the corresponding implementation from the APP level. Now the implementation of the APP is basically divided into the following types

  • Code buries: add code where it is needed, where it needs to be written. But the disadvantage is also reflected, that is, the amount of code will be tons of output, if one day your project manager ran to change a requirement, the code is tons of growth, at that time you will be like “safe programmer” rise up against!!
  • Automation burying point: through some special means (corresponding aspect programming AOP ideas, this is also the focus of this article!!) , the corresponding method for statistics!
  • The third party realizes now a lot of third parties have, Baidu, friend alliance… Just follow the instructions!

In fact, from the programmer’s point of view, is nothing more than how much code is written? Often a lot of content can be measured by this thing, so there is no implementation can not be, I will write more code! But in order for you to be a smart programmer, you always have to learn something!!

2. Application of AOP ideas

Baidu encyclopedia is so describe AOP! Section-oriented programming. In other words, on a certain slice, you can do something! So with your analogy, when you trigger a click event, click the moment is a section, you can add some corresponding content before and after the section, that is, the corresponding section programming!

What problem does it solve? A lot of people ask that, right? There is such a requirement that some apps can only do something when they are logged in. There are often many buttons that need to judge the login situation. If you write a judgment method for each button, there will be a lot of code. Everything needs to be changed? Oh, my god, it’s devastating! This is the time to use AOP programming ideas! Do something about it before you click, and even if you are making changes, you only need to make one change!

The above said so much nonsense, just understand it can! I see AOP in Android is basically using annotations and a thing called AspectJ, are said to be non-invasive buried, this non-invasive is a very good thing, that is, you can implement the corresponding requirements without changing the logic of the previous code, so I think the buried use of this thing is very good!

3. How to integrate AspectJ into the project (Difficulty 1)

This thing about AspectJ integration, will use some knowledge in the gradle, in fact, knowledge of here I don’t really understand, also no longer content we want to do today, so just skip here, anyone interested in to baidu, the interrupt (learn to have a purpose, if you want to learn a thing, Everything else can really wait!!) I will tell you how to integrate!!

3.1 Adding corresponding dependencies

First of all, since the code is non-invasive, it is recommended that you integrate AspectJ into a special Module so that you can implement the solution without changing the original content. According to? Because that’s what I do…

3.1.1 at firstprojectBuild. Gradle to add the corresponding dependencies

    classpath 'org. Aspectj: aspectjtools: 1.8.9'// If you want to add it, you can add it. classpath'org. Aspectj: aspectjweaver: 1.8.9'
Copy the code

The whole code looks like this!

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com. Android. Tools. Build: gradle: 3.1.4'
        classpath 'org. Aspectj: aspectjtools: 1.8.9'// I found this thing works fine without adding // classpath'org. Aspectj: aspectjweaver: 1.8.9'
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
Copy the code

3.1.2 Next, add dependencies and some necessary configuration to the project

In the project build. Add the corresponding gradle depend on implementation ‘org. Aspectj: aspectjrt: 1.8.9’

Then add the appropriate configuration to the root path

import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
final def log = project.logger

android.applicationVariants.all{ variant ->
    if(! variant.buildType.isDebuggable()) { log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
        return
    }

    JavaCompile javaCompile = variant.javaCompiler
    javaCompile.doLast {
        String[] args = ["-showWeaveInfo"."1.8"."-inpath", javaCompile.destinationDir.toString(),
                         "-aspectpath", javaCompile.classpath.asPath,
                         "-d", javaCompile.destinationDir.toString(),
                         "-classpath", javaCompile.classpath.asPath,
                         "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
        log.debug "ajc args: " + Arrays.toString(args)

        MessageHandler handler = new MessageHandler(true)
        new Main().run(args, handler)
        for (IMessage message : handler.getMessages(null, true)) {
            switch (message.getKind()) {
                case IMessage.ABORT:
                case IMessage.ERROR:
                case IMessage.FAIL:
                    log.error message.message, message.thrown
                    break
                case IMessage.WARNING:
                    log.warn message.message, message.thrown
                    break
                case IMessage.INFO:
                    log.info message.message, message.thrown
                    break
                case IMessage.DEBUG:
                    log.debug message.message, message.thrown
                    break}}}}Copy the code

Don’t ask me why? I really don’t understand this code, but I know it’s necessary anyway.

The whole code looks like this!

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.jinlong.aspectjdemo"
        minSdkVersion 14
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com. Android. Support: appcompat - v7:28.0.0 - rc01'
    implementation 'com. Android. Support. The constraint, the constraint - layout: 1.1.2'
    testImplementation 'junit: junit: 4.12'
    androidTestImplementation 'com. Android. Support. Test: runner: 1.0.2'
    androidTestImplementation 'com. Android. Support. Test. Espresso: espresso - core: 3.0.2'
    implementation project(':aspectmodule')
    implementation 'org. Aspectj: aspectjrt: 1.8.9'
}

import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
final def log = project.logger

android.applicationVariants.all{ variant ->
    if(! variant.buildType.isDebuggable()) { log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
        return
    }

    JavaCompile javaCompile = variant.javaCompiler
    javaCompile.doLast {
        String[] args = ["-showWeaveInfo"."1.8"."-inpath", javaCompile.destinationDir.toString(),
                         "-aspectpath", javaCompile.classpath.asPath,
                         "-d", javaCompile.destinationDir.toString(),
                         "-classpath", javaCompile.classpath.asPath,
                         "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
        log.debug "ajc args: " + Arrays.toString(args)

        MessageHandler handler = new MessageHandler(true)
        new Main().run(args, handler)
        for (IMessage message : handler.getMessages(null, true)) {
            switch (message.getKind()) {
                case IMessage.ABORT:
                case IMessage.ERROR:
                case IMessage.FAIL:
                    log.error message.message, message.thrown
                    break
                case IMessage.WARNING:
                    log.warn message.message, message.thrown
                    break
                case IMessage.INFO:
                    log.info message.message, message.thrown
                    break
                case IMessage.DEBUG:
                    log.debug message.message, message.thrown
                    break}}}}Copy the code

If you use it in your Module, you should also configure it in your app’s build.gradle. Remember!! Say “three times” for important things!! Here is a direct paste of the corresponding Module configuration!

apply plugin: 'com.android.library'

android {
    compileSdkVersion 28

    defaultConfig {
        minSdkVersion 14
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation 'com. Android. Support: appcompat - v7:28.0.0 - rc01'
    testImplementation 'junit: junit: 4.12'
    androidTestImplementation 'com. Android. Support. Test: runner: 1.0.2'
    androidTestImplementation 'com. Android. Support. Test. Espresso: espresso - core: 3.0.2'

    implementation 'org. Aspectj: aspectjrt: 1.8.9'
}

import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
final def log = project.logger

android.libraryVariants.all{ variant ->
    if(! variant.buildType.isDebuggable()) { log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
        return
    }

    JavaCompile javaCompile = variant.javaCompiler
    javaCompile.doLast {
        String[] args = ["-showWeaveInfo"."1.8"."-inpath", javaCompile.destinationDir.toString(),
                         "-aspectpath", javaCompile.classpath.asPath,
                         "-d", javaCompile.destinationDir.toString(),
                         "-classpath", javaCompile.classpath.asPath,
                         "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
        log.debug "ajc args: " + Arrays.toString(args)

        MessageHandler handler = new MessageHandler(true)
        new Main().run(args, handler)
        for (IMessage message : handler.getMessages(null, true)) {
            switch (message.getKind()) {
                case IMessage.ABORT:
                case IMessage.ERROR:
                case IMessage.FAIL:
                    log.error message.message, message.thrown
                    break
                case IMessage.WARNING:
                    log.warn message.message, message.thrown
                    break
                case IMessage.INFO:
                    log.info message.message, message.thrown
                    break
                case IMessage.DEBUG:
                    log.debug message.message, message.thrown
                    break}}}}Copy the code

Note that the main project is different from the class library!! This is enough to make sure you compile, but this is just the beginning!!

3.1.3 Configuring corresponding Classes

Here first say the following corresponding configuration, specific why not first say!! Next article I will try my best to give you a clear explanation!! Believe me

@Aspect
public class TraceAspect {

    private static final String TAG = "hjl";

    @Before("execution(* android.app.Activity.on*(..) )")
    public void onActivityMethodBefore(JoinPoint joinPoint) throws Throwable {
        String key = joinPoint.getSignature().toString();
        Log.e(TAG, "OnActivityMethodBefore: Facets of the point executed!"+ key); }}Copy the code

Let’s start with this caveat:

  • The annotation @aspect at the top is indispensable, without it everything would be bullshit!!
  • @Before(“execution(* android.app.Activity.on*(..) Check all activity methods that start with on, such as onCreate(), and the @before element indicates that the activity is executed Before the method is executed. So you can run the program, just look at the LOG,

A simple explanation of the principle, through the above class, mainly in the method in the beginning of a corresponding method, that is, you write this piece of code in the form of a method to add a location! This realizes the corresponding processing scheme through the section!!

Want to see the source code? Want to see the link? Click here