Как создать баннер библиотеки Android с помощью gradle без публичного раскрытия исходного кода?

Я хотел бы создать Jar из проекта библиотеки Android. Он настраивается следующим образом:

ProjectName
    \- lib
    |   \- lib
    |       \- armeabi
    |           \- libNativeFirst.so
    |           \- libNativeSecond.so
    \- src
        \- main
            \- java
                \- com.package.sdk
                    \- PackageSDK.java

Я бы хотел, чтобы все это было упаковано в Jar, но не обнаружило исходный код, присутствующий в PackageSDK.java.

Я установил свой файл build.gradle следующим образом:

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

apply plugin: 'android-library'

repositories {
    mavenCentral()
}

android {
    compileSdkVersion 18
    buildToolsVersion "18.0.1"

    defaultConfig {
        minSdkVersion 10
        targetSdkVersion 18
    }

    sourceSets {
        main {
            java {
                srcDir 'src/main/java'
            }
            resources {
                srcDir 'src/../lib'
            }
        }
    }
}

task jar(type: Jar) {
    from android.sourceSets.main.allSource
}

Когда я запускаю gradlew clean jar в каталоге проекта, файл Jar создается в ProjectName\build\libs, называемом ProjectName.jar. Его структура выглядит следующим образом:

ProjectName.jar
    \- lib
    |   \- armeabi
    |       \- libNativeFirst.so
    |       \- libNativeSecond.so
    \- com
        \- package
            \- sdk
                \- PackageSDK.java

Я хотел бы, чтобы скомпилированный PackageSDK.class был включен вместо файла PackageSDK.java при выполнении задачи jar. Что я могу изменить для достижения этого?

Изменить:

В предложении Бена Манеса я изменил конфигурацию sourceSets на следующее:

sourceSets {
    main {
        java {
            srcDir 'src/main/java'
        }
        resources {
            srcDir 'src/../lib'
        }
        output {
            classesDir 'build/classes'
            resourcesDir 'build/javaResources'
        }
    }
}

И задача jar:

task jar(type: Jar) {
    from android.sourceSets.main.output
}

Gradle теперь дает мне этот результат:

Could not find method output() for arguments [build_25r1m0[email protected]138532dc] on source set main.

Ответ 1

Примечание: Ответ отредактирован. См. Обновление от 07/28/2014 ниже.

Вот решение, с которым я столкнулся. Там может быть лучший способ, но я еще не нашел его.

android {
    compileSdkVersion 18
    buildToolsVersion "18.0.1"

    defaultConfig {
        minSdkVersion 10
        targetSdkVersion 18
    }

    sourceSets {
        main {
            java {
                srcDir 'src/main/java'
            }
            resources {
                srcDir 'src/../lib'
            }
        }
    }
}

task clearJar(type: Delete) {
    delete 'build/libs/ProjectName.jar'
}

task makeJar(type: Copy) {
    from('build/bundles/release/')
    into('build/libs/')
    include('classes.jar')
    rename ('classes.jar', 'ProjectName.jar')
}

makeJar.dependsOn(clearJar, build)

Запуск gradlew makeJar создает ProjectName.jar в каталоге build/libs. Структура этой банки следующая:

ProjectName.jar
    \- lib
    |   \- armeabi
    |       \- libNativeFirst.so
    |       \- libNativeSecond.so
    \- com
        \- package
            \- sdk
                \- PackageSDK.class

Это точный результат, который мне нужен. Теперь я могу использовать ProjectName.jar в других проектах.

EDIT: Хотя я могу использовать полученную банку в проектах в Android Studio, я не могу сделать этого в проектах, созданных в ADT, из-за предупреждения о том, что собственный код присутствует в файле jar. Предположительно, есть флажок, чтобы отключить эту проверку в настройках, но он работает неправильно. Таким образом, если вы хотите создать библиотеку, которая использует собственный код, те, кто использует ADT, должны будут вручную скопировать каталог armeabi в libs/.

28.07.2014 Обновление:

Начиная с Android Studio 0.8.0, Gradle были изменены каталоги вывода, и описанная выше конфигурация не будет работать. Я изменил свою конфигурацию на следующее:

task clearJar(type: Delete) {
    delete 'build/outputs/ProjectName.jar'
}

task makeJar(type: Copy) {
    from('build/intermediates/bundles/release/')
    into('build/outputs/')
    include('classes.jar')
    rename ('classes.jar', 'ProjectName.jar')
}

ВАЖНО: Обратите внимание, что ProjectName.jar теперь будет помещаться в build/outputs/ и NOT в build/libs/.

Ответ 2

Просто чтобы добавить небольшую альтернативу @BVB-ответу (хотя и в значительной степени основанный на нем), здесь я должен был сделать вывод jar myapp-api.jar, который был для проекта только на Java, который касался взаимодействия с API-интерфейсом. Это зависит от Android.jar, поэтому необходимо использовать apply plugin: 'com.android.application', а не только apply plugin: 'java'

Вызов ./gradlew build jar из myJavaAPIProject для сборки и генерации .jar в myJavaAPIProject/build/libs/myapp-api.jar

build.gradle

//Even though this is a Java project, we need to apply the android plugin otherwise it cannot find the SDK/android.jar and so cannot compile
apply plugin: 'com.android.application'

dependencies {
    //this ensures we have gson.jar and anything else in the /lib folder
    compile fileTree(dir: 'lib', include: '*.jar')
}

repositories {
    mavenCentral()
}
android{
    compileSdkVersion 21
    buildToolsVersion "21.0.1"

    defaultConfig {
        minSdkVersion 10
        targetSdkVersion 21
    }

    sourceSets {
        main {
            java {
                //points to an empty manifest, needed just to get the build to work
                manifest.srcFile 'AndroidManifest.xml'
                //defined our src dir as it not the default dir gradle looks for
                java.srcDirs = ['src']

            }
        }
    }

    //enforce java 7
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }
}

//Actually created the .jar file
task jar(type: Jar) {
    //from android.sourceSets.main.java
    from 'build/intermediates/classes/release/'
    archiveName 'myapp-api.jar'
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- this is a dummy file needed to ensure gradle validates and builds ok -->
<manifest
    package="com.myapp.android"
    />