脚手架
脚手架是为了保证各施工过程顺利进行而搭设的工作平台
而在程序开发过程中,每个工程或者说公司也都需要一个脚手架工具。通过脚手架命令行的形式简化开发流程,避免发生一些人为的相对低级的问题,所以这个也就是为什么叫做脚手架的原因吧。
而由于每个公司的代码规范都不同,一般情况下会主动让开发同学进行工程方面的cv操作,就是成本高并且容易出错。这也就是为什么我们打算写一些这样的工具的原因。
在一般情况下,更多的程序猿会选择用python去写,因为脚本语言的灵活性,但是对于一个辣鸡安卓来说会增加额外的学习成本,所以这就取决于有没有天赋了,能不能对一门陌生的语言快速上手了。
这次文章会介绍的是用kotlin去构建一个二进制文件,通过这个来完成脚手架cli工具的建设。
开搞
demo 工程地址TheNext
一开始的启发在于有时候使用一些第三方工具的时候会提供一个jar包,然后只要输入java -jar xxx.jar
就可以使用这个jar包中的Main函数了。
因为是一个jar包,所以里面的内容肯定也都是用jvm内的几种语言来进行编写的,那么这就让我们这种老年选手看到了一丝丝的希望。
开发调试
先建立了一个java工程,然后构建了一个main函数,之后开始进行代码编写。但是如果每次都需要先打包之后在通过java -jar
来执行的话非常不便利开发并且debug。而且模拟入参也灰常的恶心,你也知道的程序猿都是懒人吗。
所以我们就借用了unittest
的能力,对于入参进行mock进行简单的调试功能了。
【参考地址](github.com/Leifzhang/T…)
class Sample {
@Test
fun help() {
Next.main(
arrayOf(
"--help"
)
)
}
@Test
fun testAndroidModule() {
val file = File("")
val moduleName = "strike-freedom"
val groupName = "com.kronos.common"
Next.main(
arrayOf(
"module", "android",
"-file", file.absolutePath,
"-name", moduleName,
"-group", groupName
)
)
}
@Test
fun testAndroidApplication() {
val file = File("../app/")
val projectName = "freedom"
Next.main(
arrayOf(
"project", "android",
"-name", projectName,
"-file", file.absolutePath
)
)
}
}
此处我们将Main函数通过unittest来进行模拟,这样就可以方便我们在开发阶段快速调试脚手架的能力了。
每个方法块都可以认为是一个运行的入口,通过这个来模拟出程序所需要的入参。从而一边完成了测试代码的编写,一边完成了调试入口。
jcommander
这是一个让我们可以更像模像样的写一个cli的入参解析工具,即使参数顺序是错乱的,我们仍然能解析出我们想要的数据结构,让我们的工程看起来更正规一点。而且这个库也被很多开源项目所使用,基本算的上是千锤百炼了,比如美团的walle
。
jcommander值得你一个star的
@Parameters(commandDescription = "args 参数")
class CommandEntity {
@Parameter(
names = ["-file", "-f"],
required = true,
converter = FileConverter::class,
description = "生成目标文件路径"
)
lateinit var file: File
@Parameter(
names = ["-name"], required = true,
description = "文件名"
)
lateinit var name: String
@Parameter(names = ["-group", "-bundle", "-g", "-b"], description = "唯一标识符")
var group: String? = null
}
override fun handle(args: Array<String>) {
val commandEntity = CommandEntity()
JCommander.newBuilder().addObject(commandEntity).build().parse(*args)
}
实例demo如上,我也是参考了官方demo写的。通过JCommander
将args解析成对应的数据实体结构。
Main 函数声明
我们要在build.gradle
内的jar的task中,声明当前jar的main
函数,作为命令行工具的入口。否则打出来的jar包就会报没有main函数的异常。
jar {
exclude("**/module-info.class")
/* from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}*/
manifest {
attributes 'Main-Class': 'com.kronos.mebium.Next'
}
}
其中from的含义就是将一个jar包把所有的依赖都打到一起,从而形成一个fatjar
,而后续因为使用了gradle提供的application
插件,所以这行被我注释了。
压缩模板
我们这个脚手架最核心的就是把一部分工程模板压缩成一个zip资源文件,打包带入jar产物中。然后呢我这个人又比较懒,希望每次执行打包的时候都进行一次模板的压缩替换,所以这里我通过一部分gradle task
来进行执行了。
abstract class ZipTask extends DefaultTask {
@InputDirectory
Provider<File> library = project.objects.property(File)
@OutputFile
Provider<File> outputFile = project.objects.property(File)
@TaskAction
def doAction() {
def outputFile = outputFile.get()
createFileSafety(outputFile)
compress(library.get(), outputFile)
}
static File compress(final File srcDir, final File zipFile) {
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))
srcDir.eachFileRecurse({
zos.putNextEntry(new ZipEntry(it.path - srcDir.path + (it.directory ? "/" : "")))
if (it.file) {
zos << it.bytes
}
zos.closeEntry()
})
zos.close()
return zipFile
}
private static File createFileSafety(File file) {
if (file.exists()) {
file.delete()
}
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs()
}
return file
}
}
首先定义出一个task,然后定义好输入输出,输入的是一个文件夹,输出的则是一个zip的压缩文件,输入输出的地址由外部来声明。
def moduleTask = project.tasks.register("zipAndroidLib", ZipTask.class) {
it.library.set(file("../library"))
it.outputFile.set(file("./src/main/resources/zip/android/android.zip"))
}
def projectTask = project.tasks.register("zipAndroidProject", ZipTask.class) {
it.library.set(file("../project"))
it.outputFile.set(file("./src/main/resources/zip/android/project.zip"))
}
afterEvaluate {
project.tasks.findByName("compileJava").dependsOn(moduleTask)
project.tasks.findByName("compileJava").dependsOn(projectTask)
}
然后直接声明处两个task,之后把compileJava
依赖到这两个task上去,这样就可以保证每次compileJava
,这两个task都会被执行到了。编译缓存我就不说了,大家自行领悟吧。
java resource 读取方式
javaClass.classLoader.getResourceAsStream(name)
就可以了。
放飞自我
接下来我们就可以在命令行工具内放飞自我,开始很简单的通过unittest来进行代码的编写和调试了。
我们就可以通过自己熟悉的kotlin或者java来编写一个简单的cli工具,从而来进一步的做到基于工程定制化的一些方便的脚手架工具了。
生成最终产物
这里我们使用了 gradle提供的application plugin
,这个插件可以将java jar包装成一个可执行文件的zip的压缩包。格式如下图所示:
而这个的生成指令就是,通过./gradlew impact:assembleDist 任务生成对应的二进制压缩包。
这样的好处就是我们可以省略掉java -jar xxxxx.jar
的繁琐操作,通过可执行文件直接达到我们写一个cli的便利。
结尾
工程内的代码还是比较简单的,有兴趣的就自己读一下,只是一个demo而已。
还是那句因为菜,不想去学一门新语言。如果万一哪怕我的py在强那么一点点,我也考虑用py来写了,哈哈哈哈哈。
作者:究极逮虾户
链接:https://juejin.cn/post/7171248904971747341
最后
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
一、架构师筑基必备技能
1、深入理解Java泛型
2、注解深入浅出
3、并发编程
4、数据传输与序列化
5、Java虚拟机原理
6、高效IO
……
二、Android百大框架源码解析
1.Retrofit 2.0源码解析
2.Okhttp3源码解析
3.ButterKnife源码解析
4.MPAndroidChart 源码解析
5.Glide源码解析
6.Leakcanary 源码解析
7.Universal-lmage-Loader源码解析
8.EventBus 3.0源码解析
9.zxing源码分析
10.Picasso源码解析
11.LottieAndroid使用详解及源码解析
12.Fresco 源码分析——图片加载流程
三、Android性能优化实战解析
- 腾讯Bugly:对字符串匹配算法的一点理解
- 爱奇艺:安卓APP崩溃捕获方案——xCrash
- 字节跳动:深入理解Gradle框架之一:Plugin, Extension, buildSrc
- 百度APP技术:Android H5首屏优化实践
- 支付宝客户端架构解析:Android 客户端启动速度优化之「垃圾回收」
- 携程:从智行 Android 项目看组件化架构实践
- 网易新闻构建优化:如何让你的构建速度“势如闪电”?
- …
四、高级kotlin强化实战
1、Kotlin入门教程
2、Kotlin 实战避坑指南
3、项目实战《Kotlin Jetpack 实战》
-
从一个膜拜大神的 Demo 开始
-
Kotlin 写 Gradle 脚本是一种什么体验?
-
Kotlin 编程的三重境界
-
Kotlin 高阶函数
-
Kotlin 泛型
-
Kotlin 扩展
-
Kotlin 委托
-
协程“不为人知”的调试技巧
-
图解协程:suspend
五、Android高级UI开源框架进阶解密
1.SmartRefreshLayout的使用
2.Android之PullToRefresh控件源码解析
3.Android-PullToRefresh下拉刷新库基本用法
4.LoadSir-高效易用的加载反馈页管理框架
5.Android通用LoadingView加载框架详解
6.MPAndroidChart实现LineChart(折线图)
7.hellocharts-android使用指南
8.SmartTable使用指南
9.开源项目android-uitableview介绍
10.ExcelPanel 使用指南
11.Android开源项目SlidingMenu深切解析
12.MaterialDrawer使用指南
六、NDK模块开发
1、NDK 模块开发
2、JNI 模块
3、Native 开发工具
4、Linux 编程
5、底层图片处理
6、音视频开发
7、机器学习
七、Flutter技术进阶
1、Flutter跨平台开发概述
2、Windows中Flutter开发环境搭建
3、编写你的第一个Flutter APP
4、Flutter开发环境搭建和调试
5、Dart语法篇之基础语法(一)
6、Dart语法篇之集合的使用与源码解析(二)
7、Dart语法篇之集合操作符函数与源码分析(三)
…
八、微信小程序开发
1、小程序概述及入门
2、小程序UI开发
3、API操作
4、购物商场项目实战……
全套视频资料:
一、面试合集
二、源码解析合集
三、开源框架合集
欢迎大家一键三连支持,若需要文中资料,可扫描下方CSDN官方认证微信二维码免费领取↓↓↓