Android 用Gradle Task 插件 在编译之前做点前置准备工作自动生成资源res/java file

前提条件:
现在要做一个sdk,而这个sdk项目要适用于公司所有的App, 然后sdk的主题色要来自外部的app,所以的那个集成的时候我想根据app层的主题配置文件生成sdk所需要的theme主题色,而某个app可能有多个渠道版本,所以对同一个app来说,又分为多个theme主题色,这时候,我想知道并且根据当前运行的flovar在sdk library中生成相应的theme主题色,那么如何知道当前运行的flavor是哪个呢?或者说怎么当前运行的flavor?查阅相关资料,然后关于如何获取当前Flavor,网上千篇一律的都是这个答案:
https://stackoverflow.com/questions/30621183/how-to-get-current-flavor-in-gradle
然后我试了试,别不是网上说的那样,根本无法得到正确的输出,我得到的是这样的答案,一直是null:

然后我想了想,还是只能靠自己,于是我选择了另一条路,我去了解了Gradle的生命周期, 关于Gradle 生命周期及Task全解,感谢下面这个文章博主的干货给了我很大的帮助,
https://www.shangmayuan.com/a/41cac886af394513986270f7.html
经过一天的努力,终于我把上面所提到的Sdk中想要解决的问题完美的达到了我的目标。

Main module:

[app]: build.gradle

apply from: '../mySDK/auto-generating-build-utils.gradle'
dependencies {
   ...
   //generate multiple color files by flavors .
   //android.productFlavors.all { flavor ->
   //     preBuild.dependsOn autoGenerateFileTask(flavor.name)
   // }

  //generate single color file by currently running flavor.
afterEvaluate {
//    android.productFlavors.all { flavor ->
//        def flavorName = "${flavor.name}"
//        def capitalizeTaskPrefix = "${flavor.name}".capitalize()
        def flavorName = "main"
        def capitalizeTaskPrefix = "".capitalize()

        def buildConfigDebugTask = tasks.findByName("pre${capitalizeTaskPrefix}DebugBuild")
        def buildConfigReleaseTask = tasks.findByName("pre${capitalizeTaskPrefix}ReleaseBuild")
        if (buildConfigDebugTask != null) {
            println "chatFlavor:pre${capitalizeTaskPrefix}DebugBuild"
            buildConfigDebugTask.doLast {
                generateChatConfigTask("${flavorName}")
            }
        } else {
            println "chatFlavor:pre${capitalizeTaskPrefix}DebugBuild not found"
        }
        if (buildConfigReleaseTask != null) {
            println "chatFlavor:pre${capitalizeTaskPrefix}ReleaseBuild"
            buildConfigReleaseTask.doLast {
                generateChatConfigTask("${flavorName}")
            }
        } else {
            println "chatFlavor:pre${capitalizeTaskPrefix}ReleaseBuild not found"
        }
//    }
}
...
}

local.properties

## This file is automatically generated by Android Studio.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file should *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
sdk.dir=C\:\\android\\sdk
# example: /assets/chat_theme/chatStyle.json
chatThemeAssetsPath=/assets/my_sdk_res/themeStyle.json
auto-generating-build-utils.gradle

import groovy.json.JsonSlurper
import groovy.json.JsonOutput
import groovy.xml.MarkupBuilder

import java.util.regex.Pattern


ext.autoGenerateFileTask = { projectFlavor ->
    def myProjectName = "chatSDK"
    println projectFlavor
    return tasks.create("generateChatThemeTask$projectFlavor", DefaultTask) {
        // style_default.json is parsed in baseUILib and we will only maintain that json as default
        group = "autoGenerateThemeRelated"
        // Retailers' customized colors
        def localProperties = new Properties()
        def dis = null
        try {
            def localFile = new File("$projectDir/src/main/chat_config.properties")
            println "chat_config_path==========>$localFile"
            if (localFile != null && localFile.exists()) {
                dis = localFile.newDataInputStream()
                localProperties.load(dis)
            } else {
                println "chat_config_path==========>localProperties load failure}"
            }
        } catch (Exception e) {
            println "chat_config_path==========>Exception occurred}"
            e.printStackTrace()
        } finally {
            if (dis != null) {
                dis.close()
            }
        }
        // field definitions
        def matchString = "//.*"
        def inputFile
        def jsonFileString
        def patternComment
        def matcherComment
        def newContent
        def json
        def chatThemeAssetsPath = localProperties.getProperty("chatSDK.chatThemeAssetsPath")
        println "chatSDK.chatThemeAssetsPath==>$projectFlavor:$chatThemeAssetsPath"
        if (chatThemeAssetsPath == null || "" == chatThemeAssetsPath || "null".equalsIgnoreCase(chatThemeAssetsPath)) {
            throw new NullPointerException(" 'chatSDK.chatThemeAssetsPath' must be configured in  '$projectDir/src/main/chat_config.properties' example:\n\n chatSDK.chatThemeAssetsPath=/assets/chat_theme/themeStyle.json\n");
        }
        inputFile = new File("$projectDir/src/$projectFlavor$chatThemeAssetsPath")
        println "chatSDK.chatThemeAssetsPathAbsolutely==>$inputFile.absolutePath"
        jsonFileString = inputFile.text
        patternComment = Pattern.compile(matchString)
        matcherComment = patternComment.matcher(jsonFileString)
        newContent = matcherComment.replaceAll("")
        json = new JsonSlurper().parseText(newContent)
        //do generating color xml.
        generateColorXmlTask(json, projectFlavor, myProjectName)
        //do generating entity class.
        generateEntityTask(localProperties, json, projectFlavor, myProjectName)

        // do generating event entity class
        generateEventEntityTask(localProperties, projectFlavor, myProjectName)
    }
}

