Using AspectJ .aj file with Android Studio, weavin

2019-09-05 01:10发布

问题:

I am new to AspectJ, and we are working on migrating a third-party application originally written using Eclipse to use Android Studio 1.1.0 and Gradle instead. We have taken an external library this app needs and created a library module in the project, and this library has an AspectJ .aj file that we need to compile and have work with the main app for a field-level Observable pattern. Using the plugin found here, I have been able to get the .aj file to compile into a .class file, verified by looking in the intermediates folder.

The problem is coming in the 'weaving' step, where this code is supposed to be injected into the bytecode of the necessary classes. This does not appear to be happening, as the listeners that are supposed to be notified when a field changes, aren't. Below are my build files.

Project build.gradle:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.1.0'
        classpath 'com.uphyca.gradle:gradle-android-aspectj-plugin:0.9.12'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

app module build.gradle:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 19
    buildToolsVersion "22.0.1"

    defaultConfig {
        applicationId "com.example.myapp"
        minSdkVersion 14
        targetSdkVersion 19
    }

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

dependencies {
    compile project(':blahblah')
    compile 'com.android.support:support-v4:19.1.0'
    compile 'com.google.code.gson:gson:2.2.4'
    compile 'com.google.android.gms:play-services:6.1.11'
    compile files('libs/commons-lang3-3.3.2.jar')
}

'blahblah' library module build.gradle:

import com.android.build.gradle.LibraryPlugin
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main

apply plugin: 'com.android.library'
apply plugin: 'android-aspectj'

def gsonVersion = '2.2.4'
def aspectjVersion = '1.8.5'

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile "com.google.code.gson:gson:${gsonVersion}"
    compile "org.aspectj:aspectjrt:${aspectjVersion}"
}

android {
    compileSdkVersion 19
    buildToolsVersion "22.0.1"

    defaultConfig {
        minSdkVersion 14
        targetSdkVersion 19
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

android.libraryVariants.all { variant ->

    LibraryPlugin plugin = project.plugins.getPlugin(LibraryPlugin)

    variant.javaCompile.doLast {
        String[] args = ["-showWeaveInfo",
                         "-1.5",
                         "-inpath", javaCompile.destinationDir.toString(),
                         "-aspectpath", javaCompile.classpath.asPath,
                         "-d", javaCompile.destinationDir.toString(),
                         "-classpath", javaCompile.classpath.asPath,
                         "-bootclasspath", plugin.project.android.bootClasspath.join(
                File.pathSeparator)]

        MessageHandler handler = new MessageHandler(true);
        new Main().run(args, handler)

        def log = project.logger
        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:
                case IMessage.INFO:
                    log.info message.message, message.thrown
                    break;
                case IMessage.DEBUG:
                    log.debug message.message, message.thrown
                    break;
            }
        }
    }
}

What am I missing?

回答1:

After more research, I have been able to get everything working as expected. Here are the final build.gradle files:

Project build.gradle:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.1.0'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

app module build.gradle:

import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main

buildscript {

    repositories {
        mavenCentral()
    }

    dependencies {
        classpath 'org.aspectj:aspectjtools:1.8.1'
    }

}

apply plugin: 'com.android.application'

repositories {
    mavenCentral()
}

def gsonVersion = '2.2.4'
def aspectJVersion = '1.8.1'

dependencies {
    compile project(':blahblah')
    compile "org.aspectj:aspectjrt:${aspectJVersion}"
    compile 'com.android.support:support-v4:19.1.0'
    compile "com.google.code.gson:gson:${gsonVersion}"
    compile 'com.google.android.gms:play-services:6.1.11'
    compile files('libs/commons-lang3-3.3.2.jar')
}

android {
    compileSdkVersion 19
    buildToolsVersion "22.0.1"

    defaultConfig {
        applicationId "com.example.myapp"
        minSdkVersion 14
        targetSdkVersion 19
    }

    lintOptions {
        abortOnError true
    }

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

// The section below is what performs the AOP "weaving" (injecting the AOP code into
// the appropriate classes).  Please do not remove.

final def log = project.logger
final def variants = project.android.applicationVariants

variants.all { variant ->
    if (!variant.buildType.isDebuggable()) {
        log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
        return;
    }
    JavaCompile javaCompile = variant.javaCompile
    javaCompile.doLast {
        String[] args = ["-showWeaveInfo",
                         "-1.5",
                         "-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;
            }
        }
    }

}

'blahblah' library module build.gradle:

def gsonVersion = '2.2.4'

buildscript {

    repositories {
        mavenCentral()
    }

    dependencies {
        classpath "com.android.tools.build:gradle:1.1.0"
        classpath 'com.uphyca.gradle:gradle-android-aspectj-plugin:0.9.12'
    }

}

apply plugin: 'com.android.library'
apply plugin: 'android-aspectj'

repositories {
    mavenCentral()
}

dependencies {
    compile "com.google.code.gson:gson:${gsonVersion}"
}

android {
    compileSdkVersion 19
    buildToolsVersion "22.0.1"
    lintOptions {
        abortOnError true
    }
}