Android Gradle Task 自动打包上传到蒲公英并通知企业微信机器人

近期频繁的打包, 有点心累, 所以有了这篇文章. 话不多说, 直接开整.

先上企业微信机器人通知的效果


image.png

1. 创建 task.gradle

在项目的 build.gradle 所在的目录下创建一个 task.gradle 内容如下

project.ext {
    uploadTask = { extension,versionName ->
        extension.android {
            task upload2Pgyer(group: 'upload', description: 'Upload apk to pgyer', dependsOn: 'assembleDebug') {
                doLast {
                    android.applicationVariants.all { variant ->
                        String taskSuffix = variant.name.capitalize()
                        //输出versionname
                        if (taskSuffix.equals("Debug")) {
                            variant.outputs.all { output ->
                                // 执行脚本任务
                                uploadApk(output.outputFile, versionName)
                            }
                        }
                    }
                }
            }
        }
    }
}

我这里是只打了debug包. 别的环境的自己的需求进行修改.
接着就需要创建具体的执行任务的上传及通知脚本了.

2. 创建 pgyer-upload.gradle

代码较多, 后面一些获取git提交日志的方法没有用到. 不需要的可以删掉. 通知的内容改成了 markdown 的形式, 看起来好看一点. 这点看个人需求了. 不需要的可以将

    def json = JsonOutput.toJson([
            msgtype: "markdown",
            markdown: [
                    content: message
            ]
    ])

这里的 markdown 改为 text. 完整代码如下:

import groovy.json.JsonSlurper
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse
import java.text.SimpleDateFormat
import groovy.json.JsonOutput
ext.uploadApk = this.&uploadApk

def String makeMarkDownText(String versionName, String url, String updateTime) {
    return """
      ### <font color="warning">**新版本更新**</font>\n
      > 应用名称:<font color="info">app名称</font>
      > 应用类型:<font color="info">Android</font>
      > 对应版本:<font color="info">${versionName}</font>
      > 应用环境:<font color="info">国内测试环境</font>
      > 更新日期:<font color="info">${updateTime}</font>\n
      > 更新内容如下
      > <font color="info">1. Gradle</font> 
      > <font color="info">2. Task</font>
      > <font color="info">3. 自动构建</font>
      > <font color="info">4. 自动上传</font>
      > <font color="info">5. 自动通知</font> \n
      > [点击链接安装此版本](${url}) \n
      """
}

static String getApiKey() {
    return "蒲公英的APIKEY"
}
static String getPgyDescription() {
    return ""
}

def uploadApk(File apk, String versionName) {
    //查找上传的apk文件,这里需要换成自己apk路径
    if (!apk.exists()) {
        println "*************** APK 文件不存在 ***************"
    }
    println "*************** 开始上传文件 ***************"
    def twoHyphens = "--"
    def boundary = "*********"
    def end = "\r\n"

    //模拟表单上传 multipart/form-data
    def conn = new URL("https://www.pgyer.com/apiv2/app/upload").openConnection()
    conn.setRequestMethod('POST')
    conn.setRequestProperty("Connection", "Keep-Alive")
    conn.setRequestProperty("Charset", "UTF-8")
    conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary)
    conn.setDoInput(true)
    conn.setDoOutput(true)
    //添加参数:_api_key
    def sb = new StringBuilder()
    sb.append(twoHyphens).append(boundary).append(end)
    sb.append("Content-Disposition: form-data; name=_api_key")
    sb.append(end).append(end)
    sb.append(apiKey).append(end)

    //添加参数:buildUpdateDescription 更新日志,取值gradle.properties中的 BUILD_NOTES
    sb.append(twoHyphens).append(boundary).append(end)
    sb.append("Content-Disposition: form-data; name=buildUpdateDescription")
    sb.append(end).append(end)
    sb.append(pgyDescription).append(end)

    //添加参数file: 需要上传的apk文件
    sb.append(twoHyphens).append(boundary).append(end)
    sb.append("Content-Disposition: form-data; name=file;filename=").append(apk.getName())
    sb.append(end).append(end)

    def dos = new DataOutputStream(conn.getOutputStream())
    dos.writeBytes(sb.toString())
    dos.flush()
    sb.delete(0, sb.length())

    def fis = new FileInputStream(apk)
    byte[] bf = new byte[8192]
    int len
    while ((len = fis.read(bf)) != -1) {
        dos.write(bf, 0, len)
    }
    sb.append(end)
    sb.append(twoHyphens).append(boundary).append(end)
    dos.writeBytes(sb.toString())

    dos.flush()
    fis.close()
    dos.close()
    conn.connect()

    def text = conn.getContent().text

    def resp = new JsonSlurper().parseText(text)

    println text
    if (resp.code != 0) {
        println "*************** 上传失败 *************** 原因 " + resp.message
    }else  {
        println "*************** 上传成功 ***************"
    }

    def downloadUrl = "https://www.pgyer.com/" + resp.data.buildShortcutUrl.strip()
    def updateTime = resp.data.buildUpdated
    def content = makeMarkDownText(versionName, downloadUrl, updateTime)

    notifyWeChatBot(content)
}

