java android aop aspectj android-library

java - Aspectj con biblioteca de Android



aop android-library (1)

Tengo un lib que utiliza aspectos y está disponible a través de maven, ahora estoy tratando de usar ese lib en una aplicación de Android.

Si incluyo este complemento en el archivo gradle de la aplicación, todo funciona bien, pero mi objetivo es extraer el classpath ''com.uphyca.gradle:gradle-android-aspectj-plugin:0.9.+'' Y el apply plugin: ''android-aspectj'' (requerido por el complemento) al archivo my.lib gradle en lugar de declararlo en mi aplicación.

¿Es eso posible?

aplicación de archivo gradle:

classpath ''com.uphyca.gradle:gradle-android-aspectj-plugin:0.9.+'' apply plugin: ''android-aspectj'' dependencies { compile ''my.lib:example:1.0.0'' }

GOL:

aplicación de archivo 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'' }


Yo tuve el mismo problema. Esto es todo lo que hice para resolverlo.

Raíz / Proyecto Principal

En su proyecto raíz, agregue las herramientas de AspectJ que contienen el compilador de ajc que es necesario para tejer sus clases. (También puede agregar esto al archivo build.gradle de su biblioteca, pero es mejor agregarlo aquí, ya que el complemento gradle que creará para acomodar su biblioteca usará el ajc).

buildscript { repositories { jcenter() } dependencies { classpath ''com.android.tools.build:gradle:1.2.3'' classpath ''org.aspectj:aspectjtools:1.8.5'' }

Proyecto de biblioteca

En el archivo build.gradle de su biblioteca, asegúrese de que se parece a esto de manera similar. Las adiciones principales son las declaraciones de importación en la parte superior y el código debajo de las propiedades de compilación de 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; } } } }

Entonces, lo que está sucediendo es cuando el proyecto se está compilando, el comando ajc (tejedor de AspectJ) compila y entrelaza los archivos de fuente y .class de AspectJ y Java, produciendo archivos .class compatibles con cualquier VM de Java.

Para que esto tenga lugar, la tarea necesita argumentos sobre su biblioteca. Esa es la razón para crear la variable 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) ]

Luego, el controlador de mensajes que se crea simplemente se pasa a ajc para acumular mensajes de eventos que se están produciendo mientras ajc está compilando / tejiendo las clases. Luego se pasa a un registrador de proyectos que luego genera errores o advertencias importantes que el ajc produjo. Por ejemplo, si un corte de puntos no puede ser referenciado por un consejo, se detectará y se mostrará en la consola de gradle.

Así que todo lo que se describió anteriormente está ocurriendo básicamente aquí. Donde se pasan los args y el controlador de mensajes a la función Main del ajc (compilador 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

Plugin Gradle

Los puntos / consejos de su biblioteca no se activaron porque estaba apuntando al módulo de la aplicación, mientras que los Aspectos solo se integraron en el módulo de su biblioteca con el com.uphyca.gradle:gradle-android-aspectj-plugin AspectJ. Por lo tanto, para que los aspectos de su biblioteca se incluyan en el módulo de su aplicación, debe crear un complemento de Gradle para su proyecto. Entonces, lo que ha definido como su objetivo es que su pregunta no es posible, esta es la única forma en que puede hacerse.

Así es como debería verse el plugin. (El plugin se realiza en groovy).

Build.gradle de Plugin

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

Entonces la clase real.

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

Sé que esto puede parecer mucho, pero es mucho copiar y pegar porque la solución sigue siendo la misma. Si observa detenidamente la clase, las mismas cosas que se hacen en el módulo de su biblioteca ahora se aplican al módulo de su aplicación. La principal modificación que haría a esto es agregar el módulo de su biblioteca a las dependencias del proyecto a través del complemento que se realiza aquí.

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

Para que su biblioteca esté disponible para su complemento mientras desarrolla, debe asegurarse de que se está implementando en su repositorio local de Maven. Esto se puede hacer aplicando este complemento ( https://github.com/dcendents/android-maven-gradle-plugin ) a su módulo de biblioteca y ejecutando la tarea de gradle install .

Pasos finales

Una vez que haya hecho todo eso, puede aplicarlo a una aplicación de muestra para probarlo agregando esto a su archivo build.gradle

buildscript { repositories { mavenCentral() //Only necessary when developing locally. mavenLocal() } dependencies { classpath ''com.letz:example-plugin:1.0'' } } apply plugin: ''example-plugin''

Una vez hecho esto, su biblioteca estará disponible para la aplicación porque se agregará al proyecto una vez que se haya aplicado el complemento.

Si las cosas siguen confusas, está de suerte porque el proyecto que implementé esta solución está en Github, por lo que puede dividirlo, copiar el proyecto del complemento y realizar los cambios necesarios.

El proyecto se llama Flender y se utiliza para anotar los métodos que requieren la verificación de la conectividad. Aquí está el enlace https://github.com/jd-alexander/flender

Espero que esta respuesta ayude.