【问题标题】:Android new build system (gradle) and aspectjAndroid新构建系统(gradle)和aspectj
【发布时间】:2013-06-21 22:46:55
【问题描述】:

在 Google IO 中,宣布新的构建系统 gradle 将取代 ant。 我的项目正在使用 aspectj,我想在我的项目中使用它。 我想不出一些变量来让它工作。我在那里找不到 android.* 输出类路径。有人可以帮忙吗?

这是我当前的 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)
            }  
        }  
    }  
}

这是运行良好的旧 ant 代码: http://code.google.com/p/anymemo/source/browse/custom_rules.xml

编辑:

根据第一个答案更新了 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]              

编辑: 这是适用于我的项目的最终 build.gradle 文件: https://code.google.com/p/anymemo/source/browse/build.gradle?spec=svnf85aaa4b2d78c62876d0e1f6c3e28252bf03f820&r=f85aaa4b2d78c62876d0e1f6c3e28252bf03f820

【问题讨论】:

  • 对于你的新错误,我尝试通过添加一个 jar 库来重现它,但它对我来说工作正常。
  • 我猜该错误与库本身无关,因为 iajc 似乎找到了您的 GraphicsActivity,但它可能是错误的 sdk 路径:您的所有错误都与来自活动的方法有关t 在 GraphicsActivity 或在构造函数中未被识别为活动的 GraphicsActivity 中找到。你检查了androidSdk var吗?我的指向“/home/aegar/android-sdk/platforms”中的某个地方,我只有 android-18。
  • 这是 AAR 依赖问题。 AAR 不能用作 jar。您处理了dependencyProject,但是,如果您指定编译'com.android.support:appcompat-v7:18.0.0',则classes.jar在exploded-bundle中,该目录中的所有jar都需要添加到类路径中。

标签: java android gradle


【解决方案1】:

我还想将 aspectj 与 gradle 和 Android Studio 一起使用,我终于让它工作了,但我仍然有一些我想用更通用的 gradle 选项替换的手写路径。

编辑:我用基于 gradle 的替代方案替换了每个硬编码的绝对路径,因此这个解决方案不再依赖于给定的平台或用户名。但是,它仍然使用相对路径,这些路径可能会从 IDE 更改为其他 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},都会根据当前的构建配置将其替换为“调试”或“发布”。

需要将 android.jar 添加到类路径中才能编译 Android 特定的类,而 pathelement(location:"${project.buildDir}/source/r/${variant.dirName}") 行需要使用自动生成的 R.java 文件中的类。

编辑: 对项目依赖项的迭代以构建 iajcClasspath 允许您使用库项目中的类。 configurations.compile.asPath 已经包含对您的 apklib(aar 文件)的引用,它实际上是一个包含 jar 和库资源的 zip。 Iajc 无法识别这些文件,但在 build 目录下有一个包含您的库的 classes.jar 的 bundle 目录。我使用了一个相对路径,其中硬编码了“发布”,因为在我的情况下,库的变体与主项目不同,所以我不能在这里使用${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}")
            }
        }
    }
}

【讨论】:

  • 谢谢!我现在唯一的问题是 aspectj 没有从库项目中找到类,知道如何解决这个问题吗?
  • 我对库的使用也有同样的问题,我认为将库项目添加到 iajc 类路径就足够了,但似乎已经在其中:println configurations.compile.asPath 显示路径在我的情况下以 /home/aegar/AndroidStudioProjects/AopProject/LibTest/build/libs/LibTest.aar 开头,所以我认为问题在于 iajc 无法识别 aar 库。
  • @withoutclass:iajc 现在可以识别我的库,我更新了答案。我希望它也对你有用。
  • 非常感谢。像魅力一样工作。
  • 我想指出,对我来说,我需要将源和目标设置为“1.6”才能构建它。似乎它默认为其他一些 java 版本并导致我出现问题。
【解决方案2】:

我发现 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)

有关完整示例,请在此处查看 AnyMemo 项目的 build.gradle: https://code.google.com/p/anymemo/source/browse/build.gradle?spec=svnf85aaa4b2d78c62876d0e1f6c3e28252bf03f820&r=f85aaa4b2d78c62876d0e1f6c3e28252bf03f820

【讨论】:

  • 注意:使用工具 19 我认为他们可能已经改变了位置。我需要使用“exploded-aar”而不是上面示例中的“exploded-bundles”。
  • 无类,是的,他们改名了。 code.google.com/p/anymemo/source/browse/… 有变化。
  • 谢谢!在我放弃并看这里之前,我错过了这篇文章并与 aegar 答案作斗争。这个答案需要更多的支持。
【解决方案3】:

虽然之前的答案脚本适用于大多数情况,但它们并未涵盖将 Android 与 AspectJ 和 Gradle 一起使用的一些问题。

我的测试是创建一个库项目,任何人都应该通过 mavenCentral 或我将其用作参考库项目和测试应用程序项目。库项目是具有所有方面的项目,应用程序测试试图使用这些方面。 以此为背景,最终的项目结构是:

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

我发现使它起作用的解决方案是:

1- 对于你必须使用的库项目

libraryVariants.all { variant -> 

而不是

android.applicationVariants.all { variant ->

2- 为 Android 的 19.+ 构建工具更改了构建目录,因此正如一条评论中所建议的(感谢“WithoutClass”),您必须在树变量定义。 来自:

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

收件人:

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

3- 我在进行集成时遇到的最后一个问题是,如果您有一个库项目,则在子项目中找不到在其上定义的方面。要解决这个问题,您必须将自定义库的 classes.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,您还必须在库的 build.gradle 中拥有此脚本。

【讨论】:

    【解决方案4】:

    在使用Android Studio 0.8或以上的情况下,似乎需要使用gradle 0.12.+。

    在 gradle 0.12.+ 中,exploded aar 是在 build 文件夹中提取的,而不是在 exploded-aar 文件夹中。

    因此,为了处理aar依赖,你必须使用这段代码:

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

    【讨论】:

      【解决方案5】:

      另一种更简单的设置方法是使用维护得更好的 android aspectj 插件。 https://github.com/uPhyca/gradle-android-aspectj-plugin

      【讨论】:

        猜你喜欢
        • 2012-11-27
        • 2014-05-21
        • 2013-06-17
        • 1970-01-01
        • 2013-08-22
        • 2013-05-16
        • 2012-07-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多