Добавить зависимости через gradle для затмения в проекте android

У меня проблема с автоматической добавлением зависимостей для проекта eclipse android через gradle. У меня есть лишь немного опыта работы с gradle. До сих пор я создал два проекта java с gradle. Одна банка и исполняемая банка. Это работает без проблем. Я использовал плагин eclipse для создания проекта eclipse и добавления зависимостей к пути сборки. Я добавил новые зависимости к gradle script, запустил gradle с gradle eclipse, обновил мой проект и зависимости существуют в пути сборки, и я могу их использовать. Вот важная часть этого script.

apply plugin: 'java'
apply plugin: 'eclipse'
repositories {
   mavenCentral()
}

dependencies {
   compile 'commons-io:commons-io:2.4'
}

Итак, теперь я попробовал его в сочетании с плагином Android. Вот моя дыра gradle script.

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

apply plugin: 'android'
apply plugin: 'eclipse'

repositories {
mavenCentral()
}

dependencies {
compile 'org.apache.commons:commons-lang3:3.1'
}

android {
    compileSdkVersion 17
    buildToolsVersion "17"

    defaultConfig {
        minSdkVersion 14
        targetSdkVersion 17
    }
    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('tests')
    }
}

Если я использую gradle eclipse, ничего не происходит. Затем я узнал, что плагин java добавляет зависимости к пути сборки. Поэтому я добавил

apply plugin: 'java'

и получил ошибку, что java-плагин несовместим с плагином Android. Затем я нашел решение для автоматического копирования баннеров в папку lib проекта.

def libDir = file('libs')

task copyLibs(type: Copy) {

    doFirst {
        libDir.mkdirs()
    }
    from configurations.runtime
    into libDir
}

Но для этой задачи также нужен плагин java для конфигураций .runtime. Мне нужен плагин android для создания файла apk, поэтому он не является решением для удаления плагина android. Есть ли у кого-нибудь идея, можно ли добавить зависимости к пути сборки или папке lib в проекте ecipse, совместимом с плагином Android?

EDIT: Одна из моих идей заключалась в том, чтобы поместить java-плагин в eclipse-plugin, так что он будет применяться только при использовании плагина eclipse. Что-то вроде этого:

apply plugin: 'eclipse'

eclipse{
    apply plugin: 'java'
}

Но я все еще получаю сообщение о том, что плагины java и android не совместимы. Возможно, я понимаю, что gradle неправильно, но обычно плагин java должен применяться только тогда, когда я запускаю плагин eclipse, а не плагин Android. Я боюсь, что мое понимание и опыт gradle недостаточно хороши, чтобы решить это так или понять, почему это невозможно.

Ответ 1

Мое решение основано на Rafael's, поскольку оно копирует зависимости в каталог libs, который используется только Android. Однако я продолжаю полностью взорвать ссылку AAR для использования в Eclipse.

Gradle Файл сборки

Добавьте к концу своих Android-проектов следующее: build.gradle:

task copyJarDependencies(type: Copy) {
    description = 'Used for Eclipse. Copies all dependencies to the libs directory. If there are any AAR files it will extract the classes.jar and rename it the same as the AAR file but with a .jar on the end.'
    libDir = new File(project.projectDir, '/libs')
    println libDir
    println 'Adding dependencies from compile configuration'
    configurations.compile.filter {it.name.endsWith 'jar'}.each { File file -> moveJarIntoLibs(file)}
    println 'Adding dependencies from releaseCompile configuration'
    configurations.releaseCompile.filter {it.name.endsWith 'jar'}.each { File file -> moveJarIntoLibs(file)}
    println 'Adding dependencies from debugCompile configuration'
    configurations.debugCompile.filter {it.name.endsWith 'jar'}.each { File file -> moveJarIntoLibs(file)}
    println 'Adding dependencies from instrumentTestCompile configuration'
    configurations.instrumentTestCompile.filter {it.name.endsWith 'jar'}.each { File file -> moveJarIntoLibs(file)}
    println 'Extracting dependencies from compile configuration'
    configurations.compile.filter {it.name.endsWith 'aar'}.each { File file -> moveAndRenameAar(file) }
    println 'Extracting dependencies from releaseCompile configuration'
    configurations.releaseCompile.filter {it.name.endsWith 'aar'}.each { File file -> moveAndRenameAar(file) }
    println 'Extracting dependencies from debugCompile configuration'
    configurations.debugCompile.filter {it.name.endsWith 'aar'}.each { File file -> moveAndRenameAar(file) }
    println 'Extracting AAR dependencies from instrumentTestCompile configuration'
    configurations.instrumentTestCompile.filter {it.name.endsWith 'aar'}.each { File file -> moveAndRenameAar(file) }
}

