Подтвердить что ты не робот

Aspectj с библиотекой android

У меня есть lib, который использует аспекты и доступен через maven, теперь я пытаюсь использовать эту lib в приложении Android.

Если я включу этот плагин в файл приложения gradle, все будет хорошо, но моя цель состоит в извлечении 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'
}

ЗАДАЧА:

app 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'
}
4b9b3361

Ответ 1

У меня была та же проблема. Это все, что я сделал, чтобы решить эту проблему.

Проект Root/Main

В вашем корневом проекте добавьте инструменты 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 библиотеки убедитесь, что он похож на этот. Основными дополнениями являются операторы импорта вверху и код под свойствами сборки 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 weaver) компилирует и вставляет файлы AspectJ и Java и .class, создавая файлы .class, совместимые с любой виртуальной машиной Java.

Для этого задача требует аргументов о вашей библиотеке. Это причина для создания переменной 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. Например, если pointcut не может ссылаться на совет, он будет обнаружен и показан в консоли gradle. enter image description here

Итак, все, что было описано выше, в основном происходит прямо здесь. Если аргументы и обработчик сообщений передаются в главную функцию ajc (компилятор AspectJ).

 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 Плагин

Точки/советы вашей библиотеки не запускались, потому что вы настраивали таргетинг на модуль приложения, в то время как аспекты были только вплетены в ваш библиотечный модуль с плагином com.uphyca.gradle:gradle-android-aspectj-plugin AspectJ. Поэтому, чтобы Аспекты вашей библиотеки были вплетены в ваш модуль 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'
}

Тогда действительный класс.

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

Надеюсь, что этот ответ поможет.