private void generateColorXmlTask(Object jsonObject, String flavor, String myProjectName) {
    def sw
    def xml
    def file
    // colors.xml for Brand, will generate color file in GoBank flavor
    sw = new StringWriter()
    xml = new MarkupBuilder(sw)
    xml.setDoubleQuotes(true)
    xml.resources() {
        jsonObject.colors.each {
            k, v ->
                def colorV = swapAlphaColor(v)
                if (colorV.contains("#")) {
                    color(name: "${k}", "${colorV}")
                } else {
                    color(name: "${k}", "@color/" + "${colorV}")
                }
        }
    }

    def desPath = "${rootProject.file("$myProjectName").absolutePath}/src/main"
    def fileDirectoryRes = new File("$desPath/res/values")
    if (!fileDirectoryRes.exists()) {
        fileDirectoryRes.mkdirs()
    }
    file = new File("$desPath/res/values/generated_chat_colors.xml")
    file.write(sw.toString())
}

private String swapAlphaColor(String color) {
    if (color.length() == 9 && color.contains("#")) {
        def swapStringColor = color.substring(1)
        return swapSubstrings(swapStringColor, 7)
    } else {
        return color
    }
}

private String swapSubstrings(String colorValue, Integer index) {
    return "#" + colorValue.substring(index - 1) + colorValue.substring(0, index - 1)
}

