Aspectj con libreria Android

Ho una libreria che usa aspetti ed è disponibile via Maven, ora sto cercando di usare quella libreria in un’applicazione Android.

Se includo questo plug-in nel file gradle dell’app, tutto funziona correttamente, ma il mio objective è estrarre il classpath 'com.uphyca.gradle:gradle-android-aspectj-plugin:0.9.+' E il apply plugin: 'android-aspectj' (richiesto dal plugin) al file gradli my.lib invece di dichiararlo nella mia app.

È ansible?

file gradle app:

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

OBBIETTIVO:

file gradle app:

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

file gradli my.lib:

 classpath 'com.uphyca.gradle:gradle-android-aspectj-plugin:0.9.+' apply plugin: 'android-aspectj' dependencies { compile 'org.aspectj:aspectjrt:1.7.3' } 

Ho avuto lo stesso problema. Questo è tutto ciò che ho fatto per risolverlo.

Root / Main Project

Nel tuo progetto root aggiungi gli strumenti AspectJ che contengono il compilatore ajc necessario per tessere le tue classi. (Puoi anche aggiungerlo al file build.gradle della tua libreria, ma è meglio aggiungerlo qui come il plugin gradle che creerai per far sì che la tua libreria utilizzi l’ajc.

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

Progetto Biblioteche

Nel file build.gradle della tua biblioteca assicurati che sia simile a questo. Le principali aggiunte sono le istruzioni di importazione nella parte superiore e il codice sotto le proprietà di build di 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; } } } } 

Quindi, quello che sta succedendo è quando il progetto è in fase di compilazione. Il comando ajc (AspectJ’s weaver) compila e intreccia i file sorgente e .class di AspectJ e Java, producendo file .class compatibili con qualsiasi Java VM.

Affinché ciò avvenga, l’attività richiede argomenti sulla libreria. Questa è la ragione per la creazione della variabile 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) ] 

Quindi il gestore di messaggi che viene creato viene semplicemente passato ad ajc per accumulare messaggi di eventi che si verificano mentre ajc sta compilando / tessendo le classi. Quindi viene passato a un logger di progetto che emette quindi eventuali errori o avvertenze importanti che l’ajc ha prodotto. Ad esempio, se un pointcut non può essere referenziato da un consiglio, verrà rilevato e mostrato nella console gradle. inserisci la descrizione dell'immagine qui

Quindi tutto ciò che è stato descritto sopra sta praticamente avvenendo proprio qui. Dove gli args e il gestore di messaggi vengono passati alla funzione Main di ajc (compilatore 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 Plugin

I punti di riferimento / i consigli della tua libreria non venivano triggersti ​​perché avevi scelto come target il modulo dell’app mentre gli Aspect venivano inseriti nel modulo della tua biblioteca con il com.uphyca.gradle:gradle-android-aspectj-plugin plugin. Quindi, per far sì che gli Aspetti della tua biblioteca siano integrati nel modulo della tua app, devi creare un plugin gradle per il tuo progetto. Quindi quello che hai definito come il tuo objective è che la tua domanda non è ansible, questo è l’unico modo in cui può essere fatto.

Ecco come dovrebbe apparire il plugin. (Il plugin è fatto in groovy).

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

Quindi la class attuale.

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

So che questo potrebbe sembrare un sacco ma è un sacco di copia e incolla perché la soluzione rimane la stessa. Se osservi da vicino la class, le stesse cose fatte nel modulo della tua libreria vengono ora applicate al modulo della tua app. La modifica principale che dovresti fare è aggiungere il modulo della libreria alle dipendenze del progetto tramite il plugin che è stato fatto qui.

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

Affinché la tua libreria sia disponibile per il tuo plug-in durante lo sviluppo, devi assicurarti che venga distribuita nel tuo repository di maven locale. Questo può essere fatto applicando questo plugin ( https://github.com/dcendents/android-maven-gradle-plugin ) al modulo della libreria ed eseguendo l’ gradle install .

Passaggi finali

Una volta che tutto ciò è fatto, puoi applicarlo a un’app di esempio per il test aggiungendo questo al suo file build.gradle

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

Una volta che ciò è fatto, la tua libreria sarà disponibile per l’app perché verrà aggiunta al progetto una volta applicato il plugin.

Se le cose sono ancora confuse, sei in buona fortuna perché il progetto che ho implementato questa soluzione è su Github in modo da poterlo forgiare, copiare il progetto del plugin e apportare le modifiche necessarie.

Il progetto si chiama Flender e viene utilizzato per annotare metodi che richiedono il controllo della connettività. Ecco il link https://github.com/jd-alexander/flender

Spero che questa risposta aiuti.