搭建Android客户端APP架构——《组件化技术》
背景
本人从事开发工作也有多年,目前坐标湖南长沙,以前在各种平台也发过一些文章但是都没有坚持下来;
我初步规划是写一个完整的项目系列文章期望能坚持下来。
为什么会想到要写呢?
其一、眨眼就到了而立之年,觉得自己记忆力也是下降久做过的东西总是记不起,果然是好记性不如烂笔头。
其二、这么多年白嫖了网上很多的文章,视频,一直觉得应该分享一些东西但总是沉不下心去做。
其三、可能写的不好至少也留下一些东西,也是希望能帮助到一些朋友。
说明
其实到写完这个搭建Demo我都还没想好究竟要写一个怎么样的一个完整的APP项目。所以很多架构工作只能根据自己想玩的功能进行慢慢填了。原则上这个项目当然是尽量希望是把所有的功能都重新写重新封装一巩固学习记录一番,如果不重新封装也希望能把第三方是如何做的弄清楚再集成进入。
搭建Android客户端APP目录框架
我们一开始做一个项目可能大部分,是直接创建一个app模块然后把所有项目功能写在一个项目模块下。当然这在单人或者较少人协同工作的时候,项目并不大的时候是完全没有问题的。
那为什么要写如何搭建基础APP目录框架呢?
什么是组件化?
我的理解组件化仅仅是一种思想,就跟设计模式一样,他们的存在都是因为人员的复杂纬度,和业务的复杂性扩展后的衍生,他们存在就生为了更好的协同工作,更好的扩展新需求!
我理解中的组件化就是将业务间解耦后独立出来可以更方便开发运行而不是需要整个业务编译的一种模块开发思想!
我们为什么要组件化,插件化
核心思想
让我来解释一下我理解中的插件化开发核心思想,组件化开发核心思想吧。
插件化开发核心思想:一些功能并不打包到主APP里面发布出去,当用户需要的时候通过加载增量的方式获取并加载。
组件化开发核心思想:是将一个庞大的系统,分解成一个个小的组件,每个部分可以单独开发,单独拆解成一个APP运行。
两者之间壁垒
我认为是没什么思想屏障的。我们完全可以组件化开发后完成插件化思想效果。每个组件就是一个增量加载的部分(是不是有种理应如此的感觉)。
我们为什么要采用组件化思想开发
试想一下如果我们用传统方式开发,我们要做节日活动如:情人节,国庆活动,双十一活动,每个活动都不一样,而且只有在节日那几天我们才需要。我们是需要怎么样做呢?是不是所有的开发好然后发布新版本,节日过去了要么只屏蔽掉入口把内容集合到一个APP以后发布的版本越来越大,要么去掉所有相关内容再发布新版本。
如果我们采用组件化思想开发哪怕我们不插件化,我们也可以通过不引用组件模块的方式来上下活动模块达到发布的主APP大小不会特别臃肿。
从协同开发编译的角度下,传统开发中有可能我们的APP特别庞大,模块众多,完整编译运行一次可能会要十几二十分钟,而我们每个开发者往往负责的又仅仅是独立的某个部分的开发工作。这时候如果每个开发者所负责的部分都能独立出来编译运行,那么不仅协同的发生的合并错误,以及开发效率也将提高很多。
创建项目
我这里使用的是Android studio 开发。搭建开发环境这里就做赘述。
首先创建一个项目。
我虽然没想好要具体要做什么项目,但我知道一个APP肯定少不了要一个登录,网络,我自己想写一个换肤功能,于是,建立了如下的模块。
当然根据组件化思想,网络主题换肤只是属于功能性的库。目前只有登录适用于一个APP的组件。那么这就完了?
当然没有…
统一所有的引用库和BUILD SDK版本
在多模块开发中有时候会出现依赖版本错误,为了防止出现引用库不同以及多版本依赖问题,新建一个了config.gradle文件定义所有的第三方库,compileSdkVersion targetSdkVersion buildToolsVersion。
allprojects {
repositories {
maven {
url 'https://maven.aliyun.com/repository/google'
}
maven {
url 'https://maven.aliyun.com/repository/public'
}
google()
jcenter()
}
ext {
// compileSdkVersion 30
// buildToolsVersion "30.0.2"
compileSdkVersion = 29
targetSdkVersion = 29
buildToolsVersion = '29.0.3'
minSdkVersion = 19
appcompatVersion = '1.1.0'
constraintlayoutVersion = '1.1.3'
recyclerviewVersion = '1.1.0'
utilcodexVersion = '1.28.0'
junitVersion = '4.13'
espressoVersion = '3.2.0'
xUtilsVersion = '3.8.8'
leakcanaryVersion = '1.6.3'
multidexVersion = '1.0.2'
materialVersion = '1.0.0'
annotationVersion = '1.1.0'
lifecycleVersion = '2.0.0'
BreathViewVersion = '1.0'
licenseId = [
betterLearnBDFCLicenseId : "lzx-smartslearn-face-android",
betterLearnBDFCLicenseName: "idl-license.face-android",
musicrelaxBDFCLicenseId : "lzx-musicrelax-face-android",
musicrelaxBDFCLicenseName : "idl-license.face-android"
]
applicationVersion = [
versionName: "起航",
versionCode: 1,
]
serverUrl = [
RELEASE_SERVER: 'http://192.168.1.100:8080',
DEBUG_SERVER : 'http://192.168.1.100:8080'
]
buildAttribute = [
compileSdkVersion: compileSdkVersion,
targetSdkVersion : targetSdkVersion,
buildToolsVersion: buildToolsVersion,
minSdkVersion : minSdkVersion
]
androidDependencies = [
multidex : "com.android.support:multidex:${multidexVersion}",
constraintlayout: "androidx.constraintlayout:constraintlayout:${constraintlayoutVersion}",
appcompat : "androidx.appcompat:appcompat:${appcompatVersion}",
recyclerview : "androidx.recyclerview:recyclerview:${recyclerviewVersion}",
material : "com.google.android.material:material:${materialVersion}",
annotation : "androidx.annotation:annotation:${annotationVersion}",
lifecycle : "androidx.lifecycle:lifecycle-extensions:${lifecycleVersion}",
]
uiDependencies = [
BreathView: "com.github.arpsyalin:BreathView:${BreathViewVersion}",
]
toolDependencies = [
utilcodex: "com.blankj:utilcodex:${utilcodexVersion}",
]
errorDependencies = [
leakcanary: "com.squareup.leakcanary:leakcanary-android-no-op:${leakcanaryVersion}",
]
}
}
再在项目根目录下的build.gradle添加
apply from: 'config.gradle'
让模块拥有组件化能力
既然要组件化开发那么我这个login应该既可以变成library又是变能单独运行的APP模块,那么问题来了,我们怎么做呢?
1.定义一个boolean变量
可以在build.gradle中定义,也可以定义在gradle.properties中
我这里在gradle.properties中定义
2.根据boolean变量判断是library还是application
这样只需要改变isModule就可以控制login组件是library还是application了。
为library和application配置不同的AndroidManifest.xml
由于运行application和library需要的Manifest文件由于合并的关系要求是不一样的。我们最好是提供两个不同的AndroidManifest.xml
有一些在application模式中需要加载的资源文件其实在library模式中是不需要打包到主入口APP里面去的,于是也做了如下处理:
sourceSets {
main {
if (isModule.toBoolean()) {
manifest.srcFile 'src/main/module/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'
java.srcDirs = [
"src/main/java",
"src/main/module/java"
]
res.srcDirs = [
'src/main/res',
'src/main/module/res'
]
}
}
}
链接: Android 项目源码地址
链接: JAVA后端项目源码地址
//todo 给我感觉写代码远比写文章要轻松....致敬所有写文分享的人
当然组件化的切换配置操作可以用编译时技术进行封装动态生成。这里只写了组件化开发的一些基础简要原理方案。