2015-06-30 18 views
24

Tôi có một lib sử dụng các khía cạnh và có sẵn thông qua maven, bây giờ tôi đang cố gắng sử dụng lib đó trong một ứng dụng Android.Aspectj với thư viện android

Nếu tôi bao gồm this plug-in trong ứng dụng tập tin gradle, mọi thứ hoạt động tốt, nhưng mục tiêu của tôi là để trích xuất các classpath 'com.uphyca.gradle:gradle-android-aspectj-plugin:0.9.+'apply plugin: 'android-aspectj' (theo yêu cầu của các plugin) cho my.lib tập tin gradle thay vì tuyên bố trong ứng dụng của tôi.

Điều đó có khả thi không?

ứng dụng tập tin gradle:

classpath 'com.uphyca.gradle:gradle-android-aspectj-plugin:0.9.+' 

apply plugin: 'android-aspectj' 

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

MỤC TIÊU:

ứng dụng gradle file:

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

tệp 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' 
} 

Trả lời

12

Tôi cũng gặp vấn đề tương tự. Đây là tất cả những gì tôi đã làm để giải quyết nó.

Root/Main Project

Trong dự án gốc của bạn thêm các công cụ AspectJ có chứa trình biên dịch AJC đó là cần thiết cho dệt lớp học của bạn. (Bạn cũng có thể thêm video này vào tập tin build.gradle của thư viện của bạn, nhưng nó tốt hơn để thêm nó ở đây là plugin gradle rằng bạn sẽ được tạo để phù hợp với thư viện của bạn sẽ sử dụng AJC.

buildscript { 
    repositories { 
     jcenter() 


    } 
    dependencies { 
     classpath 'com.android.tools.build:gradle:1.2.3' 
     classpath 'org.aspectj:aspectjtools:1.8.5' 
    } 

Dự án Thư viện

Trong file build.gradle thư viện của bạn đảm bảo rằng nó trông giống như tương tự này để này. các bổ sung chính là những điều khoản về nhập khẩu ở phía trên và mã bên dưới xây dựng thuộc tính 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; 
      } 
     } 
    } 
} 

Vì vậy, những gì đang xảy ra là khi dự án đang được biên dịch lệnh ajc (WeaverJ's weaver) biên dịch và dệt các tệp AspectJ và Java và các tệp .class, tạo các tệp .class tương thích với bất kỳ máy ảo Java nào.

Để điều này xảy ra, tác vụ cần đối số về thư viện của bạn. Đó là lý do để tạo biến 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) 
      ] 

Sau đó, trình xử lý tin nhắn được tạo chỉ đơn giản được chuyển tới ajc để tích lũy các thông báo sự kiện đang diễn ra trong khi ajc đang biên soạn/dệt các lớp. Sau đó, nó được chuyển đến một logger dự án và sau đó xuất ra bất kỳ lỗi hoặc cảnh báo quan trọng nào mà ajc đã tạo ra. Ví dụ, nếu một điểm cắt không thể được tham chiếu bởi một lời khuyên nó sẽ được phát hiện và hiển thị trong bảng điều khiển gradle. enter image description here

Vì vậy, tất cả những gì được mô tả ở trên về cơ bản đang diễn ra ngay tại đây. Trong trường hợp trình xử lý thông điệp và args được truyền đến hàm chính của ajc (trình biên dịch 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

Các pointcuts/lời khuyên của thư viện của bạn đã không được kích hoạt bởi vì bạn nhắm mục tiêu các module ứng dụng trong khi khía cạnh được chỉ được dệt vào mô-đun của thư viện của bạn với AspectJ Plugin com.uphyca.gradle:gradle-android-aspectj-plugin. Vì vậy, để cho các khía cạnh của thư viện của bạn được dệt vào mô-đun ứng dụng của bạn, bạn phải tạo một plugin gradle cho dự án của bạn. Vì vậy, những gì bạn đã xác định là mục tiêu của bạn là câu hỏi của bạn là không thể, đây là cách duy nhất nó có thể được thực hiện.

Đây là giao diện của plugin. (Plugin được thực hiện trong groovy).

Plugin của 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' 
} 

Sau đó, lớp thực tế.

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

Tôi biết điều này có vẻ như rất nhiều nhưng không sao chép và dán vì giải pháp vẫn giữ nguyên. Nếu bạn nhìn kỹ vào lớp, những thứ tương tự đang được thực hiện trong mô-đun thư viện của bạn hiện đang được áp dụng cho mô-đun của ứng dụng. Việc sửa đổi chính bạn sẽ làm điều này là thêm mô-đun thư viện của bạn vào các phụ thuộc của dự án thông qua plugin được thực hiện ở đây.

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

Để thư viện của bạn khả dụng với plugin trong khi phát triển, bạn phải đảm bảo rằng thư viện được triển khai tới kho lưu trữ maven cục bộ của bạn. Điều này có thể được thực hiện bằng cách áp dụng plugin này (https://github.com/dcendents/android-maven-gradle-plugin) vào mô-đun thư viện của bạn và chạy tác vụ gradle install.

cuối cùng bước

Khi tất cả điều đó được thực hiện thì bạn có thể áp dụng nó vào một ứng dụng mẫu để thử nghiệm bằng cách thêm này để nó build.gradle tập tin

buildscript { 
    repositories { 
     mavenCentral() 

     //Only necessary when developing locally. 
     mavenLocal() 
    } 

    dependencies {    

     classpath 'com.letz:example-plugin:1.0' 
    } 
} 
apply plugin: 'example-plugin' 

Khi đã xong thư viện của bạn sẽ có sẵn cho ứng dụng vì ứng dụng sẽ được thêm vào dự án khi plugin đã được áp dụng.

Nếu mọi thứ vẫn còn khó hiểu, bạn sẽ gặp may mắn vì dự án tôi đã triển khai giải pháp này là trên Github để bạn có thể chia nhỏ nó, sao chép dự án của plugin và thực hiện các thay đổi cần thiết.

Dự án được gọi là Flender và được sử dụng để chú thích các phương thức yêu cầu kiểm tra kết nối. Đây là liên kết https://github.com/jd-alexander/flender

Hy vọng câu trả lời này sẽ hữu ích.

Các vấn đề liên quan