手把手教你實(shí)現(xiàn)一個(gè) Gradle Tansform 實(shí)例

關(guān)于Gradle Transform API 的詳細(xì)分析我之前有一篇文章Android Gradle Transform 詳解已經(jīng)講到了,這里不再重復(fù),直接開始上手?jǐn)]代碼,還沒看過前面一篇博客的同學(xué)建議先去看看,好幫助理解。

1、 新建 Android Library Module :plugin,清空plugin的build.gradle文件中的內(nèi)容,然后修改成如下內(nèi)容

apply plugin: 'groovy'
apply plugin: 'maven'
dependencies {
    implementation gradleApi() //gradle sdk
    implementation localGroovy() //groovy sdk

    implementation 'com.android.tools.build:gradle:3.4.1'
}
repositories {
    jcenter()
}

uploadArchives {
    repositories.mavenDeployer {
        //本地倉庫路徑,以放到項(xiàng)目根目錄下的 repo 的文件夾為例
        repository(url: uri('../repo'))

        //groupId ,自行定義,組織名或公司名
        pom.groupId = 'com.jokerwan'

        //artifactId,自行定義,項(xiàng)目名或模塊名
        pom.artifactId = 'autotrack.android'

        //插件版本號(hào)
        pom.version = '1.0.0'
    }
}

我們這里是發(fā)布plugin插件到本地倉庫,上面配置的groupIdartifactIdversion屬性能容都是可以自定義的,當(dāng)應(yīng)用程序引用這個(gè)插件時(shí)會(huì)用到這些信息。通過repositories屬性,可以把uri配置在本地目錄,這樣就可以把maven設(shè)置成本地倉庫,我們目前把倉庫配置到當(dāng)前Project根目錄下的repo目錄。

2、 刪除plugin/src/main目錄下的所有文件,新建groovy目錄

因?yàn)椴寮覀冇玫氖莋roovy語言開發(fā)的,所以需要放到groovy目錄下。接著再groovy目錄下新建一個(gè)package com.jokerwan.demo.plugin來存放Transform類文件

3、 創(chuàng)建Transform類

在包com.jokerwan.demo.plugin下創(chuàng)建JokerWanTransform.groovy類,直接new一個(gè)file,名稱為“JokerWanTransform.groovy”,代碼如下:

package com.jokerwan.demo.plugin

import com.android.build.api.transform.*
import com.android.build.gradle.internal.pipeline.TransformManager
import org.apache.commons.codec.digest.DigestUtils
import org.apache.commons.io.FileUtils
import org.gradle.api.Project

class JokerWanTransform extends Transform {

    private static Project project
    private static final String NAME = "JokerWanAutoTrack"

    JokerWanTransform(Project project) {
        this.project = project
    }

    @Override
    String getName() {
        return NAME
    }

    /**
     * 需要處理的數(shù)據(jù)類型,有兩種枚舉類型
     * CLASSES 代表處理的 java 的 class 文件,RESOURCES 代表要處理 java 的資源
     * @return
     */
    @Override
    Set<QualifiedContent.ContentType> getInputTypes() {
        return TransformManager.CONTENT_CLASS
    }

    /**
     * 指 Transform 要操作內(nèi)容的范圍,官方文檔 Scope 有 7 種類型:
     * 1. EXTERNAL_LIBRARIES        只有外部庫
     * 2. PROJECT                   只有項(xiàng)目?jī)?nèi)容
     * 3. PROJECT_LOCAL_DEPS        只有項(xiàng)目的本地依賴(本地jar)
     * 4. PROVIDED_ONLY             只提供本地或遠(yuǎn)程依賴項(xiàng)
     * 5. SUB_PROJECTS              只有子項(xiàng)目。
     * 6. SUB_PROJECTS_LOCAL_DEPS   只有子項(xiàng)目的本地依賴項(xiàng)(本地jar)。
     * 7. TESTED_CODE               由當(dāng)前變量(包括依賴項(xiàng))測(cè)試的代碼
     * @return
     */
    @Override
    Set<? super QualifiedContent.Scope> getScopes() {
        return TransformManager.SCOPE_FULL_PROJECT
    }

    @Override
    boolean isIncremental() {
        return false
    }

    static void printCopyRight() {
        println()
        println("******************************************************************************")
        println("******                                                                  ******")
        println("******                歡迎使用 JokerWanTransform 編譯插件               ******")
        println("******                                                                  ******")
        println("******************************************************************************")
        println()
    }

    @Override
    void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
        printCopyRight()

