【问题标题】:Aspectj with android libraryAspectj 与 android 库
【发布时间】:2015-09-17 11:27:25
【问题描述】:

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

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

这可能吗?

应用 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 文件:

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

apply plugin: 'android-aspectj'

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

【问题讨论】:

    标签: java android aop aspectj android-library


    【解决方案1】:

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

    根/主项目

    在您的根项目中添加包含编织类所必需的 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'
        }
    

    图书馆项目

    在你的库的 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 控制台中。

    所以上面描述的所有事情基本上都在这里发生。 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 仅通过 com.uphyca.gradle:gradle-android-aspectj-plugin AspectJ 插件被编织到您的库模块中。因此,为了将库的 Aspects 编织到应用程序的模块中,您必须为您的项目创建一个 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'
    }
    

    然后是实际的类。

    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

    希望这个答案有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-09
      • 1970-01-01
      • 1970-01-01
      • 2021-08-01
      相关资源
      最近更新 更多