Новая система сборки Android (gradle) и aspectj

17

В Google IO объявлен новый алгоритм построения системы для замены ant. Мой проект использует aspectj, и я хотел бы использовать его в своем проекте. Я не мог понять некоторые переменные, чтобы заставить его работать. Я не нашел android. * Output classpath. Кто может помочь?

Вот мой текущий build.gradle:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.4'
    }
}
apply plugin: 'android'
sourceCompatibility = 1.6

configurations {
    ajc
} 

dependencies {
    compile fileTree(dir: 'libs', includes: ['*.jar'])
    ajc files('build-tools/aspectjtools.jar', 'libs/aspectjrt.jar')
}

android {
    compileSdkVersion 16
    buildToolsVersion "17"

    defaultConfig {
        minSdkVersion 8
        targetSdkVersion 16
    }
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }

        instrumentTest.setRoot('test')
    }
}

gradle.projectsEvaluated {
    compileJava.doLast {
        tasks.compileAspectJ.execute()
    }
    println 'lalalalala'
}

task compileAspectJ {

    ant.taskdef(resource: "org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties",
        classpath: configurations.ajc.asPath)
    ant.iajc(source: sourceCompatibility, target: sourceCompatibility,
        destDir: "?????????????????????",
        classpath: "????????????????????????????") {

        sourceroots{
            android.sourceSets.main.java.srcDirs.each {
                pathelement(location: it.absolutePath)
            }  
        }  
    }  
}

Это старый код муравья, который работает очень хорошо: Ссылка

Edit:

Обновлен build.gradle в соответствии с первым ответом. Однако я не вижу, что iajc распознает все библиотеки и жалуется на классы в найденных библиотеках

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.5.+'
    }
}

apply plugin: 'android'
sourceCompatibility = 1.6
targetCompatibility = 1.6

repositories {
    mavenCentral()
}

android {
    compileSdkVersion 18
    buildToolsVersion "18.1.0"

    defaultConfig {
        minSdkVersion 9
        targetSdkVersion 16
    }
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }

        // Move the tests to tests/java, tests/res, etc...
        instrumentTest.setRoot('tests')

        // Move the build types to build-types/<type>
        // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
        // This moves them out of them default location under src/<type>/... which would
        // conflict with src/ being used by the main source set.
        // Adding new build types or product flavors should be accompanied
        // by a similar customization.
        debug.setRoot('build-types/debug')
        release.setRoot('build-types/release')
    }
}

configurations {
    ajc
    aspects
    ajInpath
}

ext.aspectjVersion = '1.7.3'

dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')

    ajc "org.aspectj:aspectjtools:${aspectjVersion}"
    compile "org.aspectj:aspectjrt:${aspectjVersion}"
    compile 'com.android.support:appcompat-v7:18.0.0'
}

android.applicationVariants.all { variant ->

    variant.javaCompile.doLast {
        def androidSdk = android.adbExe.parent + "/../platforms/" + android.compileSdkVersion + "/android.jar"
    println 'AAAAAAAAAAAAAAAAA: ' + androidSdk

        def iajcClasspath = configurations.compile.asPath + ":" + androidSdk
        configurations.compile.dependencies.each { dep ->
            if(dep.hasProperty("dependencyProject")) {
                iajcClasspath += ":" + dep.dependencyProject.buildDir + "/bundles/release/classes.jar"
            }
        }
    println 'BBBBBBBBBBBBBB : ' + iajcClasspath 

        ant.taskdef( resource:"org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties", classpath: configurations.ajc.asPath)
        ant.iajc (
                source:sourceCompatibility,
                target:targetCompatibility,
                destDir:"${project.buildDir}/classes/${variant.dirName}",
                maxmem:"512m",
                fork:"true",
                aspectPath:configurations.aspects.asPath,
                inpath:configurations.ajInpath.asPath,
                sourceRootCopyFilter:"**/.svn/*,**/*.java",
                classpath:iajcClasspath
        ){
            sourceroots{
                android.sourceSets.main.java.srcDirs.each{
                    pathelement(location:it.absolutePath)
                }
                pathelement(location:"${project.buildDir}/source/r/${variant.dirName}")
            }
        }
    }
}

Ошибки:

