Android Build.Gradle解释了ð
#java #groovy #android #buildgradle

你好朋友,

gradle 是一个自动化Android应用程序开发阶段的构建系统。

gradle 系统中为Java平台编写代码时,我们使用 groovy 编程语言,这是一种非常简单的语言。 Groovy 具有比Java更简单的语言。您可以看一下我解释这些差异的GitHub回购。

这个凹槽是什么?

Groovy是一种强大的,按需的动态语言,具有静态键入和Java平台的静态汇编,旨在通过简洁,简单且易于学习的语法提高开发人员的生产率。

借助我们在Groovy中学到的这些信息,让我们仔细研究一下如何构建我们的构建。

build.gradle 允许我们在我们通过Android Studio开发的应用程序的开发过程中进行更改,以自定义我们收到的构建(以最简单的示例,为Pro生成不同的.APK和免费版本),具有多种环境(调试,ENT,测试,beta,prod ..),并允许我们与团队舒适地合作。

构建gradle(app)工具

它的一般结构如下:

`插件{
id'com.android.application'

}
导入java.util.regex.pattern
android {

compilesdk 32
DefaultConfig {
“ com.hakki.uygulamaadi”
Minsdk 21
Targetsdk 32
resonfigs“ in”,“ tr”
...
}
}
buildTypes {}
compileoptions {}
依赖项{
实现'androidx.AppCompat:appCompat:1.4.1'
...
}`


现在让我们看看我们在build.gradle设置中拥有什么。

signingConfigs :发布应用程序时会存储所需的密钥。释放已添加到版本中。

buildTypes :我们添加和编辑应用程序开发过程的部分。

buildconfigfield :允许在构建时发送恒定值。
收到构建后,创建了buildConfig.java类。要从类访问此常数,它可以作为buildConfig.info访问。注意:由于您尚未收到构建,它将看起来像是红色的,好像存在错误。

Productflavors :要在一个屋顶下收集多个项目时使用。它默认为“主要”,不包含在build.gradle中。提前定义了黄色辅助。

清单持有人:更改应用程序图标。
借方:允许根据应用程序更改资源值。
例如:在几个地方提到了应用程序名称(它可以是常见的飞溅或活动),我们可以通过在此处分配值来添加动力。

variantFilter :我们添加的构建类型越多,我们为每个应用程序添加的开发环境就越可选。例如。我们添加了诸如测试,调试,β,ENT,释放到我们的TODO应用程序之类的过程。对于每个应用程序,在某些情况下,流程无法正常工作。我们使用VariantFilter将其删除,因此它不会不必要地填充开发环境列表。

Applications and Development Processes

如果我需要简要解释其他关键点:
在项目中收集所有应用程序提供了方便变化和管理方面的便利。但是,这也带来了一些需要添加的较小改进。
这些;

  • 当我们构建时,请防止项目中的所有类都加载到每个应用程序的.APK中,
  • 在每个.apk中定义一个通用文件夹并上传通用类和资源文件,
  • 仅执行版本(实时)特定操作,

您可以查看下面的示例构建。

一个Android项目统治它们(应用程序)。

plugins {
    id 'com.android.application'
}

import java.util.regex.Matcher
import java.util.regex.Pattern

/*
sonarqube {
    properties {
        property "sonar.projectName", "LargeProjectExample"
        property "sonar.projectKey", "LargeProjectExample"
        property "sonar.host.url", "http://localhost:9000"
        property "sonar.language", "java"
        property "sonar.login", "admin"
        property "sonar.password", "******"
    }
}
*/