private void generateEntityTask(Properties localProperties, Object jsonObject, String projectFlavor, String myProjectName) {
    def desPath = "${rootProject.file("$myProjectName").absolutePath}/src/main/java/com/patrick/chatsdk/theme/model"
    File genDir = new File(desPath)
    if (!genDir.exists()) {
        genDir.mkdirs()
    }
    def autoGenerateTips = "auto-generated code. DO NOT MODIFY!"
    def packageName = "com.patrick.chatsdk.theme.model;"
    def fileHeader = "/**\n*$autoGenerateTips\n*/\npackage $packageName\n\n"
//--------------<start> auto generating ChatColors.java </start>-------------------
    String chatColorFileName = "ChatColors"
    StringBuilder chatColorContent = new StringBuilder()
    chatColorContent.append("$fileHeader")
    chatColorContent.append("public class $chatColorFileName {\n")
    jsonObject.colors.each {
        k, v ->
            chatColorContent.append("    public final String $k = \"$v\";\n")
    }
    chatColorContent.append("}")
    FileWriter colorFw = new FileWriter(new File("$desPath/${chatColorFileName}.java"))
    colorFw.write(chatColorContent.toString())
    colorFw.flush()

//--------------<start> auto generating ChatDimens.java </start>-------------------
    String chatDimensFileName = "ChatDimens"
    StringBuilder chatDimensContent = new StringBuilder()
    chatDimensContent.append("$fileHeader")
    chatDimensContent.append("public class $chatDimensFileName {\n")
    jsonObject.dimens.each {
        k, v ->
            chatDimensContent.append("    public final Double $k = $v;\n")
    }
    chatDimensContent.append("}")
    FileWriter dimensFw = new FileWriter(new File("$desPath/${chatDimensFileName}.java"))
    dimensFw.write(chatDimensContent.toString())
    dimensFw.flush()

//--------------<start> auto generating ChatFonts.java </start>-------------------
    //example:chatSDK.chatFontsDirName=/assets/font/
    //Implementation 1:
//    def assetsDir = "$projectDir/src/$flavor/assets"
//    def defaultFontsDir = new File("$assetsDir/fonts")
//    if (!defaultFontsDir.exists()) {
//        defaultFontsDir = new File("$assetsDir/font")
//    }
//    println "chatSDK.defaultFontsDir==>${defaultFontsDir}[$flavor]"
//    if (!defaultFontsDir.exists()) {
//        def chatFontsDirName = localProperties.getProperty("chatSDK.chatFontsDirName")
//        defaultFontsDir = "$projectDir/src/$flavor$chatFontsDirName"
//        println "chatSDK.chatFontsDirName==>${defaultFontsDir}[$flavor]"
//    }
//    if (defaultFontsDir == null || "" == defaultFontsDir || "null".equalsIgnoreCase(defaultFontsDir)) {
//        throw new NullPointerException(" There is no font files found in ${defaultFontsDir},\n\n either 'chatSDK.chatFontsDirName' must be configured in  '$projectDir/src/main/chat_config.properties' example:\n\n chatSDK.chatFontsDirName=/assets/font/ \n");
//    }
    //Implementation 2:
    def defaultFontsDir = localProperties.getProperty("chatSDK.chatFontsDirName")
    if (defaultFontsDir == null || "" == defaultFontsDir || "null".equalsIgnoreCase(defaultFontsDir)) {
        defaultFontsDir = "font"
    }
    println "chatSDK.defaultFontsDir==>$defaultFontsDir"
    //check first.
    def jsonSlurper = new JsonSlurper()
    def firstFontStyleJson = ""
    jsonObject.fonts.eachWithIndex {
        keyValue, index ->
            if (index == 0) {
                def firstFontEntry = JsonOutput.toJson(keyValue)
                def firstFontValue = jsonSlurper.parseText(firstFontEntry).value
                def firstFontGroovy = JsonOutput.toJson(firstFontValue)
                firstFontStyleJson = jsonSlurper.parseText(firstFontGroovy)
                println "chatSDK.firstFontFileJsonStyle==>${firstFontStyleJson.family}|${firstFontStyleJson.weight}|${firstFontStyleJson.size}"
                return true
            }
            println "chatSDK.testLoopBreak==>index=$index"
    }
    println "\nchatSDK.checkValidFont==>phrase_1"
    def validFormatJson = checkValidFont(projectFlavor, "assets", defaultFontsDir, firstFontStyleJson.family, firstFontStyleJson.weight, "_", 0)
    if ("" == validFormatJson) {
        println "\nchatSDK.checkValidFont==>phrase_2"
        validFormatJson = checkValidFont(projectFlavor, "res", defaultFontsDir, firstFontStyleJson.family, firstFontStyleJson.weight, "_", 0)
    }
    println "chatSDK.checkValidFont==>found in valid font format json '$validFormatJson'\n"
    //start generating.
    def validFormatJsonObject = jsonSlurper.parseText(validFormatJson)
    String chatFontsFileName = "ChatFonts"
    StringBuilder chatFontsContent = new StringBuilder()
    chatFontsContent.append("$fileHeader")
    chatFontsContent.append("public class $chatFontsFileName {\n")
    def fontStyleGroovy
    def fontStyleJson
    def canonicalFamilyChanged
    def canonicalWeightChanged
    def canonicalName
    def isCapital = Boolean.valueOf(validFormatJsonObject.isCapital)
    jsonObject.fonts.each {
        k, v ->
            fontStyleGroovy = JsonOutput.toJson(v)
            fontStyleJson = jsonSlurper.parseText(fontStyleGroovy)
            canonicalFamilyChanged = capitalChange(fontStyleJson.family, isCapital)
            canonicalWeightChanged = capitalChange(fontStyleJson.weight, isCapital)
            canonicalName = "${canonicalFamilyChanged}${validFormatJsonObject.splitSymbol}${canonicalWeightChanged}"
            chatFontsContent.append("    public final ChatThemeFont $k = new ChatThemeFont(\"$defaultFontsDir/${canonicalName}.ttf\", ${fontStyleJson.size}f);\n")
    }
    chatFontsContent.append("}")
    FileWriter fontsFw = new FileWriter(new File("$desPath/${chatFontsFileName}.java"))
    fontsFw.write(chatFontsContent.toString())
    fontsFw.flush()
}

ext.validFormatJson = ""
ext.tempFileName = ""

