从0开始搭建一个APP:(1)项目的配置

最近frameWork的blog都没有写了,原因就在于要重新搭一个APP的架子出来,需要无脑的搬砖。

还是说选型吧,viewModel是首选方案,语言上直接就是全kotlin,组件化技术用DD的DRouter,虽然那个是Java 写的,但是不自己写KSP的情况下,感觉他是最好的方案了,当然功能也蛮多的,啥都能找到,kapt还是基于apt封装,感觉上还不如直接APT,因为compose和xml 这种方式可以混合开发。所以把能整的都整一下。

gradle相关的

我们先直接基于AS创建一个app,先不选择compose,就是原始的那种xml 风格即可,gradle的DSL语言还是选择kotlin DSL,因为本地是7+,所以我们手动把gradle 版本修改到8以下,通过Android build tools 版本也和gradle 版本有一定约束关系(参考),主要是原因还是看国内的组件化插件或者编译时插件到底支持到了什么版本。 gradle版本:

ini 复制代码
distributionUrl=https://services.gradle.org/distributions/gradle-7.5-all.zip

Android与kotlin plugin 版本

bash 复制代码
plugins {
    id("com.android.application") version "7.4.2" apply false
    id("com.android.library") version "7.4.2" apply false
    id("org.jetbrains.kotlin.android") version "1.8.10" apply false
}

可以看到,这个和之前的classpath 还是不一样,但是还是可以使用classpath,这个后面我们使用DRouter的时候再说。这个可以简单的理解成 Android build tools 版本迭代导致的,如果说改到4.2.2,那么就会发现很多东西报错,所以还是不往太低的改。

设置maven的地址和plugin 的地址

这个玩意被修改到了setting.gradle 里面去了

scss 复制代码
pluginManagement {
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
        maven { setUrl("https://s01.oss.sonatype.org/content/repositories/releases/") }
    }
}


dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        maven { setUrl("https://s01.oss.sonatype.org/content/repositories/releases/") }
        maven { setUrl("https://jitpack.io") }
        maven { setUrl("https://maven.aliyun.com/repository/public/") }
        mavenCentral()
    }
}

这个就说gradle 迭代的问题了。

配置Androidx 与 androidx 代码都自动转换

在gradle.propertis 文件里面加入:

ini 复制代码
android.useAndroidX=true
android.enableJetifier=true

第二行:启用 Jetifier 工具,该工具可以自动将你的项目中使用的第三方库迁移到 AndroidX。

buildSrc 本地化gradle plugin

这个熟悉编译时技术的同学可能有经验,这个玩意里面的plugin 可以不通过classpath 导入就可以使用,而且是默认加载。所以我们先在根目录创建一个这样的文件夹,至于为什么是这个名字,gradle人家就定义成这样了,只有写成这样才会默认加载,不是这样要手动添加clsspath。

无论是plugins 还是classpath 的目标都是为gradle 工程服务的,所以我们可以在gradle中直接使用。我们先在buildSrc 目录下创建一个:build.gradle.kts 文件。然后导入相应的配置:

ini 复制代码
plugins {
    `java-library`
    `kotlin-dsl`
}

repositories {
    mavenCentral()
    google()
}

java {
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11
}


dependencies {
}

因为这个buildSrc 的src 目录中的的所有class 都可以在整个gradle 工程中直接访问,那么常用的方式就有:

  • 定义 maven
  • 定义app 的配置信息中的Flavor。
  • 定义plugin
  • 定义一些自定义的task,比如说打包的时候,拉预置数据,打包完成后自动上传到某些服务器上面去,或者说切换工作空间什么的。

常规配置

因为我们要考虑到是组件化开发,一些UImodule的配置就几乎是固定的,而gradle 又允许导入外部的gradle 文件,所以我们可以单独写一个gradle文件,用于配置一些UI层的配置,比如说,我们创建一个叫common.gradle的文件在项目的根目录,

至于为啥上面用kotlin 的DSL,但是这个文件要用groovy的DSL,因为我还没有解决通过apply from 导入到gradle文件 Android 闭包找不到的问题,但是groovy的DSL没有这个问题。

arduino 复制代码
// 这个玩意写成kotlin dsl 会报Android 闭包找不到。先用groovy 写。等找到原因了再全部切换到kotlin  dsl
// 这个玩意里面不能导入plugin。

