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