2015-06-30 46 views
24

我有一個lib,使用方面,可通過maven,現在我試圖在Android應用程序中使用該庫。Aspectj與Android庫

如果我包括APP 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' 
} 

回答

12

我有同樣的問題。這是我所做的一切來解決它。

根/主項目

在你的根項目添加AspectJ的工具,包含AJC編譯器所必需的編織你的類。 (你也可以將它添加到您的圖書館的build.gradle文件,但最好是添加在這裏爲您將創建以適應您的圖書館將使用AJC的gradle這個插件。

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's weaver)命令編譯並編譯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產生的任何重要錯誤或警告。例如,如果切入點不能被建議引用,它將被檢測到並顯示在gradle控制檯中。 enter image description here

因此,上述所有內容基本上都在這裏發生。 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 

搖籃插件

的切入點/沒有被觸發庫的建議,因爲你而各方面都僅被編入您的圖書館與com.uphyca.gradle:gradle-android-aspectj-plugin AspectJ的插件模塊針對應用程序模塊。所以爲了讓你的庫的Aspects被編入你的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上,所以你可以fork,複製插件的項目,並進行必要的修改。

該項目被稱爲弗蘭德和它用於標註需要連接的檢查方法。這裏的鏈接https://github.com/jd-alexander/flender

希望這個答案幫助。