關於Android Gradle你需要知道這些(4)

Jensen95發表於2018-02-03

前言

上一篇文章,我們實現了一個簡單的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外掛相關知識梳理到了第四篇了,最近事情比較多,對於這系列文章的開始定為更多的是一個入門系列,針對一些知識點進行梳理。認識這個東西,並能夠利用它做一些東西,對於具體的深入還需要我們花時間去看相應文件去做更深層次的研究,當然對於基本開發的應用,其已經基本滿足需求了。

相關文章