void moveJarIntoLibs(File file){
    println 'Added jar ' + file
        copy{
            from file
            into 'libs'
        }
}

void moveAndRenameAar(File file){
    println 'Added aar ' + file
    def baseFilename = file.name.lastIndexOf('.').with {it != -1 ? file.name[0..<it] : file.name}

    // directory excluding the classes.jar
    copy{
        from zipTree(file)
        exclude 'classes.jar'
        into 'libs/'+baseFilename
    }

    // Copies the classes.jar into the libs directory of the expoded AAR.
    // In Eclipse you can then import this exploded ar as an Android project
    // and then reference not only the classes but also the android resources :D 
    copy{
        from zipTree(file)
        include 'classes.jar'
        into 'libs/' + baseFilename +'/libs'
        rename { String fileName ->
            fileName.replace('classes.jar', baseFilename + '.jar')
        }
    }
}

Здание с Gradle

Запуск:

"gradle clean build"

Вы должны найти все зависимости и взорванные AAR в каталоге libs. Это все, что нужно Eclipse.

Импорт в Eclipse

Теперь здесь начинается реальная польза. После того, как вы создали каталог libs с шага gradle выше, вы заметите, что там есть папки. Эти новые папки представляют собой взорванные зависимости AAR из файла build.gradle.

Теперь классная часть заключается в том, что при импорте существующего Android-проекта в Eclipse он также обнаружит взорванные папки AAR в качестве проектов, которые он может импортировать тоже!

1. Импортируйте эти папки в каталог libs, не импортируйте папки 'build', они генерируются Gradle

2. Убедитесь, что вы выполняете Проект → Очистить во всех проектах AAR, которые вы добавили. В своей рабочей области проверьте, что каждый проект с разнесением AAR имеет следующие свойства project.properties:

target=android-<YOUR INSTALLED SKD VERSION GOES HERE>
android.library=true

3. Теперь в вашем основном проекте Android вы можете просто добавить ссылки на библиотеку либо с помощью ADT, либо просто отредактировать файл project.properties и добавить

android.libraries.reference.1=libs/someExplodedAAR/

4. Теперь вы можете щелкнуть правой кнопкой мыши свой основной проект Android и Запустить как → Приложение Android.

Но что это значит?

  • Ну, это означает, что вам не нужен исходный код для любых ваших зависимостей Android AAR gradle, чтобы ссылаться как на его классы, так и на ресурсы в Eclipse.

  • gradle build script выше берет файл AAR и готовит его для использования в Eclipse. Как только вы добавите его в рабочее пространство, вы сможете просто сосредоточиться на своем реальном проекте Android.

  • Теперь вы можете отлаживать и разрабатывать с использованием Eclipse и развертывать с использованием ADT с зависимостями AAR, которые правильно вложены в APK. Когда вам нужно сделать некоторые конкретные сборки, вы можете использовать gradle.

Ответ 2

Наконец, я нашел решение, которое работает для меня. Эта задача копирует зависимости в папку проектов libs.

task copyDependencies(type: Copy) 
{
    description = 'Copy depencies to libs. Useful for Eclipse'
    libDir = new File(project.projectDir, '/libs')
    println libDir
    println 'Adding dependencies from compile configuration'
    for(file in configurations.compile) 
    {
        println 'Added ' + file
        copy 
        {
            from file
            into libDir
        }
    }
    println 'Adding dependencies from releaseCompile configuration'
    for(file in configurations.releaseCompile)
    {
        println 'Added ' + file
        copy
        {
            from file
            into libDir
        }
    }
    println 'Adding dependencies from debugCompile configuration'
    for(file in configurations.debugCompile)
    {
        println 'Added ' + file
        copy
        {
            from file
            into libDir
        }
    }

    println 'Adding dependencies from instrumentTestCompile configuration'
    for(file in configurations.instrumentTestCompile)
    {
        println 'Added ' + file
        copy
        {
            from file
            into libDir
        }
    }
}

Ответ 3