android {
    useLibrary 'org.apache.http.legacy'
    compileSdk 32

    defaultConfig {
        applicationId "com.largeproject.example"
        minSdk 21
        targetSdk 32
        versionCode 1
        versionName "1.0"
        resConfigs "en", "tr"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"    
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    signingConfigs {
        release {
            keyAlias 'key0'
            keyPassword '******'
            storeFile file('27tkey.jks')
            storePassword '******'
        }
    }

    buildTypes {
        // Development Environments
        release {
            signingConfig signingConfigs.release
            // zipAlignEnabled true      //
            //shrinkResources true   //res
            minifyEnabled true    //java code
            // multiDexEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            debuggable false
        }
        debug {
            //applicationIdSuffix ".debug"
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            debuggable true
        }
        dev {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            debuggable true
            /* DEV ORTAMI */
            buildConfigField "String", "INFO", '"someinfodev"'
        }
        plat {
            /* PLATFORM ORTAMI */
            buildConfigField "String", "INFO", '"someinfoplat"'

        }
        prod {
            /* PROD ORTAMI */
            buildConfigField "String", "INFO", '"someinfoprod"'

        }
    }

    flavorDimensions "APP"
    productFlavors {

        largeProject {
            dimension "APP"

            // CHANGE
            String appName = "Large Project"
            String appVersionName = "4.1.55"
            Integer appVersionCode = 255
            String appIdSuffix = ".largeproject"
            // CHANGE

            manifestPlaceholders = [appName: appName, appIcon: "@drawable/ic_second"]
            resValue("string", "app_name", appName)
            versionName appVersionName
            versionCode appVersionCode
            applicationIdSuffix appIdSuffix
        }

        largeProject2 {
            dimension "APP"

            String appName = "Another Large Project"
            String appVersionName = "4.1.55"
            Integer appVersionCode = 255
            String appIdSuffix = ".largeProject2"

            manifestPlaceholders = [appName: appName, appIcon: "@drawable/ic_second"]
            resValue("string", "app_name", appName)
            versionName appVersionName
            versionCode appVersionCode
            applicationIdSuffix appIdSuffix

            buildConfigField 'String', 'merhabaa', '"selam"'
        }

    }

    // Ignore Operations. Note: "==" operator is better than ".contains".
    variantFilter { variant ->
        String app = variant.flavors*.name.get(0).toLowerCase()
        String buildType = variant.buildType.name.toLowerCase()
        // println("app : " + app + " buildType : " + buildType)

        if (app == "largeproject" && buildType == "ent") {
            variant.setIgnore(true)
        }
    }

    // Changing the Default Media Storage Location Groovy
    List<String> resBuildTypes = new ArrayList<String>()
    List<String> resBuildType  = new ArrayList<String>()
    resBuildTypes.add("src/main/res/common")

    productFlavors.all { flavor  ->
        String folder = "src/main/res/customers/" + flavor.name
        resBuildTypes.add(folder)
        resBuildType.add(flavor.name)
    }

    //println resBuildTypes // output: [src/main/res/common, src/main/res/customers/largeProject, src/main/res/customers/largeProject2]
    //println resBuildType  //output: [largeProject, largeProject2]

    sourceSets {
        main.res.srcDirs  = resBuildTypes
        // also you can change manifest file for every customer
        //main.manifest.srcFile = "src/main/res/"

        for (String var : resBuildType) {
            "$var" {
                setRoot "src/main/res/" + var
            }
        }
    }

    buildFeatures {
        buildFeatures.dataBinding = true
        buildFeatures.viewBinding = true
    }
}


// Build task that allows us to get the received project request information.
def projectName
def projectBuildType
task getCurrentFlavor() {
    Gradle gradle = getGradle()
    String tskReqStr = gradle.getStartParameter().getTaskRequests().toString()

    Pattern pattern

    // take buildTypes to String
    String buildTypes = ""
    android.buildTypes.all {
        type ->
            //println(type.name) Capitalize
            String output = type.name.substring(0, 1).toUpperCase() + type.name.substring(1)
            buildTypes += output + "|"
    }
    buildTypes = buildTypes.substring(0, buildTypes.length() - 1) //delete last | character
    //println buildTypes

    if (tskReqStr.contains("assemble"))
        pattern = Pattern.compile("assemble(\\w+)($buildTypes)") // Addition Required for Every BuildType Created. Dev|Ent|Tst,
    else
        pattern = Pattern.compile("generate(\\w+)($buildTypes)") // $buildTypes fulfills this request by automating.

    Matcher matcher = pattern.matcher(tskReqStr)

    if (matcher.find()) {
        //projectVariant = matcher.group().toLowerCase()
        projectName = matcher.group(1).toLowerCase() // Changing to 2 will return build type, 1 provides product flavor
        projectBuildType = matcher.group(2).toLowerCase() // Changing to 2 will return build type, 1 provides product flavor

    } else {
        println "NO MATCH FOUND"
    }
}

task buildVariantTasks(type: Copy) {
    dependsOn getCurrentFlavor
    println "flavor name is " + projectName
    println "build type is "  + projectBuildType

    if(projectName!=null && projectBuildType!=null) {

        // Separating Classes and Resourses
        // To identify location of Common (Main) Classes, simply change the part that says "common".

        String appID = android.defaultConfig.applicationId
        String appIdSlashes = "src/main/java/" + appID.replaceAll("\\.", "/") + "/"
        android.sourceSets.main {
            java.srcDirs = [appIdSlashes + "common", appIdSlashes + projectName]
            res.srcDirs  = ['src/main/res/common', 'src/main/res/'+ projectName]
            manifest.srcFile "src/main/res/customers/" + projectName + "/AndroidManifest.xml"
        }

        android.applicationVariants.all { variant ->

            // Output APK Name & appVer - Specify a Common BuildConfig to Add to Each Product
            String buildType = variant.buildType.name
            String flavorName = variant.getFlavorName()
            String buildTime = new Date().format("yyMMddHHmm", TimeZone.getTimeZone("Asia/Istanbul"))

            variant.outputs.all {
                buildConfigField 'String', 'INFO', "\"${flavorName}.${buildType}\""
                buildConfigField 'String', 'appVer', "\"${versionName}_${buildTime}\""
                outputFileName = getFileName(flavorName, versionName, buildTime, buildType)
            }

            // Action By Product Specific Defined BuildConfigField, If Product Is Defined ...
            /*variant.productFlavors.each { flavor ->
                if (variant.getFlavorName() == projectName) {

                    flavor.buildConfigFields.each { key, value ->
                        if(key == "INFO") {
                            println value.type
                            println value.name
                            println value.value
                        }
                    }
                }
            }*/

            // Release Actions for Release -> Allatori is here.
            if(projectBuildType.contains("release") && flavorName == projectName) {

                // You can add here compression tools...


            }

        }


    }
}
preBuild.dependsOn buildVariantTasks


static String getFileName(flavorName, versionName, buildTime, buildType) {
    return flavorName + "_" + versionName + "_" + buildTime + "_" + buildType + ".apk"
}

// Example of defining version for dependencies
ext {
    appCombat = '1.4.1'
    material = '1.5.0'
    constrain = '2.1.3'
    junit = '4.13.2'
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')

    implementation 'androidx.appcompat:appcompat:' + appCombat
    implementation 'com.google.android.material:material:'+ material
    implementation 'androidx.constraintlayout:constraintlayout:'+constrain
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    testImplementation 'junit:junit:'+junit
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

在我的下一篇文章中,我们将研究与Kotlin在开发过程中可以做出的改进。

来源:
Gradle
What it this Groovy?
Github Build.Gradle