前言
上一篇文章,我们实现了一个简单的Gradle 插件,并打印出了Hello world。打通了对于插件开发的流程,导师之前写了一个检测目录资源的Gradle插件,看了其源码后,自己准备完全用groovy来实现一个帮助我么定位出工程中的大文件,比如一个大的资源文件,一个类文件,我们可以迅速定位到相关文件,做分析,是否需要对资源文件压缩,或者类文件是否需要重构。当然大的类不一定都是需要我们去重构的类。
本着简洁代码的原则,带着我们的需求来做相应的开发。
实现思路
实现的思路比较简单。在Build文件执行完成之后,也就是在Project的afterEvaluate方法中,来遍历当前的文件目录,然后计算当前文件的大小,根据设置的数据来保存下相应的文件信息。最后打印出来。
插件的实现
- 定义插件类
向Task中传递我们当前Java目录和资源目录,然后还有定义的对于资源数量的限制的数目。
import org.gradle.api.Plugin
import org.gradle.api.Project
class FileCleaner implements Plugin<Project> {
@Override
void apply(Project project) {
def fileCount = project.extensions.create("fileCount", FileSizeExtension)
Set<String> paths = new LinkedHashSet<>()
for (String clazz : project.android.sourceSets.main.java.getSrcDirs()) {
paths.add(clazz)
}
for (String resource : project.android.sourceSets.main.res.getSrcDirs()) {
paths.add(resource)
}
project.afterEvaluate {
initTask(project, fileCount, paths)
}
}
FileTraverseTask initTask(Project project, FileSizeExtension fileSizeExtension, Set<String> paths) {
def fileTraverseTask = project.task("filetraverse", type:FileTraverseTask) {
classCount fileSizeExtension.classCount
resourceCount fileSizeExtension.resourceCount
filePaths paths
}
return fileTraverseTask
}
}
- 定义Task
对于核心功能的实现,主要通过一个这里定义的一个FileManager类来
实现。
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
class FileTraverseTask extends DefaultTask {
int classCount
int resourceCount
Set<String> filePaths
void filePaths(Set<String> values) {
this.filePaths = values
}
@TaskAction
def traverseFile () {
FileManager manager = new FileManager(classCount, resourceCount)
for (String path : filePaths) {
File file = new File(path)
manager.traverseFile(file)
}
manager.printResult(project.getBuildDir().getAbsolutePath()+File.separator+"/filecleaner.txt")
}
}
- 遍历文件
class FileManager {
private SortArray classArray
private SortArray resourceArray
FileManager (int classCount, int resourceCount) {
classArray = new SortArray(classCount)
resourceArray = new SortArray(resourceCount)
}
void traverseFile(File file) {
File[] files = file.listFiles()
for (File file1 : files) {
if (file1.directory) {
traverseFile(file1)
} else if (file1.file) {
processFile(file1)
}
}
}
void processFile(File file) {
String path = file.absolutePath
long size = file.size()
FileItem item = new FileItem()
item.path = path
item.size = size
if (isResource(file.path)) {
resourceArray.add(item)
} else {
classArray.add(item)
}
}
boolean isResource(String path) {
if (path.contains("main/res")) {
return true
} else if (path.contains("main/java")) {
return false
}
}
void printResult(String fileName) {
try {
output(fileName)
} catch (IOException) {
}
}
void output(String fileName) throws IOException {
if (classArray.length() == 0 || resourceArray.length() == 0)
return
File result = null
FileWriter writer = null
result = new File(fileName)
writer = new FileWriter(result)
BufferedWriter bufferedWriter = new BufferedWriter(writer)
bufferedWriter.write("Class size table")
bufferedWriter.newLine()
for (int i = 0; i < classArray.length(); i++) {
bufferedWriter.write(i+"")
bufferedWriter.newLine()
bufferedWriter.write(classArray.getItem(i).toString())
bufferedWriter.newLine()
}
bufferedWriter.newLine()
bufferedWriter.write("Resource size table")
bufferedWriter.newLine()
for (int j = 0; j < resourceArray.length(); j++) {
bufferedWriter.write(j+"")
bufferedWriter.newLine()
bufferedWriter.write(resourceArray.getItem(j).toString())
bufferedWriter.newLine()
}
bufferedWriter.flush()
writer.close()
}
}
对于SortArray内部的是通过LinkedList来实现的
class SortArray {
private LinkedList<FileItem> list
private int size
SortArray(int size) {
this.size = size
list = new LinkedList<>()
}
void add(FileItem item) {
if (list.size() == 0) {
list.add(item)
return
}
for (int i = 0; i < list.size(); i++) {
FileItem tmp = list.get(i)
if (item.size > tmp.size) {
list.add(i, item)
break
}
}
if (list.size() > size) {
list.removeLast()
}
}
int length() {
return list.size()
}
FileItem getItem(int index) {
return list.get(index)
}
}
通过FileItem来表示每一个文件,主要包含文件的路径信息和大小。
class FileItem {
private long size
private String path
void setSize(long size) {
this.size = size
}
long getSize() {
return size
}
String getPath() {
return path
}
String setPath(String path) {
this.path = path
}
boolean compareTo(FileItem item) {
if (item == null) {
return true
}
return (this.size - item.size) >= 0 ? true : false
}
String toString() {
return "path:" + path +"\n" + "size:" + size
}
}
上传到Jcenter
上传到Jcenter的过程可以说是一个非常痛苦的过程,中间遇到了很多的问题,各种配置出问题,而且可能会出现重启AndroidStudio后,就可上传成功的类似问题~~~(clean并不管用)
这个时候也意识到在网上写文章一定要对与自己的读者负责,如果你不能够去把一个技术细节讲好,那么也不要把其讲错,否则就是在给后来人挖一个大坑。
网上针对上传到Jcenter的文章有很多,针对其中具体的步骤也就不再展开了。对于上传主要步骤。对于其中的配置项在配置时要仔细。这里丢一个链接 Gradle之使用Android Studio 编写Gradle插件并上传Library到JCenter
- 注册Jcenter账号
- 添加install配置
- 添加bintray配置
- 执行install
- 执行bintray上传
Tips:对于Bintray中账号的注册,要记得注册为个人版,否则会导致上传项目无法add link 到jcenter之中。
应用到项目
由于刚上传到Jcenter,这里应用到项目的方式还是上一篇文章中讲的方式,通过本地maven依赖的方式。输出结果如下。
Class size table
0
path:/Users/chenjensen/AndroidStudioProjects/Graphics/app/src/main/java/com/chenjensen/myapplication/MainActivity.java
size:1019
1
path:/Users/chenjensen/AndroidStudioProjects/Graphics/app/src/main/java/com/chenjensen/myapplication/ExampleService.java
size:735
Resource size table
0
path:/Users/chenjensen/AndroidStudioProjects/Graphics/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
size:14696
1
path:/Users/chenjensen/AndroidStudioProjects/Graphics/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
size:10486
2
path:/Users/chenjensen/AndroidStudioProjects/Graphics/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
size:10056
3
path:/Users/chenjensen/AndroidStudioProjects/Graphics/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
size:7718
4
path:/Users/chenjensen/AndroidStudioProjects/Graphics/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
size:6114
总结
gradle插件相关知识梳理到了第四篇了,最近事情比较多,对于这系列文章的开始定为更多的是一个入门系列,针对一些知识点进行梳理。认识这个东西,并能够利用它做一些东西,对于具体的深入还需要我们花时间去看相应文档去做更深层次的研究,当然对于基本开发的应用,其已经基本满足需求了。