你好朋友,
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将其删除,因此它不会不必要地填充开发环境列表。
如果我需要简要解释其他关键点:
在项目中收集所有应用程序提供了方便变化和管理方面的便利。但是,这也带来了一些需要添加的较小改进。
这些;
- 当我们构建时,请防止项目中的所有类都加载到每个应用程序的.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在开发过程中可以做出的改进。