Gradle总结

作者: 坚坚老师 | 来源:发表于2016-01-22 17:05 被阅读1033次

    0x00 前言

    Android studio默认使用Gradle构建Android工程。我之前有花一段时间研究Gradle,在此总结一下!
    Gradle跟ant/maven一样,是一种依赖管理/自动化构建工具。但是跟ant/maven不一样,它并没有使用xml语言,而是采用了Groovy语言(语法类似于Java),这使得它更加简洁、灵活,更加强大。
    Gradle的安装略,百度一大堆。

    0x01 HelloWorld

    先写个hello world吧!

    task hello << {
        println 'Hello world!'
    }
    

    执行段语句:gradle -q hello,-q表示不显示log,相应的还可以 -info-debug来查看详细的log信息。

    LogLevel
    然后输出的内容是:Hello world!
    这就是一个简单的gradle文件。里面定义了一个task:hello。执行打印任务。
    当使用gradle命令行执行task时,每个task只会被执行一次,所以gradle test test和gradle test命令的执行结果是一模一样的。

    0x02 Gradle Plugin

    看了上面的例子,我们知道如何定义一个任务,但是在Android开发时我们看到的Gradle并没有定义task。因为在Android中我们默认添加了Gradle的Android插件:apply plugin: 'com.android.application'com.android.application中默认定义了我们一些常用的task:

    build:    完整编译项目,包含编译,测试和创建jar包  
    clean:    删除build目录 
    assemble:  编译和创建jar包
    check:    编译和测试代码
    

    我们在一个gradle中可以使用多个插件。正如我们的项目使用crashlytics进行bug收集统计,那么我们的项目中还得依赖apply plugin: 'io.fabric'插件。

    0x03 Android Gradle

    在Android Studio新建Android项目现在默认使用gradle构建。使用gradle构建在规范的目录结构与以前ADT生成的有很大的不同了。Gradle要求的一些规范:工程源码位于$workspace/app/src/main/java,测试代码位于$workspace/app/src/test/java。所有位于$workspace/app/src/main/res文件都被包含到jar包中作为资源文件,所有的输出文件都会放在build目录里面,jar文件放在$workspace/app/build/libs目录下。
    详细目录咱们可以通过命令gradlew app:sourceSets来查看:

    main                           
    ----                           
    Compile configuration: compile 
    build.gradle name: android.sourceSets.main
    Java sources: [app\src\main\java]
    Manifest file: app\src\main\AndroidManifest.xml
    Android resources: [app\src\main\res]
    Assets: [app\src\main\assets]  
    AIDL sources: [app\src\main\aidl]
    RenderScript sources: [app\src\main\rs]
    JNI sources: [app\src\main\jni]
    JNI libraries: [app\src\main\jniLibs]
    Java-style resources: [app\src\main\resources]
    

    对于添加工程依赖也方便了很多,咱们可以通过dependencies来依赖工程,依赖生成的文件路径为:$workspace/app/build/intermediates/exploded-aar/***。依赖格式如下:

    dependencies {
        compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'
    }
    缩写形式 “group:name:version”.
    dependencies {
        compile 'org.hibernate:hibernate-core:3.6.7.Final'
    }
    

    note:-x命令用来排除一些命令的执行,比如gradle build -x ext,会在编译的时候不执行ext任务,即使build task依赖ext也不会执行, 但ext所依赖的task如果被其他task依赖是会执行的。
    dependenciesDSL 元素是标准的 Gradle API 的一部分,不属于android 元素内。

    dependencies {
        compile files('libs/test.jar')
    }
    

    0x04 Gradlew

    在项目的根目录下我们看到有gradlew/gradlew.bat文件,gradlew代表 gradle wrapper,意思是gradle的一层包装,大家可以理解为在这个项目本地就封装了gradle,即gradle wrapper, 在$workspace/gradle/wrapper/gralde-wrapper.properties文件中声明了它指向的目录和版本。只要下载成功即可用grdlew wrapper的命令代替全局的gradle命令。第一次执行gradlew *时系统会下载创建项目时使用的gradle环境,时间会比较长。下载完后就可以直接像gradle一样使用了。

    省略写法:gradle assembleRelease --> gradle aR

    gradlew tasks
    gradlew tasks --all
    可以得到一个完整的任务列表,并且看到任务运行之间的依赖关系。

    0x05 Gradle Build

    Gradle编译过程如图:


    build.png

    我们可以查看gradle执行过程,比如我们要编译一个welove渠道的release包,执行gradle aWR >>1.txt>>1.txt表示将打印的内容重定向到记事本中,得到的内容:

    :app:preBuild UP-TO-DATE
    :app:preWeloveReleaseBuild UP-TO-DATE
    :app:checkWeloveReleaseManifest
    :app:preWeloveDebugBuild UP-TO-DATE
    :app:prepareComAndroidSupportAppcompatV72200Library UP-TO-DATE
    :app:preWeloveDebugAndroidTestBuild UP-TO-DATE
    :app:prepareComAndroidSupportMultidex101Library UP-TO-DATE
    :app:prepareComAndroidSupportRecyclerviewV72200Library UP-TO-DATE
    :app:prepareComAndroidSupportSupportV42200Library UP-TO-DATE
    :app:prepareWeloveReleaseDependencies
    :app:compileWeloveReleaseAidl UP-TO-DATE
    :app:compileWeloveReleaseRenderscript UP-TO-DATE
    :app:generateWeloveReleaseBuildConfig UP-TO-DATE
    :app:generateWeloveReleaseAssets UP-TO-DATE
    :app:mergeWeloveReleaseAssets UP-TO-DATE
    :app:generateWeloveReleaseResValues UP-TO-DATE
    :app:generateWeloveReleaseResources UP-TO-DATE
    :app:mergeWeloveReleaseResources UP-TO-DATE
    :app:processWeloveReleaseManifest UP-TO-DATE
    :app:processWeloveReleaseResources UP-TO-DATE
    :app:generateWeloveReleaseSources UP-TO-DATE
    :app:compileWeloveReleaseJavaWithJavac UP-TO-DATE
    :app:compileWeloveReleaseNdk UP-TO-DATE
    :app:compileWeloveReleaseSources UP-TO-DATE
    :app:lintVitalWeloveRelease
    :app:processWeloveReleaseJavaRes UP-TO-DATE
    :app:transformResourcesWithMergeJavaResForWeloveRelease UP-TO-DATE
    :app:transformClassesAndResourcesWithProguardForWeloveRelease UP-TO-DATE
    :app:collectWeloveReleaseMultiDexComponents UP-TO-DATE
    :app:transformClassesWithMultidexlistForWeloveRelease UP-TO-DATE
    :app:transformClassesWithDexForWeloveRelease UP-TO-DATE
    :app:mergeWeloveReleaseJniLibFolders UP-TO-DATE
    :app:transformNative_libsWithMergeJniLibsForWeloveRelease UP-TO-DATE
    :app:validateReleaseConfigSigning
    :app:packageWeloveRelease UP-TO-DATE
    :app:zipalignWeloveRelease UP-TO-DATE
    :app:assembleWeloveRelease
    
    BUILD SUCCESSFUL
    
    Total time: 46.918 secs
    

    对比上图可以体会gradle打包的过程!
    0x06 Gradle Demo
    ==
    放出我们项目工程的gradle,删除部分关键信息,给大家做个参考,如下:

    android {
        compileSdkVersion 22
        buildToolsVersion "22.0.1"
    
        defaultConfig {
            applicationId "***"
            minSdkVersion 10
            targetSdkVersion 22
            versionCode 1
            versionName "1.0"
            multiDexEnabled true
        }
    
        // 配置keystore签名
        signingConfigs {
            releaseConfig {
                storeFile file('release-key.keystore')
                keyAlias "releasekey"
                storePassword "Replace Valid Store Password"
                keyPassword "Replace Valid Key Password"
            }
        }
    
        buildTypes {
            debug {
    
            }
    
            release {
                minifyEnabled true  // 进行混淆
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
                signingConfig signingConfigs.releaseConfig
            }
        }
    
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_7
            targetCompatibility JavaVersion.VERSION_1_7
        }
    
        // 平台定制
        productFlavors {
            welove {}
        }
    
        lintOptions {
            ignoreWarnings true // 只报告错误
            checkReleaseBuilds true    // release构建时issus的严重级为fatal,若发现了致命(fatal)的问题,则中止构建
            abortOnError false  // 当lint发现错误时停止 gradle构建
        }
    
        // 通过查看打包顺序发现打welove的Release包时,第三步就是执行checkWeloveReleaseManifest
        // 而且在打Debug包时不会执行checkWeloveReleaseManifest,为了自动执行releaseCheck 增加以下代码
        tasks.whenTaskAdded { task ->
            if (task.name == 'checkWeloveReleaseManifest') {
                task.dependsOn releaseCheck
            }
        }
    }
    
    dependencies {
        // 编译libs目录下的所有jar包
        compile fileTree(dir: 'libs', include: ['*.jar'])
        compile 'com.android.support:support-v4:22.0.0'
        compile 'com.android.support:appcompat-v7:22.0.0'
        compile 'com.android.support:recyclerview-v7:22.0.0'
        compile 'com.android.support:multidex:1.0.1'
        compile('com.crashlytics.sdk.android:crashlytics:2.5.5@aar') {
            transitive = true
        }
    }
    
    import java.util.regex.Pattern
    task releaseCheck <<{
        // 检查 baidu api key 是不是有效值
        def baiduApiFile = file("$workspace/tools/WeloveConstants.java")
        def baiduApiFilePattern = Pattern.compile("\\s*public static final String BAIDU_MAP_API_KEY = ResourceUtil.getStr\\(R.string.(.*)\\)")
        def baiduApiFileMatcher = baiduApiFilePattern.matcher(baiduApiFile.getText())
        if (baiduApiFileMatcher.find()){
            def baiduApiUrl = baiduApiFileMatcher.group(1)
            if (!baiduApiUrl.equals("str_baidu_map_api_key")){
                throw new GradleException(baiduApiFile.toString() + " Contain Invalid Baidu API Key ")
            }
        }else {
            throw new GradleException(baiduApiFile.toString() + " Contain Invalid Baidu API Key ")
        }
    }
    

    因为使用crashlytics,所以根目录的build.gradle文件也贴出来:

    buildscript {
        repositories {
            jcenter()
            maven { url 'https://maven.fabric.io/public' }
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:1.5.0'
            classpath 'io.fabric.tools:gradle:1.+'
        }
    }
    
    allprojects {
        repositories {
            jcenter()
            maven { url 'https://maven.fabric.io/public' }
        }
    }
    

    0x07 参考资料

    Gradle 官方文档翻译: 文档一文档二
    Android Gradle插件: 文档

    相关文章

      网友评论

      本文标题:Gradle总结

      本文链接:https://www.haomeiwen.com/subject/juclhttx.html