Android Gradle权威指南

1.Android Gradle插件介绍

  我们知道Android起始就是Gradle的一个第三方插件,它是由Google的Android开发团队开发的。但从Android的角度来看,Android插件是基于Gradle构建的,和AndroidStudio完美无缝搭配的新一代构建系统。

2.Android Gradle插件分类

在Android中有3类工程
  1.App应用工程,他可以生成一个可运行的apk应用。
   App插件id :com.android.application

  2.Library库工程,他可以生成AAR包给其他App工程公用,就和我们的Jar一样,但是它包含了Android的资源等信息。
   Library插件id :com.android.library

  3.Test测试工程,用于对App工程或者Library库工程进行单元测试
   Test插件id :com.android.test

3.Android Gradle工程配置介绍

 

apply plugin: 'com.android.application'

android {
    compileSdkVersion 29              //配置我们编译Android工程的SDK,29是AndroidSDK的API Level
    buildToolsVersion "29.0.2"        //Android构建工具的版本

    //默认配置
    defaultConfig {
        applicationId "com.ych.androidgradle"  //包名
        minSdkVersion 15                       //最低支持的Android系统API
        targetSdkVersion 29                    //我们基于那个Android版本开发的
        versionCode 1                          //App应用内部版本号
        versionName "1.0"                      //App应用版本名称
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"  //用于配置单元测试时使用的Runner
        singingConfig singingConfigs.debug     //默认配置签名信息
        multiDexEnabled true      //是否用于差分多个Dex的功能,也可以单独在buildTypes中进行配置。
    }

    buildTypes {
        release {
            minifyEnabled false                //是否启用混淆  false不启用   true启用
            zipAlignEnabled false              //整理优化apk文件工具,提高应用运行效率 false不启用   true启用
            shrinkResources false              //是否自动移除未使用的资源  false不启用  true启用
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'    //混淆,所使用的proguard配置文件。
            singingConfig singingConfigs.debug  //打包时
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.2.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}

Android Gradler工程配置都是在android{}中,这是唯一的一个入口,通过它,可以对Android Gradle工程进行自定义配置。

4.自定义Android Gradle工程

4.1 singingConfigs:配置默认的签名信息,对生成的APP签名。

 

  signingConfigs {
        release {
            storeFile file('../cartoonapp.jks')    //签名证书文件
            storePassword "xxxxxx"               //签名证书文件的密码
            keyAlias "xxxxxx"                          //签名证书中密钥别名
            keyPassword "xxxxxx"                 //签名证书中密钥密码
        }
        
// 默认情况下debug模式签名已经被配置好;自动生成的debug证书,一般在$HOME/.android/debug.keystore
        debug {
            storeFile file('../cartoonapp.jks')    //签名证书文件
            storePassword "xxxxxx"               //签名证书文件的密码
            keyAlias "xxxxxx"                          //签名证书中密钥别名
            keyPassword "xxxxxx"                 //签名证书中密钥密码
        }
  }

5.高级自定义Android Gradle(动态生成版本信息)

如果只有一个application module还好,如果我们有多个module怎么办呢?每次改版本号累不累?

解决方案:就是在root里申明全局变量,可以在单独的gradle里(比如新建一个config.gradle)
注意:申明然后使用apply from引用进来,或者直接定义在root的build.gradle中。

 

  apply plugin: 'com.android.application'
  apply from: '../config.gradle'    //引入进来  ../表示上一级

  android {
      ...
  }

5.1 config.gradle文件配置

 

rootProject.ext {
    
    android = [
            compileSdkVersion       : 29,
            buildToolsVersion       : "29.0.2",
            applicationId       : "com.ych.mvpadvance",
            minSdkVersion           : 15,
            targetSdkVersion        : 29,
            versionCode             : 1,
            versionName             : "1.0"
    ]
    
    //版本号
    version = [
            androidSupportSdkVersion: "28.0.0",
            retrofitSdkVersion      : "2.6.0",
            dagger2SdkVersion       : "2.23.2",
            glideSdkVersion         : "4.9.0",
            butterknifeSdkVersion   : "9.0.0",
            rxlifecycleSdkVersion   : "1.0",
            rxlifecycle2SdkVersion  : "2.2.2",
            espressoSdkVersion      : "3.0.1",
            canarySdkVersion        : "1.6.3"
    ]

    dependencies = [
            //support
            "appcompat-v7"             : "com.android.support:appcompat-v7:${version["androidSupportSdkVersion"]}",
            "design"                   : "com.android.support:design:${version["androidSupportSdkVersion"]}",
            "support-v4"               : "com.android.support:support-v4:${version["androidSupportSdkVersion"]}",
            "cardview-v7"              : "com.android.support:cardview-v7:${version["androidSupportSdkVersion"]}",
            "annotations"              : "com.android.support:support-annotations:${version["androidSupportSdkVersion"]}",
            "recyclerview-v7"          : "com.android.support:recyclerview-v7:${version["androidSupportSdkVersion"]}",

            //network
            "retrofit"                 : "com.squareup.retrofit2:retrofit:${version["retrofitSdkVersion"]}",
            "retrofit-converter-gson"  : "com.squareup.retrofit2:converter-gson:${version["retrofitSdkVersion"]}",
            "retrofit-adapter-rxjava"  : "com.squareup.retrofit2:adapter-rxjava:${version["retrofitSdkVersion"]}",
            "retrofit-adapter-rxjava2" : "com.squareup.retrofit2:adapter-rxjava2:${version["retrofitSdkVersion"]}",
            "okhttp3"                  : "com.squareup.okhttp3:okhttp:3.5.0",
            "okhttp4"                  : "com.squareup.okhttp3:okhttp:4.0.0",
            "okhttp-urlconnection"     : "com.squareup.okhttp:okhttp-urlconnection:2.0.0",
            "glide"                    : "com.github.bumptech.glide:glide:${version["glideSdkVersion"]}",
            "glide-compiler"           : "com.github.bumptech.glide:compiler:${version["glideSdkVersion"]}",
            "glide-loader-okhttp3"     : "com.github.bumptech.glide:okhttp3-integration:${version["glideSdkVersion"]}",
            "picasso"                  : "com.squareup.picasso:picasso:2.5.2",

            //view
            "autolayout"               : "com.zhy:autolayout:1.4.5",
            "butterknife"              : "com.jakewharton:butterknife:${version["butterknifeSdkVersion"]}",
            "butterknife-compiler"     : "com.jakewharton:butterknife-compiler:${version["butterknifeSdkVersion"]}",
            "pickerview"               : "com.contrarywind:Android-PickerView:3.2.5",
            "photoview"                : "com.github.chrisbanes.photoview:library:1.2.3",
            "numberprogressbar"        : "com.daimajia.numberprogressbar:library:1.2@aar",
            "nineoldandroids"          : "com.nineoldandroids:library:2.4.0",
            "paginate"                 : "com.github.markomilos:paginate:0.5.1",
            "vlayout"                  : "com.alibaba.android:vlayout:1.1.0@aar",
            "autosize"                 : "me.jessyan:autosize:1.1.2",

            //rx1
            "rxandroid"                : "io.reactivex:rxandroid:1.2.1",
            "rxjava"                   : "io.reactivex:rxjava:1.3.0",
            "rxlifecycle"              : "com.trello:rxlifecycle:${version["rxlifecycleSdkVersion"]}",
            "rxlifecycle-components"   : "com.trello:rxlifecycle-components:${version["rxlifecycleSdkVersion"]}",
            "rxcache"                  : "com.github.VictorAlbertos.RxCache:runtime:1.7.0-1.x",
            "rxcache-jolyglot-gson"    : "com.github.VictorAlbertos.Jolyglot:gson:0.0.4",
            "rxbinding-recyclerview-v7": "com.jakewharton.rxbinding:rxbinding-recyclerview-v7:1.0.1",
            "rxpermissions"            : "com.tbruyelle.rxpermissions:rxpermissions:0.9.4@aar",
            "rxerrorhandler"           : "me.jessyan:rxerrorhandler:1.0.1",

            //rx2
            "rxandroid2"               : "io.reactivex.rxjava2:rxandroid:2.1.1",
            "rxjava2"                  : "io.reactivex.rxjava2:rxjava:2.2.10",
            "rxlifecycle2"             : "com.trello.rxlifecycle2:rxlifecycle:${version["rxlifecycle2SdkVersion"]}",
            "rxlifecycle2-android"     : "com.trello.rxlifecycle2:rxlifecycle-android:${version["rxlifecycle2SdkVersion"]}",
            "rxlifecycle2-components"  : "com.trello.rxlifecycle2:rxlifecycle-components:${version["rxlifecycle2SdkVersion"]}",
            "rxcache2"                 : "com.github.VictorAlbertos.RxCache:runtime:1.8.3-2.x",
            "rxpermissions2"           : "com.github.tbruyelle:rxpermissions:0.10.2",
            "rxerrorhandler2"          : "me.jessyan:rxerrorhandler:2.1.1",

            //tools
            "dagger2"                  : "com.google.dagger:dagger:${version["dagger2SdkVersion"]}",
            "dagger2-android"          : "com.google.dagger:dagger-android:${version["dagger2SdkVersion"]}",
            "dagger2-android-support"  : "com.google.dagger:dagger-android-support:${version["dagger2SdkVersion"]}",
            "dagger2-compiler"         : "com.google.dagger:dagger-compiler:${version["dagger2SdkVersion"]}",
            "dagger2-android-processor": "com.google.dagger:dagger-android-processor:${version["dagger2SdkVersion"]}",
            "androideventbus"          : "org.simple:androideventbus:1.0.5.1",
            "eventbus"                 : "org.greenrobot:eventbus:3.1.1",
            "otto"                     : "com.squareup:otto:1.3.8",
            "gson"                     : "com.google.code.gson:gson:2.8.5",
            "multidex"                 : "com.android.support:multidex:1.0.3",
            "javax.annotation"         : "javax.annotation:jsr250-api:1.0",
            "arouter"                  : "com.alibaba:arouter-api:1.3.1",
            "arouter-compiler"         : "com.alibaba:arouter-compiler:1.1.4",
            "progressmanager"          : "me.jessyan:progressmanager:1.5.0",
            "retrofit-url-manager"     : "me.jessyan:retrofit-url-manager:1.4.0",
            "lifecyclemodel"           : "me.jessyan:lifecyclemodel:1.0.1",

            //test
            "junit"                    : "junit:junit:4.12",
            "androidJUnitRunner"       : "android.support.test.runner.AndroidJUnitRunner",
            "runner"                   : "com.android.support.test:runner:1.0.1",
            "espresso-core"            : "com.android.support.test.espresso:espresso-core:${version["espressoSdkVersion"]}",
            "espresso-contrib"         : "com.android.support.test.espresso:espresso-contrib:${version["espressoSdkVersion"]}",
            "espresso-intents"         : "com.android.support.test.espresso:espresso-intents:${version["espressoSdkVersion"]}",
            "mockito-core"             : "org.mockito:mockito-core:1.+",
            "timber"                   : "com.jakewharton.timber:timber:4.7.1",
            "logger"                   : "com.orhanobut:logger:2.2.0",
            "canary-debug"             : "com.squareup.leakcanary:leakcanary-android:${version["canarySdkVersion"]}",
            "canary-release"           : "com.squareup.leakcanary:leakcanary-android-no-op:${version["canarySdkVersion"]}",
            "umeng-analytics"          : "com.umeng.analytics:analytics:6.0.1"
    ]
}

5.2 引用config.gradle文件中配置信息

 

apply plugin: 'com.android.application'
apply from: '../config.gradle'


android {
    compileSdkVersion rootProject.ext.android["compileSdkVersion"]
    buildToolsVersion rootProject.ext.android["buildToolsVersion"]
    defaultConfig {
        applicationId rootProject.ext.android["applicationId"]
        minSdkVersion rootProject.ext.android["minSdkVersion"]
        targetSdkVersion rootProject.ext.android["targetSdkVersion"]
        versionCode rootProject.ext.android["versionCode"]
        versionName rootProject.ext.android["versionName"]
        testInstrumentationRunner rootProject.ext.dependencies["androidJUnitRunner"]

          //设置支持的SO库架构
          ndk {
            abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a' ,'x86' , 'x86_64'
          }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }

        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.2.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

    //引用
    implementation rootProject.ext.dependencies.okhttp3
}

6.动态配置AndroidManifest文件

Android Gradle中提供了非常便捷的方法让我们来替换AndroidManifest文件内容,他就是manifestPlaceholder,Manifest占位符,也可以在defaultConfig中配置。

 

  productFlavors {
        _xiaomi {
           ...
           manifestPlaceholders = [
                JPUSH_PKGNAME: applicationId,
                JPUSH_APPKEY : rootProject.ext.apienv == 0 ? rootProject.ext.jpushReleaseKey : rootProject.ext.apienv == 4 ? rootProject.ext.jpushReleaseKey : rootProject.ext.jpushTestKey, //JPush上注册的包名对应的appkey.  正式
                JPUSH_CHANNEL: "developer-default", //暂时填写默认值即可.
                JPUSH_APPNAME: rootProject.ext.apienv == 0 ? "安路通正式2.1" : rootProject.ext.apienv == 4 ? "天天快车" : "安路通测试2.1",
                BAIDU_APPKEY : rootProject.ext.apienv == 0 ? rootProject.ext.baiduReleaseKey : rootProject.ext.apienv == 4 ? rootProject.ext.baiduReleaseKey : rootProject.ext.baiduTestKey,
                JPUSH_ICON : rootProject.ext.apienv == 0 ? "@mipmap/ic_launcher": rootProject.ext.apienv == 1 ? "@mipmap/ic_launcher": "@drawable/tianhong",
         ]
     }
    }

AndroidManifest中使用:

 

<application
    android:name=".app.SampleApplication"
    android:allowBackup="true"
    android:icon="${JPUSH_ICON}"
    android:label="${JPUSH_APPNAME}"
    android:largeHeap="true"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    
    <!-- Required. For publish channel feature -->
    <!-- JPUSH_CHANNEL 是为了方便开发者统计APK分发渠道。 -->
    <!-- 例如: -->
    <!-- 发到 Google Play 的APK可以设置为 google-play; -->
    <!-- 发到其他市场的 APK 可以设置为 xxx-market。 -->
    <!-- 目前这个渠道统计功能的报表还未开放。 -->
    <meta-data
        android:name="JPUSH_CHANNEL"
        android:value="${JPUSH_CHANNEL}" />
    <!-- Required. AppKey copied from Portal -->

    <meta-data
        android:name="JPUSH_APPKEY"
        android:value="${JPUSH_APPKEY}" />
</application>

7.自定义你的BuildConfig

 

  //默认的BuildConfig
  public final class BuildConfig {
      public static final boolean DEBUG = Boolean.parseBoolean("true");
      public static final String APPLICATION_ID = "com.ych.androidgradle";
      public static final String BUILD_TYPE = "debug";
      public static final String FLAVOR = "";
      public static final int VERSION_CODE = 1;
      public static final String VERSION_NAME = "1.0";
  }

假设我们有 Baidu 和 Google 两个渠道,发布的时候也会有两个渠道。当我们安装Baidu渠道包的时候打开的 是Baidu首页,当安装Google渠道包的时候,打开的是Google的首页。我们只需要添加一个字段(WEB_URL),字段名自己定义。

 

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "com.ych.androidgradle"
        minSdkVersion 15
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    productFlavors {
        google {
            buildConfigField "String", "WEB_URL", ' "http://www.google.com " '
            buildConfigField "int", "API_ENV", ' "1 " '
            buildConfigField "boole", "API_ENV", ' "1 " '
        }
        baidu {
            buildConfigField "String", "WEB_URL",  ' "http://www.baidu.com " '
            buildConfigField "int", "API_ENV", ' "2" '
        }

    }
}

8.签名管理(非常重要)

签名是一个很敏感的东西,只要有了签名文件和对应的密码信息,就能轻易反编译修改源码然后再签名进行发布,因此如何保存这些敏感信息是很重要的。

在我的个人实践中,主要做了这么几点:

8.1 在local.properties文件下定义keystore信息文件路径:

 

sdk.dir=D\:\\Develop\\SDK
keystore.props.file=../keystore.properties

8.2 keystore.properties保存keystore信息:
store=../buildsystem/alt.keystore
alias=xxx
pass=xxx
storePass=xxx

8.3 buildsystem下保存了:
文件加下放入我们的签名文件 xxx.keystore/ xxx.jks
debug.keystore
release.keystore

**8.4 application module的signingConfigs:

 

  signingConfigs {

        def Properties localProps = new Properties()
        localProps.load(new FileInputStream(file('../local.properties')))
        def Properties keyProps = new Properties()

        // 如果读取不到'keystore.props.file'属性,就使用debug keystore
        if (localProps['keystore.props.file']) {
            keyProps.load(new FileInputStream(file(localProps['keystore.props.file'])))
        } else {
            keyProps["store"] = '../buildsystem/debug.keystore'
            keyProps["alias"] = 'android'
            keyProps["storePass"] = 'androiddebugkey'
            keyProps["pass"] = 'android'
        }

        debug {
            storeFile file(keyProps["store"])
            keyAlias keyProps["alias"]
            storePassword keyProps["storePass"]
            keyPassword keyProps["pass"]
        }

        release {
            // release版本使用assert确保存在该属性否则报错,避免错误打包
            assert localProps['keystore.props.file'];
            storeFile file(keyProps["store"])
            keyAlias keyProps["alias"]
            storePassword keyProps["storePass"]
            keyPassword keyProps["pass"]
        }
    }

9.总结

  本篇主要讲了开发阶段gradle的各种实践,希望可以帮到大家。



作者:如愿以偿丶
链接:https://www.jianshu.com/p/6c1fcf251623
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

上一篇:时间序列研(part11)--EG两步法


下一篇:system、 exec函数族、fork函数用法说明