Aspectj with android library

2022-09-01 21:21:50

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

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

这可能吗?

应用 gradle 文件:

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

apply plugin: 'android-aspectj'

dependencies { 
  compile 'my.lib:example:1.0.0'
}

目标:

应用 gradle 文件:

dependencies { 
  compile 'my.lib:example:1.0.0'
}

my.lib gradle file:

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

apply plugin: 'android-aspectj'

dependencies { 
  compile 'org.aspectj:aspectjrt:1.7.3'
}

答案 1

我遇到了同样的问题。这就是我为解决它所做的一切。

根/主项目

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

buildscript {
    repositories {
        jcenter()


    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.2.3'
        classpath 'org.aspectj:aspectjtools:1.8.5'
    }

图书馆项目

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

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;
            }
        }
    }
}

        

因此,当编译项目时,ajc(AspectJ的编织者)命令编译并编织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)
            ]

然后,创建的消息处理程序只是被传递到 ajc 以累积在 ajc 编译/编织类时发生的事件的消息。然后将其传递给项目记录器,然后项目记录器输出ajc产生的任何重要错误或警告。例如,如果建议无法引用切入点,则会检测到该切入点并将其显示在 gradle 控制台中。enter image description here

所以上面描述的所有事情基本上都发生在这里。其中,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

Gradle 插件

您的库的切入点/建议没有被触发,因为您的目标是应用程序模块,而Aspects只是使用AspectJ插件编织到库的模块中。因此,为了使库的各个方面编织到应用程序的模块中,您必须为项目创建一个gradle插件。所以你所定义的是你的目标,你的问题是不可能的,这是唯一可以做到的方法。com.uphyca.gradle:gradle-android-aspectj-plugin

这就是插件的外观。(插件在时髦中完成)。

Plugin's 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'
}

然后是实际的类。

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;
                    }
                }
            }
        }
    }
}

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

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

为了使您的库在开发时可用于您的插件,您必须确保将其部署到本地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'

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

如果事情仍然令人困惑,那么您很幸运,因为我实现此解决方案的项目是在Github上,因此您可以对其进行分叉,复制插件的项目并进行必要的更改。

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

希望这个答案有所帮助。


答案 2

推荐