Aspectj与android库

let*_*etz 24 java aop android aspectj android-library

我有一个使用方面的lib,可以通过maven获得,现在我正在尝试在Android应用程序中使用该lib.

如果我在app gradle文件中包含此插件,一切正常,但我的目标是将my classpath 'com.uphyca.gradle:gradle-android-aspectj-plugin:0.9.+'apply plugin: 'android-aspectj'插件所需的(和插件所需)解压缩到my.lib gradle文件而不是在我的应用程序中声明.

那可能吗?

app gradle文件:

classpath 'com.uphyca.gradle:gradle-android-aspectj-plugin:0.9.+'

apply plugin: 'android-aspectj'

dependencies { 
  compile 'my.lib:example:1.0.0'
}
Run Code Online (Sandbox Code Playgroud)

目标:

app gradle文件:

dependencies { 
  compile 'my.lib:example:1.0.0'
}
Run Code Online (Sandbox Code Playgroud)

my.lib gradle文件:

classpath 'com.uphyca.gradle:gradle-android-aspectj-plugin:0.9.+'

apply plugin: 'android-aspectj'

dependencies { 
  compile 'org.aspectj:aspectjrt:1.7.3'
}
Run Code Online (Sandbox Code Playgroud)

Joe*_*ean 13

我有同样的问题.这就是我所做的一切来解决它.

根/主项目

在根项目中添加包含编织类所需的ajc编译器的AspectJ工具.(您也可以将它添加到库的build.gradle文件中,但最好将其添加到此处,因为您将创建的gradle插件可以使用ajc来容纳您的库.

buildscript {
    repositories {
        jcenter()


    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.2.3'
        classpath 'org.aspectj:aspectjtools:1.8.5'
    }
Run Code Online (Sandbox Code Playgroud)

图书馆计划

在库的build.gradle文件中,确保它看起来像这样.主要的补充是top顶部的import语句和android build属性下面的代码.

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'


dependencies {
    compile 'org.aspectj:aspectjrt:1.8.5'
}
android {
    compileSdkVersion 22
    buildToolsVersion "22.0.1"

    defaultConfig {
        minSdkVersion 14
        targetSdkVersion 22
        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)
    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", 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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以正在发生的事情是在编译项目时,ajc(AspectJ的weaver)命令编译并编织AspectJ和Java源文件和.class文件,生成符合任何Java VM的.class文件.

为此,任务需要有关您的库的参数.这就是创建args变量的原因.

 String[] args = [
                    "-showWeaveInfo",
                    "-1.5",
                    "-inpath", javaCompile.destinationDir.toString(),
                    "-aspectpath", javaCompile.classpath.asPath,
                    "-d", javaCompile.destinationDir.toString(),
                    "-classpath", javaCompile.classpath.asPath,
                    "-bootclasspath", android.bootClasspath.join(File.pathSeparator)
            ]
Run Code Online (Sandbox Code Playgroud)

然后,创建的消息处理程序被简单地传递给ajc,以累积在ajc编译/编织类时发生的事件的消息.然后它被传递给项目记录器,然后输出ajc产生的任何重要错误或警告.例如,如果建议无法引用切入点,则会在gradle控制台中检测并显示切入点. 在此输入图像描述

因此,上面描述的所有内容基本上都在这里发生.将args和消息处理程序传递给ajc(AspectJ编译器)的Main函数.

 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
Run Code Online (Sandbox Code Playgroud)

Gradle插件

您的库的切入点/建议未被触发,因为您的目标是应用程序模块,而Aspects仅使用com.uphyca.gradle:gradle-android-aspectj-pluginAspectJ插件编入您的库模块 .因此,为了将您图书馆的Aspects编织到App的模块中,您必须为您的项目创建一个gradle插件.所以你定义的目标是你的问题是不可能的,这是唯一可行的方法.

这就是插件的外观.(插件是在groovy中完成的).

插件的build.gradle

apply plugin: 'groovy'

targetCompatibility = JavaVersion.VERSION_1_7
sourceCompatibility = JavaVersion.VERSION_1_7

dependencies {
  compile gradleApi()
  compile localGroovy()
  compile 'com.android.tools.build:gradle:1.1.0-rc3'
  compile 'org.aspectj:aspectjtools:1.8.5'
  compile 'org.aspectj:aspectjrt:1.8.5'
}
Run Code Online (Sandbox Code Playgroud)

然后是实际的课程.

import com.android.build.gradle.AppPlugin
import com.android.build.gradle.LibraryPlugin
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
import org.gradle.api.Plugin
import org.gradle.api.Project

public class YourPlugin implements Plugin<Project> {
    @Override void apply(Project project) {
        def hasApp = project.plugins.withType(AppPlugin)
        def hasLib = project.plugins.withType(LibraryPlugin)
        if (!hasApp && !hasLib) {
            throw new IllegalStateException("'android' or 'android-library' plugin required.")
        }

        final def log = project.logger
        final def variants
        if (hasApp) {
            variants = project.android.applicationVariants
        } else {
            variants = project.android.libraryVariants
        }

        project.dependencies {
            compile 'com.name:example:1.0'
            // TODO this should come transitively
            compile 'org.aspectj:aspectjrt:1.8.5'
        }

        variants.all { variant ->

            variant.dex.doFirst {
                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;
                    }
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道这可能看起来很多,但它有很多复制和粘贴,因为解决方案保持不变.如果仔细查看该类,您的库模块中正在执行的相同操作现在将应用于您的应用程序模块.您要对此进行的主要修改是通过此处完成的插件将库模块添加到项目的依赖项中.

 project.dependencies {
                compile 'com.letz:example-library:1.0'
                // TODO this should come transitively
                compile 'org.aspectj:aspectjrt:1.8.5'
            }
Run Code Online (Sandbox Code Playgroud)

为了使您的库在开发时可用于您的插件,您必须确保将其部署到您的本地maven存储库.这可以通过将此插件(https://github.com/dcendents/android-maven-gradle-plugin)应用于库模块并运行gradle install任务来完成.

最后的步骤

完成所有这些后,您可以将其应用于示例应用程序,以便通过将其添加到其build.gradle文件进行测试

buildscript {
    repositories {
        mavenCentral()

        //Only necessary when developing locally.
        mavenLocal()
    }

    dependencies {             

        classpath 'com.letz:example-plugin:1.0'
    }
}
apply plugin: 'example-plugin'
Run Code Online (Sandbox Code Playgroud)

完成后,您的库将可供应用程序使用,因为一旦应用了插件,它就会被添加到项目中.

如果事情仍然令人困惑,那么你好运,因为我实现这个解决方案的项目是在Github上,所以你可以分叉它,复制插件的项目并进行必要的更改.

该项目称为Flender,它用于注释需要连接检查的方法.这是链接https://github.com/jd-alexander/flender

希望这个答案有所帮助