android{
    compileSdk AndroidConfig.compileSdk
    defaultConfig{
        minSdk AndroidConfig.minSdk
        targetSdk AndroidConfig.targetSdk
        versionCode 1
        versionName "1.0"
    }

    kotlinOptions {
        jvmTarget = BuildConfig.kotlinOptionsJvmTarget
    }
    compileOptions {
        sourceCompatibility BuildConfig.sourceCompatibility
        targetCompatibility BuildConfig.targetCompatibility
    }

    buildFeatures {
        viewBinding true
        aidl true
        buildConfig true
        // 开启compose
        compose true
    }

    composeOptions {
        kotlinCompilerExtensionVersion = "1.4.3"
    }

    lint {
        abortOnError false
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        debug {
            signingConfig signingConfigs.debug
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}
dependencies {
    implementation Common.ktx
    implementation Common.appcompat
    implementation Common.material
    implementation Common.constraintlayout
    implementation Common.kotlinx_coroutines_android
    implementation Common.lifecycle_common
    implementation Common.lifecycle_viewmodel_compose
    implementation Common.lifecycle_livedata_core_ktx
    implementation Common.activity_ktx
    implementation Common.fragment_ktx
    // 路由
    implementation Router.router
    implementation Router.page
    implementation Router.process
    
}

通过上面的代码,可以看到,我们使用了在buildSrc 中定义的常量,以Common 为例:

ini 复制代码
object Common{
    const val ktx="androidx.core:core-ktx:1.8.0"
    const val appcompat="androidx.appcompat:appcompat:1.6.1"
    const val material="com.google.android.material:material:1.5.0"
    const val constraintlayout="androidx.constraintlayout:constraintlayout:2.1.4"
    const val kotlinx_coroutines_android="org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"
    const val lifecycle_common="androidx.lifecycle:lifecycle-common:2.6.1"
    const val lifecycle_viewmodel_compose="androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1"
    const val lifecycle_livedata_core_ktx="androidx.lifecycle:lifecycle-livedata-core-ktx:2.6.1"
    const val activity_ktx="androidx.activity:activity-ktx:1.7.2"
    const val fragment_ktx="androidx.fragment:fragment-ktx:1.6.1"
}

同时还可以发下一个问题,这个gradle 文件中没有任何的plugin 或者apply 的代码,可以简单理解成kotlin 的inline 函数的效果,通过下列的代码导入common.gradle

ini 复制代码
apply(from = "../common.gradle")

Android lib module的配置

因为我们写了一个common.gradle,所以我们lib 的代码就很简单了:

python 复制代码
plugins {
    id("com.android.library")
    id("org.jetbrains.kotlin.android")
}
apply(from = "../common.gradle")
android {
    namespace = "com.luoye.baseui"
}

dependencies {
    api(project(mapOf("path" to ":common")))
}

module 中的差异部分也可以自己配置。

Drouter 的配置

为什么要先写这个,因为Drouter 的plugin 只需要写到application里面即可DRouter gitHub地址,可以在demo 代码里面看到,他依旧是使用classpath 导入plugin的,那么能不能通过plugins{id } 这种方式获得呢?

反正我是没有弄出来,没有搞明白plugins{id} 怎么拼drouter-plugin 这一部分。

既然plugins没有整通畅,那么还是使用classpath 即可:

scss 复制代码
buildscript{
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
        maven { setUrl("https://s01.oss.sonatype.org/content/repositories/releases/") }
    }
    dependencies{
        classpath("io.github.didi:drouter-plugin:1.3.4")
    }
}

可以看到,我们classpath 没有写Android build tools,因为我们上面plugins 里面已经申请了。

app的配置

整了这么多,终于写到了app 这边了。我们app依旧导入common.gradle 文件,至于common.gradle 是否臃肿,臃肿了就拆分成多个即可,我们app 主要是对打包进行限制,比如说NDK,比如说排除某些maven版本,比如说flavor。

kotlin 复制代码
plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
    id("com.didi.drouter")
}


apply(from = "../common.gradle")

drouter {
    debug = true
}

android {
    namespace = "com.example.luoye"

    applicationVariants.all {
        outputs.filterIsInstance<com.android.build.gradle.internal.api.ApkVariantOutputImpl>().forEach {
            it.outputFileName = "${applicationId}_v${versionName}_${versionCode}_${buildType.name}.apk"
        }
    }
    // 配置 productFlavors
    flavorDimensions += AndroidConfig.DIMENSION_ENV

    productFlavors {
        arrayOf(AndroidConfig.FLAVOR_MOBILE_PRD, AndroidConfig.FLAVOR_MOBILE_DEV).forEach {
            create(it) {
                dimension = AndroidConfig.DIMENSION_ENV
               val config= AndroidConfig.getConfigInfo(it)
                applicationId = config.applicationId
                versionName = project.properties["AppVersionName"].toString().trim().ifEmpty { config.versionName }

                versionCode = project.properties["AppVersionCode"].toString().trim().toIntOrNull() ?: config.versionCode
                // 调试模式通过打包进行配置。
                val appDebug=project.properties["app_debug"].toString().toBoolean()
                buildConfigField("Boolean","app_debug","$appDebug")

            }
        }
    }

    packagingOptions {
        jniLibs {
            keepDebugSymbols += "*/armeabi-v7a/*.so"
        }
        // compose 配置
        resources {
            excludes+="/META-INF/{AL2.0,LGPL2.1}"
        }
    }
}

dependencies {
   
    // 内存泄漏检测
    debugImplementation(Debug.leakcanary)
    implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar", "*.aar"))))
   
}

可以看到下面代码用于配置apk 文件的文件名。

kotlin 复制代码
    applicationVariants.all {
        outputs.filterIsInstance<com.android.build.gradle.internal.api.ApkVariantOutputImpl>().forEach {
            it.outputFileName = "${applicationId}_v${versionName}_${versionCode}_${buildType.name}.apk"
        }
    }

而且我们还通过 project.properties["AppVersionName"] 获取了gradle.properties 中的AppVersionName,当我们工程需要使用Jenkins打包的时候,往往就是在这个文件里面配置东西,然后将数据通过gradle的执行设置到APP的配置文件里面,比如说string,清单文件,buildConfig 文件等等。

结束

其实这篇蛮简单的,主要是思路的和一些常规的经验,用于提高后续的编码速率,也没有啥相关的知识点。

相关推荐
诸神黄昏EX1 小时前
Android 分区相关介绍
android
大白要努力!2 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
Estar.Lee2 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
Winston Wood2 小时前
Perfetto学习大全
android·性能优化·perfetto
Dnelic-5 小时前
【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录
android·junit·单元测试·android studio·自学笔记
Eastsea.Chen7 小时前
MTK Android12 user版本MtkLogger
android·framework
长亭外的少年15 小时前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin
建群新人小猿17 小时前
会员等级经验问题
android·开发语言·前端·javascript·php
1024小神18 小时前
tauri2.0版本开发苹果ios和安卓android应用,环境搭建和最后编译为apk
android·ios·tauri
兰琛19 小时前
20241121 android中树结构列表(使用recyclerView实现)
android·gitee