/**
 * 通知企业微信机器人
 */
def notifyWeChatBot(String message) {
    // 替换以下变量为你的企业微信机器人 webhook URL
    def webhookUrl = "企业微信机器人的urlkey"

    // 构建 JSON 数据
    def json = JsonOutput.toJson([
            msgtype: "markdown",
            markdown: [
                    content: message
            ]
    ])

    // 发送 HTTP POST 请求
    HttpResponse<String> response = postJsonData(webhookUrl, json)

    // 打印响应结果
    println ">>>> 企业微信机器人通知结果:\n${response.body()}"
}

/**
 * 发送 JSON 数据的 HTTP POST 请求
 */
static HttpResponse<String> postJsonData(String url, String json) {
    HttpRequest httpRequest = HttpRequest
            .newBuilder(URI.create(url))
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(json))
            .build()
    return HttpClient.newHttpClient().send(httpRequest, HttpResponse.BodyHandlers.ofString())
}



/**
 * 获取当天提交日志
 * @return
 */
static String getGitCommitLogByToDay() {
    //获取 git 提交日志
    Calendar calendar = Calendar.getInstance()
    String endTime = new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime())
    calendar.add(Calendar.DATE, -1)
    String startTime = new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime())
    //git 命令
    String gitCommand = "git log --pretty=\"%s\" --since=\"${startTime}\" --before=\"${endTime}\""
    //println "getUpdateDescription() --> gitCommand = ${gitCommand}"
    String description = gitCommand.execute().text.trim()
    return description
}

/**
 * 获取最近 n 条提交日志
 */
static String getGitCommitLogByCount(int count) {
    //git 命令
    String gitCommand = "git log -${count} --pretty=format:\"%s\""
    //println "getUpdateDescription() --> gitCommand = ${gitCommand}"
    String description = gitCommand.execute().text.trim()
    return description
}

/**
 * 获取分支名
 */
static String getBranchName() {
    String gitCommand = "git rev-parse --abbrev-ref HEAD"
    return gitCommand.execute().text.trim()
}

class KeyValue {
    String key
    String value
    boolean isFile

    KeyValue(String key, String value) {
        this(key, value, false)
    }

    KeyValue(String key, String value, boolean isFile) {
        this.key = key
        this.value = value
        this.isFile = isFile
    }

    @Override
    String toString() {
        return "{key:" + key + ", value:" + value + ", isFile:$isFile}"
    }
}

3. 使用

app module 下中的 build.gradle 文件中添加

apply from: "${rootProject.rootDir}/task.gradle"
apply from: "${rootProject.rootDir}/pgyer-upload.gradle"

重新编译后,在Gradle 工具侧栏中的 Tasks 目录下就回有一个 upload 的文件夹, 里面有一个 uplopad2Pgyer 的任务. 双击就能执行脚本了. 自动打Debug包, 然后上传到蒲公英, 并发送企业微信通知了.

image.png

4. 遇到的问题

4.1 Tasks 没有显示

遇到 Gradle 中的这个 Tasks 没有出现的. 需要进行设置一下. 如下图

image.png
4.2 IPv6

我电脑开启了ipv6, 一直报错, 关闭了后就正常了. 遇到此问题的可以尝试一下这个操作.

后面遇到其他问题了, 继续记录.

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

推荐阅读更多精彩内容