最近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版别:

distributionUrl=https://services.gradle.org/distributions/gradle-7.5-all.zip

Android与kotlin plugin 版别

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 里边去了

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 文件里边参加:

android.useAndroidX=true
android.enableJetifier=true

第二行:启用 Jetifier 东西,该东西能够自动将你的项目中运用的第三方库迁移到 AndroidX。

buildSrc 本地化gradle plugin

这个熟悉编译时技能的同学可能有经历,这个玩意里边的plugin 能够不经过classpath 导入就能够运用,而且是默许加载。所以咱们先在根目录创立一个这样的文件夹,至于为什么是这个名字,gradle人家就界说成这样了,只要写成这样才会默许加载,不是这样要手动添加clsspath。

无论是plugins 仍是classpath 的目标都是为gradle 工程服务的,所以咱们能够在gradle中直接运用。咱们先在buildSrc 目录下创立一个:build.gradle.kts 文件。然后导入相应的装备:

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没有这个问题。

// 这个玩意写成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 为例:

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

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

Android lib module的装备

由于咱们写了一个common.gradle,所以咱们lib 的代码就很简略了:

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 即可:

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。

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 文件的文件名。

    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 文件等等。

完毕

其实这篇蛮简略的,主要是思路的和一些惯例的经历,用于进步后续的编码速率,也没有啥相关的知识点。