        TransformOutputProvider outputProvider = transformInvocation.getOutputProvider()

        // Transform 的 inputs 有兩種類型,一種是目錄,一種是 jar 包,要分開遍歷
        transformInvocation.inputs.each { TransformInput input ->
            input.jarInputs.each { JarInput jarInput ->
                // 處理jar
                processJarInput(jarInput, outputProvider)
            }

            input.directoryInputs.each { DirectoryInput directoryInput ->
                // 處理源碼文件
                processDirectoryInput(directoryInput, outputProvider)
            }
        }

    }

    void processJarInput(JarInput jarInput, TransformOutputProvider outputProvider) {
        // 重命名輸出文件(同目錄copyFile會(huì)沖突)
        def jarName = jarInput.name
        def md5Name = DigestUtils.md5Hex(jarInput.file.getAbsolutePath())
        if (jarName.endsWith(".jar")) {
            jarName = jarName.substring(0, jarName.length() - 4)
        }

        File dest = outputProvider.getContentLocation(
                jarName + md5Name,
                jarInput.getContentTypes(),
                jarInput.getScopes(),
                Format.JAR
        )

        // TODO do some transform

        // 將 input 的目錄復(fù)制到 output 指定目錄
        FileUtils.copyFile(jarInput.getFile(), dest)
    }

    void processDirectoryInput(DirectoryInput directoryInput, TransformOutputProvider outputProvider) {
        File dest = outputProvider.getContentLocation(
                directoryInput.getName(),
                directoryInput.getContentTypes(),
                directoryInput.getScopes(),
                Format.DIRECTORY
        )

        // TODO do some transform

        // 將 input 的目錄復(fù)制到 output 指定目錄
        FileUtils.copyDirectory(directoryInput.getFile(), dest)
    }
}

我們?cè)?code>transform方法里面,先打印一個(gè)提示信息,然后分別遍歷目錄和jar包,在這里我們僅僅把所有的輸入文件拷貝到目標(biāo)目錄下,并沒有對(duì)文件進(jìn)行任何處理。這里需要注意的是,即使我們對(duì)文件沒有任何處理,任然需要將所有的輸入文件拷貝到目標(biāo)目錄下,否則下一個(gè)Task就沒有TansformInput了,如果我們將 input 的目錄復(fù)制到 output 指定目錄,最后會(huì)導(dǎo)致打包的apk缺少.class文件。

4、 創(chuàng)建plugin

在包com.jokerwan.demo.plugin下創(chuàng)建JokerWanPlugin.groovy類,并將JokerWanTransform類注冊(cè)進(jìn)去

class JokerWanPlugin implements Plugin<Project> {
    void apply(Project project) {
        AppExtension appExtension = project.extensions.findByType(AppExtension.class)
        appExtension.registerTransform(new JokerWanTransform(project))
    }
}

JokerWanPlugin實(shí)現(xiàn)了Plugin<Project>接口中的apply(Project project)方法,獲取一個(gè)appExtension對(duì)象,然后調(diào)用其registerTransform方法將JokerWanTransformNew的實(shí)例注冊(cè)進(jìn)去

5、 創(chuàng)建properties文件

在plugin/src/main目錄下新建目錄 resources/META-INF/gradle-plugins,接著在此目錄下新建文件com.jokerwan.android.properties,文件內(nèi)容如下:

implementation-class=com.jokerwan.demo.plugin.JokerWanPlugin

文件名com.jokerwan.android就是用來指定插件名稱的,apply該組件時(shí)會(huì)用到,即

apply plugin: 'com.jokerwan.android'

“=”號(hào)后面的內(nèi)容就是我們插件類JokerWanPlugin的全類名

6、 構(gòu)建plugin

執(zhí)行plugin的uploadArchives任務(wù)構(gòu)建plugin

構(gòu)建成功之后,在項(xiàng)目的根目錄會(huì)生成一個(gè)repo目錄,里面存放的就是plugin插件的目標(biāo)文件。構(gòu)建成功輸出信息如下:


7、 添加對(duì)插件的依賴

7.1、 修改項(xiàng)目根目錄下的build.gradle文件
7.2、 修改app/build.gradle文件

8、 構(gòu)建應(yīng)用程序

可以通過命令行進(jìn)行編譯

./gradlew assembleDebug

如果編譯沒有報(bào)錯(cuò)的話并且看到相應(yīng)的輸出信息,就可以說明上面定義的JokerWanTransform已經(jīng)成功運(yùn)行了。編譯成功輸出信息如下:

demo代碼如下
https://github.com/isJoker/TestTransform

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容