Следующая задача gradle просто объединяет зависимости gradle в путь класса eclipse. Добавьте его в build.gradle и вызовите его с помощью gradle gradleDep2EclipseClasspath.

  import groovy.xml.StreamingMarkupBuilder
  task gradleDep2EclipseClasspath() {
     description "Merge gradle dependencies into the eclipse class path"

     def files = ["compile", "releaseCompile", "debugCompile", "instrumentTestCompile"]
       .collect {project.configurations[it].files}
       .inject([] as Set) {result, files -> result + files}
       .asList()
       .unique()
       .grep {! [email protected]().contains("android-support")}

      def classpath = new XmlParser().parse(file(".classpath"))
      def libs = classpath.grep {it.'@gradle-dependency' == "true"}
      libs.each {classpath.remove(it)}

      files.collect {file ->
         new Node(null, "classpathentry", [
           "path": file.toString(),
           "kind": "lib",
           "exported": "true",
           "gradle-dependency": "true"
         ])
      }.each {classpath.append(it)}

      file(".classpath").withWriter {writer ->
         writer << new StreamingMarkupBuilder().bind { mkp.xmlDeclaration() }
         def printer = new XmlNodePrinter(new PrintWriter(writer))
         printer.print(classpath)
      }
   }

Ответ 4

Благодаря решению JavaJedi я создал еще один, используя Gradle аннотации ввода/вывода. Он основан на тех же принципах, но является более общим в использовании (например, вы можете легко определить новые задачи типа CopyJars или ExtractAars) и разрешить Gradle решать, требуется ли копирование файлов или нет.

Ответ 5

Вот мое решение, основанное на всех предыдущих решениях от @JavaJedi и @gubaer.

Шаг 1

Добавьте copyAars задачу для сборки. Он распаковывает и копирует зависимости AAR в специальную папку "deps", а не в "libs", чтобы избежать конфликтов с Android Studio и/или другими плагинами и задачами Gradle. После этого все взорванные AARs должны быть импортированы вручную в виде проектов Android Library и добавлены как зависимости от основного проекта в Eclipse. Это модифицированное решение от @JavaJedi.

task copyAars << {
    configurations.compile.filter { it.name.endsWith 'aar' }.each { File file -> copyAndRenameAar(file) }
}

void copyAndRenameAar(File file) {
    println 'Added aar ' + file
    def baseFilename = file.name.lastIndexOf('.').with { it != -1 ? file.name[0..<it] : file.name }

    // directory excluding the classes.jar
    copy {
        from zipTree(file)
        exclude 'classes.jar'
        into "deps/aars/exploded/" + baseFilename
    }

    // Copies the classes.jar into the libs directory of the expoded AAR.
    // In Eclipse you can then import this exploded aar as an Android project
    // and then reference not only the classes but also the android resources
    copy {
        from zipTree(file)
        include 'classes.jar'
        into "deps/aars/exploded/" + baseFilename + "/libs"
        rename { String fileName -> fileName.replace('classes.jar', baseFilename + '.jar') }
    }
}

Шаг 2

Добавьте eclipseClasspath задачу для сборки. Зависимости JAR добавляются по-другому. Они фильтруются и добавляются непосредственно в файл .classpath, поэтому они автоматически доступны в основном проекте Eclipse. Это модифицированное решение от @gubaer. Он включает только JAR, за исключением AAR, и только из конфигурации "компиляции", но вы можете легко добавить больше конфигураций.

task eclipseClasspath << {
    def classpath = new XmlParser().parse(file(".classpath"))
    def libs = classpath.grep { it.'@gradle-dependency' == "true" }
    libs.each { classpath.remove(it) }

    configurations.compile.filter { it.name.endsWith 'jar' }
    .collect { file ->
        new Node(null, "classpathentry", [
            "path": file.toString(),
            "kind": "lib",
            "exported": "true",
            "gradle-dependency": "true"
        ])
    }
    .each { classpath.append(it) }

    file(".classpath").withWriter { writer ->
        writer << new groovy.xml.StreamingMarkupBuilder().bind { mkp.xmlDeclaration() }
        def printer = new XmlNodePrinter(new PrintWriter(writer))
        printer.print(classpath)
    }
}

Шаг 3

Установите http://marketplace.eclipse.org/content/java-source-attacher плагин в Eclipse. После этого вы сможете щелкнуть правой кнопкой мыши по каждому JAR и выбрать "Прикрепить источник Java". Для зависимостей Gradle это работает 99% времени в моем опыте.