private String checkValidFont(String projectFlavor, String assetsDir, String fontDir, String family, String weight, String splitSymbol, int index) {
    ext.tempFileName = "${family}$splitSymbol${weight}.ttf"
    def fontCheckingPath = "$projectDir/src/$projectFlavor/$assetsDir/$fontDir/${ext.tempFileName}"
    def validFile = new File(fontCheckingPath)
    println "chatSDK.checkValidFont path==>${validFile.getCanonicalPath()} |exists=${validFile.exists()}"
    if (!validFile.exists()) {//checked: ax_bx.ttf
        if (index == 0) {
            //check: ax-bx.ttf
            checkValidFont(projectFlavor, assetsDir, fontDir, family, weight, "-", 1)
        } else if (index == 1) {
            //check: Ax_Bx.ttf
            checkValidFont("main", assetsDir, fontDir, family, weight, "_", 2)
        } else if (index == 2) {
            //check: Ax-Bx.ttf
            checkValidFont("main", assetsDir, fontDir, family, weight, "-", 3)
        } else if (index == 3) {
            ext.validFormatJson = ""
        }
    } else {
        def isCapitalStr = ext.tempFileName.matches("^[A-Z].*\$")
        if (validFile.getCanonicalPath().contains("${ext.tempFileName}")) {
            println "\nchatSDK.checkValidFont==>path contains=${ext.tempFileName}"
            ext.validFormatJson = "{\"isCapital\":\"${isCapitalStr}\",\"splitSymbol\":\"$splitSymbol\",\"canonicalName\":\"${ext.tempFileName}\"}"
        } else {
            def canonicalFamilyChanged = capitalChange(family, !isCapitalStr)
            def canonicalWeightChanged = capitalChange(weight, !isCapitalStr)
            def canonicalName = "${canonicalFamilyChanged}$splitSymbol${canonicalWeightChanged}"
            println "\nchatSDK.checkValidFont==>path not contains='${ext.tempFileName}' ,the correct one should be '$canonicalName'.ttf"
            ext.validFormatJson = "{\"isCapital\":\"${!isCapitalStr}\",\"splitSymbol\":\"$splitSymbol\",\"canonicalName\":\"$canonicalName\"}"
        }
    }
    return ext.validFormatJson
}

private String capitalChange(String targetStr, boolean upperCase) {
    def targetStrFirst = targetStr.substring(0, 1)
    def targetStrAfter = targetStr.substring(1)
    if (upperCase) {
        return "${targetStrFirst.toUpperCase()}$targetStrAfter"
    } else {
        return "${targetStrFirst.toLowerCase()}$targetStrAfter"
    }
}

private void generateEventEntityTask(Properties localProperties, String projectFlavor, String myProjectName) {

    def chatEventAssetsPath = localProperties.getProperty("chatSDK.chatEventAssetsPath")
    if (chatEventAssetsPath == null || "" == chatEventAssetsPath || "null".equalsIgnoreCase(chatEventAssetsPath)) {
        throw new NullPointerException(" 'chatSDK.chatEventAssetsPath' must be configured in  '$projectDir/src/main/chat_config.properties' example:\n\n chatSDK.chatEventAssetsPath=/assets/chat_theme/chatEvent.json\n");
    }
    def eventInputFile = new File("$projectDir/src/$projectFlavor$chatEventAssetsPath")
    println "chatSDK.chatEventAssetsPathAbsolutely==>$eventInputFile.absolutePath"

    def eventJsonFileString = eventInputFile.text
    def matchString = "//.*"
    def patternComment = Pattern.compile(matchString)
    def matcherComment = patternComment.matcher(eventJsonFileString)
    def eventNewContent = matcherComment.replaceAll("")
    def eventJson = new JsonSlurper().parseText(eventNewContent)

    def desPath = "${rootProject.file("$myProjectName").absolutePath}/src/main/java/com/patrick/chatsdk/event"
    File genDir = new File(desPath)
    if (!genDir.exists()) {
        genDir.mkdirs()
    }

    def autoGenerateTips = "auto-generated code. event part  DO NOT MODIFY!"
    def packageName = "com.patrick.chatsdk.event;"
    def fileHeader = "/**\n*$autoGenerateTips\n*/\npackage $packageName\n\n"

    String chatEventFileName = "ChatEventKey"
    StringBuilder chatEventContent = new StringBuilder()
    chatEventContent.append("$fileHeader")
    chatEventContent.append("public class $chatEventFileName {\n")

    eventJson.eventStateKey.each {
        k, v ->
            chatEventContent.append("    public final String $k = \"$v\";\n")
    }

    eventJson.eventKey.each {
        k, v ->
            chatEventContent.append("    public final String $k = \"$v\";\n")
    }

    chatEventContent.append("}")

    FileWriter eventFw = new FileWriter(new File("$desPath/${chatEventFileName}.java"))
    eventFw.write(chatEventContent.toString())
    eventFw.flush()
}

-----------------------------End-----------------------------

我也是有底线的,感谢您的耐心阅读,欢迎支持与点赞。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355

推荐阅读更多精彩内容