SDK项目结构和使用Gradle构建?

时间:2015-02-17 09:29:55

标签: java android android-studio gradle sdk

随着Android Studio成为Android开发的官方IDE,我想从Eclipse迁移一些项目。

我在多个Android示例应用程序中共享了Java库项目。 在Eclipse中,我将Java库项目称为项目依赖项,但是当我分发时,Ant脚本生成库jar并将其复制到Android libs文件夹。我能够轻松地调试我的代码,而不会在分发时暴露库源代码或整个项目。

分发后的最终结果必须是带有文档和库jar的压缩示例应用程序。有什么建议我如何在Android Studio中实现它?

1 个答案:

答案 0 :(得分:0)

经过长时间的搜索,我决定编写自己的自定义gradle插件,但首先是:

项目结构如下:

+--------------------+         +---------------------+
|Workspace (Project) |         |Distributed archive  |
|                    |         |                     |
|                    |         |                     |
|    +------------+  |         |  +---------------+  |
|  +-+    SDK     |  |         |  |  SDK Jar lib  |  |
|  | +------------+  |         |  +---------------+  |
|  |                 |         |                     |
|  | +------------+  +--------->  +---------------+  |
|  +->  Sample 1  |  |         |  |  SDK Javadoc  |  |
|  | +------------+  |         |  +---------------+  |
|  |                 |         |                     |
|  | +------------+  |         |  +---------------+  |
|  +->  Sample 2  |  |         |  | Sample source |  |
|    +------------+  |         |  +---------------+  |
|                    |         |                     |
+--------------------+         |  +----------------+ |
                               |  |   Sample APK   | |
                               |  +----------------+ |
                               |                     |
                               +---------------------+

所以我们有几个项目的工作区:一个用于 SDK(纯Java)几个样本(Java或Android),这取决于它我们想分发一个存档包含:

  • SDK Jar文件
  • SDK Javadoc
  • 其中一个示例应用程序(来源 与SDK jar捆绑在一起)
  • 示例应用APK
  • 存档名称包含日期,版本项目和样本名称等......

在Eclipse中它很简单 - 一些依赖项,Ant脚本和copy-here,copy-there,但现在是时候迁移到Intellij和Android Studio了。这是我成功编写自定义Gradle脚本的尝试:

apply plugin: CustomProcessor


import com.android.build.gradle.AppPlugin
import com.android.build.gradle.LibraryPlugin

class CustomProcessor implements Plugin<Project> {

    private Project mRoot;
    private List<WrappedProject> mProjects = new ArrayList<>();
    private File mDistribOutput;

    class WrappedProject {
        private final Project project;
        private final Object android;

        WrappedProject(Project project) {
            this.project = project;

            if (isLibrary()) {
                this.android = project.plugins.getPlugin(LibraryPlugin)
                project.logger.info "${project.name}: SDK (API) project detected."
            } else if(isApplication()) {
                project.logger.info "${project.name}: Demo (Sample) project detected."
                this.android = project.plugins.getPlugin(AppPlugin)
            } else {
                project.logger.warn "${project.name}: No Android plugin detected."
                this.android = null
            }
        }

        public boolean isLibrary() {
            return project.plugins.any { p -> p instanceof LibraryPlugin }
        }

        public boolean isApplication() {
            return project.plugins.any { p -> p instanceof AppPlugin }
        }
    }

    @Override
    void apply(Project target) {

        this.mRoot = target
        this.mDistribOutput = new File(target.buildDir, "custom")

        target.configure(target.allprojects) { module ->
            module.afterEvaluate {
                def wrapped = new WrappedProject(module)
                mProjects.add(wrapped)

                if (wrapped.isLibrary()) {
                    addSdkTasks(wrapped.project)
                }

                if (wrapped.isApplication()) {
                    addSampleTasks(wrapped.project)
                }
            }
        }
    }

    void addSdkTasks(Object project) {
        project.android.libraryVariants.all { variant ->
            if (variant.name.equalsIgnoreCase("release")) {
                Task t = project.task("generate${project.name.capitalize()}Javadoc", type: Javadoc, overwrite: true) {
                    description "Generates Javadoc for $project.name."
                    source = variant.javaCompile.source
                    ext.androidJar = "${project.android.sdkDirectory}/platforms/${project.android.compileSdkVersion}/android.jar"
                    classpath = project.files(variant.javaCompile.classpath.files) + project.files(ext.androidJar)
                    exclude '**/BuildConfig.java'
                    exclude '**/R.java'
                    failOnError = false
                }
                t.group = 'custom'

                t = project.task("javadoc${project.name.capitalize()}", type: Jar, overwrite: true) {
                    description "Bundles Javadoc into a JAR file for $project.name."

                    classifier = "javadoc"
                    appendix = project.name
                    baseName = mRoot.name
                    version = project.version

                    from project.tasks["generate${project.name.capitalize()}Javadoc"]

                }
                t.group = 'custom'

                t = project.task("jar${project.name.capitalize()}", type: Jar, overwrite: true) {
                    description "Bundles compiled .class files into a JAR file for $project.name."

                    baseName = mRoot.name
                    appendix = project.name
                    version = project.version

                    dependsOn: [project.tasks.assemble ]
                    from variant.javaCompile.destinationDir
                    exclude '**/R.class', '**/R$*.class', '**/R.html', '**/R.*.html'
                }
                t.group = 'custom'
            }
        }
    }

    void addSampleTasks(Object sample) {
        Task t = sample.task(
                "distribute${sample.name.capitalize()}",
                dependsOn: [sample.tasks.assemble, ":sdk:jarSdk", ":sdk:javadocSdk"],
                overwrite: true,
                type: Zip
         ) {
            baseName = mRoot.name
            appendix = project.name
            version = "v${mRoot.project(':sdk').getVersion()}_${getDate()}"
            classifier = 'src'

            from("${project.buildDir}/outputs/apk/") {
                include '**-debug.apk'
                into "apk"
            }

            from("${mRoot.project(':sdk').buildDir}/docs/javadoc") {
                into "doc"
            }

            from("${mRoot.project(':sdk').buildDir}/libs") {
                into "libs"
            }

            from("${mRoot.project(':sdk').buildDir}/libs") {
                into "sample/app/libs"
            }

            from(sample.zipTree("${sample.rootDir}/sample.zip")) {
                into "/"
            }

            from(sample.projectDir) {
                exclude "build"
                exclude "**.iml"
                exclude "build.gradle"
                into "sample/app"
            }
        }
        t.group = 'custom'
    }

    static def getDate() {
        def date = new Date()
        def formattedDate = date.format('yyyyMMddHHmmss')
        return formattedDate
    }
}

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

allprojects {
    repositories {
        jcenter()
    }
}

要在Android Studio中将示例源生成为可打开的项目,我使用sample.zip这是空的Android Studio项目模板。