1 [error] The method onPrepareOptionsMenu(Menu) of type FingerPaint must override or impl[3780/18642]
rtype method
[ant:iajc] public boolean onPrepareOptionsMenu(Menu menu) {
[ant:iajc]                ^^^^^^^^^^^^^^^^^^^^^^^^^^
[ant:iajc] /home/liberty/mp/android/AnyMemo/src/com/example/android/apis/graphics/FingerPaint.java:21
2 [error] The method onPrepareOptionsMenu(Menu) is undefined for the type GraphicsActivity
[ant:iajc] super.onPrepareOptionsMenu(menu);
[ant:iajc]       ^^^^^^^^^^^
[ant:iajc] /home/liberty/mp/android/AnyMemo/src/com/example/android/apis/graphics/FingerPaint.java:21
7 [error] The method onOptionsItemSelected(MenuItem) of type FingerPaint must override or implement a
 supertype method
[ant:iajc] public boolean onOptionsItemSelected(MenuItem item) {
[ant:iajc]                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[ant:iajc] /home/liberty/mp/android/AnyMemo/src/com/example/android/apis/graphics/FingerPaint.java:22
8 [error] The constructor ColorPickerDialog(FingerPaint, FingerPaint, int) is undefined
[ant:iajc] new ColorPickerDialog(this, this, mPaint.getColor()).show();
[ant:iajc] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[ant:iajc] /home/liberty/mp/android/AnyMemo/src/com/example/android/apis/graphics/FingerPaint.java:25
4 [error] The method onOptionsItemSelected(MenuItem) is undefined for the type GraphicsActivity
[ant:iajc] return super.onOptionsItemSelected(item);
[ant:iajc]              ^^^^^^^^^^^^
[ant:iajc] /home/liberty/mp/android/AnyMemo/src/com/example/android/apis/graphics/FingerPaint.java:25
8 [error] The method getDefaultSharedPreferences(Context) in the type PreferenceManager is not applic
able for the arguments (FingerPaint)
[ant:iajc] SharedPreferences shre = PreferenceManager.getDefaultSharedPreferences(this);
[ant:iajc]              

EDIT: Это окончательный файл build.gradle, который работает для моего проекта: Ссылка

    
задан Liberty 22.06.2013 в 00:46
источник
  • Для вашей новой ошибки я попытался воспроизвести ее, добавив библиотеку jar, но она отлично работает для меня. –  aegar 13.11.2013 в 22:02
  • Я полагаю, что ошибка не связана с самой библиотекой, так как iajc, похоже, находит вашу GraphicsActivity, но это может быть неправильный путь sdk: все ваши ошибки либо связаны с методами из активности, которые не могут быть найдены в GraphicsActivity или к GraphicsActivity, которая не распознается как активность в конструкторах. Вы проверили var androidSdk? Mine указывает где-то в «/ home / aegar / android-sdk / platform», где у меня только Android-18. –  aegar 13.11.2013 в 22:11
  • Это проблема зависимости AAR. AAR нельзя использовать в качестве банки. Вы обрабатываете dependencyProject, но если вы укажете компиляцию «com.android.support:appcompat-v7:18.0.0», class.jar находится в вложенном пакете, все банки в этом каталоге должны быть добавлены в путь к классам. –  Liberty 28.11.2013 в 06:06

5 ответов

6

Я понял, что AAR не может использоваться в качестве библиотеки jar в моем коде. Если вы используете зависимости типа

compile 'com.android.support:appcompat-v7:18.0.0'

Вам нужно найти файл jar и добавить в путь к классам. Следующий код сделает это.

tree = fileTree(dir: "${project.buildDir}/exploded-bundles", include: '**/classes.jar')
tree.each { jarFile ->
    iajcClasspath += ":" + jarFile
}

Таким образом, весь раздел будет:

variant.javaCompile.doLast {
    // Find the android.jar and add to iajc classpath
    def androidSdk = android.adbExe.parent + "/../platforms/" + android.compileSdkVersion + "/android.jar"
    println 'Android SDK android.jar path: ' + androidSdk

    def iajcClasspath = androidSdk + ":" + configurations.compile.asPath
    configurations.compile.dependencies.each { dep ->
        if(dep.hasProperty("dependencyProject")) {
            iajcClasspath += ":" + dep.dependencyProject.buildDir + "/bundles/release/classes.jar"
        }
    }

    // handle aar dependencies pulled in by gradle (Android support library and etc)
    tree = fileTree(dir: "${project.buildDir}/exploded-bundles", include: '**/classes.jar')
    tree.each { jarFile ->
        iajcClasspath += ":" + jarFile
    }
        println 'Classpath for iajc: ' + iajcClasspath

        ant.taskdef( resource:"org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties", classpath: configurations.ajc.asPath)

Для полного примера см. проект build.gradle для AnyMemo: Ссылка

    
ответ дан Liberty 28.11.2013 в 06:01
  • Примечание: Использование инструментов 19 Я думаю, что они, возможно, изменили местоположение. Мне нужно было использовать «exploded-aar» вместо «взорванных пачек» из приведенного выше примера. –  withoutclass 14.04.2014 в 22:31
  • withoutclass, Да, они изменили имя. code.google.com/p/anymemo/source/browse/... имеет изменения. –  Liberty 03.05.2014 в 21:36
  • СПАСИБО! Я пропустил этот пост и сражался с ответом, прежде чем я сдался и посмотрел сюда. Этот ответ требует большего количества оборотов. –  dieend 29.05.2014 в 15:20
15

Я также хотел использовать aspectj с gradle и Android Studio, и я, наконец, получил его работу, но у меня все еще есть некоторые рукописные пути, которые я бы хотел заменить более универсальными вариантами градиента.

Изменить: Я заменил все жестко закодированные абсолютные пути альтернативами на основе градиента, поэтому это решение больше не зависит от данной платформы или имени пользователя. Тем не менее, он по-прежнему использует относительные пути, которые могут измениться с IDE на другой или в дальнейших версиях Android Studio. Кроме того, я не очень доволен тем, как я нахожу android.jar.

Я сначала загружаю aspectj:

configurations {
ajc
aspects
ajInpath
}

ext.aspectjVersion = '1.7.3'

dependencies {
    compile project(":LibTest")

    ajc "org.aspectj:aspectjtools:${aspectjVersion}"
    compile "org.aspectj:aspectjrt:${aspectjVersion}"
    compile 'com.android.support:appcompat-v7:18.0.0'
}

И затем я добавляю задачу, которая будет запускаться после задачи JavaCompile текущего варианта:

android.applicationVariants.all { variant ->

    variant.javaCompile.doLast {
        def androidSdk = android.adbExe.parent + "/../platforms/" + android.compileSdkVersion + "/android.jar"

        def iajcClasspath = configurations.compile.asPath + ";" + androidSdk
        configurations.compile.dependencies.each { dep ->
            if(dep.hasProperty("dependencyProject")) {
                iajcClasspath += ":" + dep.dependencyProject.buildDir + "/bundles/release/classes.jar"
            }
        }

        ant.taskdef( resource:"org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties", classpath: configurations.ajc.asPath)
        ant.iajc (
                source:sourceCompatibility,
                target:targetCompatibility,
                destDir:"${project.buildDir}/classes/${variant.dirName}",
                maxmem:"512m",
                fork:"true",
                aspectPath:configurations.aspects.asPath,
                inpath:configurations.ajInpath.asPath,
                sourceRootCopyFilter:"**/.svn/*,**/*.java",
                classpath:iajcClasspath
        ){
            sourceroots{
                android.sourceSets.main.java.srcDirs.each{
                    pathelement(location:it.absolutePath)
                }
                pathelement(location:"${project.buildDir}/source/r/${variant.dirName}")
            }
        }
    }
}

Где бы я ни использовал ${variant.dirName} , он будет заменен «debug» или «release» в соответствии с текущей конфигурацией сборки.

Добавление android.jar в путь к классам необходимо для компиляции специфических для Android классов, а для строки pathelement(location:"${project.buildDir}/source/r/${variant.dirName}") требуется использовать классы из файла с автогенератором R.java.

Изменить: Итерации над зависимостями проекта для сборки iajcClasspath позволяют использовать классы из проектов ваших библиотек. configurations.compile.asPath уже содержит ссылку на ваш apklib (файл aar), который на самом деле является почтовым индексом, содержащим как банку, так и ресурсы библиотеки. Iajc не распознает эти файлы как это, но есть каталог пакетов, содержащий класс.jar для вашей библиотеки в каталоге сборки. Я использую относительный путь с «выпуском», жестко закодированным в нем, потому что библиотека имеет другой вариант, чем основной проект в моей ситуации, поэтому я не могу использовать ${variant.dirName} здесь.

Вот полный файл build.gradle:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.5.+'
    }
}
apply plugin: 'android'

repositories {
    mavenCentral()
}

android {
    compileSdkVersion 18
    buildToolsVersion "18.1.0"

    defaultConfig {
        minSdkVersion 7
        targetSdkVersion 18
    }
}

configurations {
    ajc
    aspects
    ajInpath
}

ext.aspectjVersion = '1.7.3'

dependencies {
    compile project(":LibTest")

    ajc "org.aspectj:aspectjtools:${aspectjVersion}"
    compile "org.aspectj:aspectjrt:${aspectjVersion}"
    compile 'com.android.support:appcompat-v7:18.0.0'
}

android.applicationVariants.all { variant ->

    variant.javaCompile.doLast {
        def androidSdk = android.adbExe.parent + "/../platforms/" + android.compileSdkVersion + "/android.jar"

        def iajcClasspath = configurations.compile.asPath + ";" + androidSdk
        configurations.compile.dependencies.each { dep ->
            if(dep.hasProperty("dependencyProject")) {
                iajcClasspath += ":" + dep.dependencyProject.buildDir + "/bundles/release/classes.jar"
            }
        }

        ant.taskdef( resource:"org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties", classpath: configurations.ajc.asPath)
        ant.iajc (
                source:sourceCompatibility,
                target:targetCompatibility,
                destDir:"${project.buildDir}/classes/${variant.dirName}",
                maxmem:"512m",
                fork:"true",
                aspectPath:configurations.aspects.asPath,
                inpath:configurations.ajInpath.asPath,
                sourceRootCopyFilter:"**/.svn/*,**/*.java",
                classpath:iajcClasspath
        ){
            sourceroots{
                android.sourceSets.main.java.srcDirs.each{
                    pathelement(location:it.absolutePath)
                }
                pathelement(location:"${project.buildDir}/source/r/${variant.dirName}")
            }
        }
    }
}
    
ответ дан aegar 11.10.2013 в 00:37
  • Спасибо! Моя единственная проблема сейчас - это аспект j не найти классы из проекта библиотеки, любую идею о том, как исправить это? –  withoutclass 11.10.2013 в 21:23
  • У меня такая же проблема с использованием библиотек, я думал, что будет достаточно добавить проект библиотеки в путь класса iajc, но кажется, что это уже есть: println configurations.compile.asPath показывает путь, начинающийся с /home/aegar/AndroidStudioProjects/AopProject/LibTest/build/libs/LibTest.aar в моем случае, поэтому я думаю, что проблема в том, что iajc не распознает библиотеки aar как это. –  aegar 12.10.2013 в 22:14
  • @withoutclass: iajc теперь распознает мои библиотеки, я обновил ответ. Надеюсь, это сработает и для вас. –  aegar 14.10.2013 в 22:02
  • Большое вам спасибо. Работает как шарм. –  withoutclass 15.10.2013 в 16:58
  • Я хотел бы отметить, что для меня мне нужно было установить источник и цель в «1.6», чтобы создать это. Похоже, что это портит некоторые другие версии Java и вызывает у меня проблемы. –  withoutclass 15.10.2013 в 18:04
Показать остальные комментарии
4

Несмотря на то, что предыдущие скрипты ответов работают в большинстве ситуаций, они не охватывают некоторые проблемы использования Android с AspectJ и Gradle.

Мой тест состоял в том, чтобы создать проект библиотеки, который должен использоваться кем-либо через mavenCentral или мной как проект справочной библиотеки, и проект тестового приложения. Проект библиотеки - это тот, который имеет все аспекты, и прикладной тест пытается использовать эти аспекты. Предоставляя это как контекст, результирующая структура проекта была:

HEAD-Gradle
---LibraryProject
-------SomeAspects
---TestApplication
-------Uses-SomeAspects

Решения, которые я нашел, чтобы заставить его работать:

1- Для проектов библиотеки вы должны использовать

libraryVariants.all { variant -> 

вместо

android.applicationVariants.all { variant ->

2. Созданный dir был изменен для инструментов 19. + build для Android, так как это предлагается в одном комментарии (благодаря «Без Class»), вы должны использовать вместо него взорванный-aar-файл вместо вложенных пакетов определение древовидной переменной. From:

def tree = fileTree(dir: "${project.buildDir}/exploded-bundles", include: '**/classes.jar')

To:

def tree = fileTree(dir: "${project.buildDir}/exploded-aar", include: '**/classes.jar')

3. Последняя проблема, с которой я столкнулся при интеграции, заключалась в том, что если у вас есть проект библиотеки, на нем не были определены аспекты, определенные на дочернем проекте. Чтобы решить эту проблему, вы должны добавить class.jar вашей пользовательской библиотеки в конфигурацию компилятора aspectJ. Вы можете добиться этого, добавив в зависимости:

aspects project(":YourLibraryProject")

, и также необходимо внести некоторые изменения в скрипт, предоставленный в финале этого сообщения.

В настоящий момент лучший сценарий, который я могу себе представить, дает полную поддержку aspectj, использующего даже проекты библиотеки:

Для зависимостей:

configurations {
    ajc
    aspects
    ajInpath
}

//Version of aspectj
def aspectjVersion = '1.8.+'
// The dependencies for this project
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    //Your dependencies to a custom library project
    compile project(":YourLibraryProject")
    aspects project(":YourLibraryProject")
    //Aspectj dependencies
    ajc "org.aspectj:aspectjtools:${aspectjVersion}"
    compile "org.aspectj:aspectjrt:${aspectjVersion}"
}

Сценарий запуска компилятора

android.applicationVariants.all { variant ->

variant.javaCompile.doLast {
    // Find the android.jar and add to iajc classpath
    def androidSdk = android.adbExe.parent + "/../platforms/" + android.compileSdkVersion + "/android.jar"

    def iajcClasspath = androidSdk + ":" + configurations.compile.asPath
    //This line and the fordward assignations allow the aspects support in the child project from the library project
    def customAspectsPath = configurations.aspects.asPath
    configurations.compile.dependencies.each { dep ->
        if(dep.hasProperty("dependencyProject")) {
            iajcClasspath += ":" + dep.dependencyProject.buildDir + "/bundles/${variant.buildType.name}/classes.jar"
            customAspectsPath += ":" + dep.dependencyProject.buildDir + "/bundles/${variant.buildType.name}/classes.jar"
        }
    }

    // handle aar dependencies pulled in by gradle (Android support library and etc)

    def tree = fileTree(dir: "${project.buildDir}/exploded-aar", include: '**/classes.jar')
    tree.each { jarFile ->
        iajcClasspath += ":" + jarFile
    }

    ant.taskdef( resource:"org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties", classpath: configurations.ajc.asPath)
    ant.iajc (
            source:sourceCompatibility,
            target:targetCompatibility,
            destDir:"${project.buildDir}/classes/${variant.dirName}",
            maxmem:"512m",
            fork:"true",
            aspectPath:customAspectsPath,
            inpath:configurations.ajInpath.asPath,
            sourceRootCopyFilter:"**/.svn/*,**/*.java",
            classpath:iajcClasspath
    ){
        sourceroots{
            android.sourceSets.main.java.srcDirs.each{
                pathelement(location:it.absolutePath)
            }
            pathelement(location:"${project.buildDir}/source/r/${variant.dirName}")
        }
    }
}
}

Помните, что если вы хотите запустить AspectJ в проекте library-child, вы должны также иметь этот скрипт в файле build.gradle библиотеки.

    
ответ дан droidpl 18.05.2014 в 01:01
1

В случае использования Android Studio 0.8 или выше, кажется, что использование gradle 0.12. + необходимо.

В градиенте 0.12. +, взорванные aar извлекаются в папке сборки, а не в папке с взорванными-aar.

Поэтому, чтобы обрабатывать зависимости aar, вы должны использовать этот код:

tree = fileTree(dir: "${project.buildDir}", include: '**/classes.jar')
tree.each { jarFile ->
    iajcClasspath += ":" + jarFile
}
    
ответ дан Suhjin Park 27.07.2014 в 08:04
1

Еще один простой способ настроить это - использовать плагин android aspectj, который лучше поддерживается. Ссылка

    
ответ дан Liberty 22.11.2014 в 03:40