Android——Gradle自动打包上传蒲公英并进行钉钉群提醒

Android——Gradle自动打包上传蒲公英并进行钉钉群提醒开发测试阶段频繁打包未免太过枯燥 自动打包发布解放双手

开发测试阶段频繁打包未免太过枯燥,自动打包发布解放双手。上一节我们分析了fastlane打包发布的过程,嗯~总体来说有点繁琐,而且Android使用fast lane自动打包网上资料比较少,出错之后解决难度颇大。所以今天我们来用一种更简便的方式进行自动打包发布。

1、Gradle自动打包发布蒲公英

apply from: './dingding.gradle'//引用钉钉通知方法 def apkFileName = "${ 
     buildTime()}_test_v${rootProject.ext.android["versionName"]}_release.apk" def apkFilePath = "${ 
     projectDir.absolutePath}/build/outputs/apk/test/release/${ 
     apkFileName}" private def uploadPGY(String filePath) { 
    def stdout = new ByteArrayOutputStream() exec { 
    executable = 'curl' args = ['-F', "file=@${ 
     filePath}", '-F', "_api_key=${rootProject.ext.pgy["apiKey"]}", rootProject.ext.pgy["uploadUrl"]] standardOutput = stdout } String output = stdout.toString() def parsedJson = new groovy.json.JsonSlurper().parseText(output) println parsedJson.data.buildQRCodeURL println "蒲公英上传完成 版本号:" + parsedJson.data.buildVersion println "开始发送钉钉群通知" def downloadUrl = "https://www.pgyer.com/" + parsedJson.data.buildShortcutUrl postDingMsg(parsedJson.data.buildQRCodeURL, downloadUrl) } task uploadApk(dependsOn: '打包Task名称') { 
   //可以从Gradle的Task列表中选取,也可以查看Generate Signed Bundle/Apk执行的task是什么,复制出来就好了 group = "publish"//GradleTask列表中会生成一个publish的分组,里面包含uploadApk,后续只要这个uploadTask任务就可以自动打包发布了 doLast { 
    println "打包完成: ${ 
     apkFilePath}" println "开始上传蒲公英" uploadPGY(apkFilePath) } } 

注:记得在app的build.gradle里面引入这个文件。

2、钉钉群通知

自定义钉钉机器人文档

1、创建自定义钉钉机器人

群组右上角设置按钮打开群设置->智能群助手->添加机器人->自定义机器人->填写机器人名称和关键词(这里的关键词后面发送钉钉群组消息的时候消息内容必须包含该关键词,否则发送不成功)
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

2、接入钉钉群通知
import groovy.json.JsonBuilder import groovy.json.JsonOutput def dingDingUrl = "https://oapi.dingtalk.com/robot/send?access_token=${rootProject.ext.dingding["accessToken"]}" ext.postDingMsg = { 
    String qrcodeUrl, String downloadUrl -> String allTips = "版本号:V${rootProject.ext.android["versionName"]}\n" + "下载地址:${ 
     downloadUrl}\n" postAll(dingDingUrl, allTips, qrcodeUrl, downloadUrl) } //发送到群,@所有人 def postAll(url, tips, qrcodeUrl, downloadUrl) { 
    JsonBuilder builder = new JsonBuilder() builder { 
    msgtype 'link' link { 
    title '新版本发布提醒' text tips messageUrl downloadUrl picUrl qrcodeUrl } at { 
    isAtAll false //@所有人(只有text,markdown,actioncard这三种消息类型支持@功能) } } String data = JsonOutput.prettyPrint(builder.toString()) postDingDing(url, data) } //调用接口,发送消息 def postDingDing(urlString, msg) { 
    if (msg == null) { 
    return } HttpURLConnection conn = null OutputStream outputStream = null try { 
    if (conn == null) { 
    URL url = new URL(urlString) conn = (HttpURLConnection) url.openConnection() } if (conn != null) { 
    conn.setReadTimeout(15000) conn.setConnectTimeout(15000) conn.setDoOutput(true) conn.setUseCaches(false) conn.setRequestProperty("Content-Type", "application/json; charset=utf-8") } if (conn == null) { 
    return null } if (msg != null && msg.length() > 0) { 
    DataOutputStream dataOutputStream = new DataOutputStream(conn.getOutputStream()) byte[] t = msg.getBytes("utf-8") dataOutputStream.write(t) dataOutputStream.flush() dataOutputStream.close() int res = conn.getResponseCode() if (res == 200) { 
    //成功 InputStream input = conn.getInputStream() StringBuffer sb = new StringBuffer() int ss while ((ss = input.read()) != -1) { 
    sb.append((char) ss) } println "发送消息成功: ${ 
     sb.toString()}" } else { 
    println("发送消息失败: " + conn.getResponseCode()) } } } catch (EOFException e) { 
    e.printStackTrace() } catch (IOException e) { 
    e.printStackTrace() } finally { 
    if (outputStream != null) { 
    try { 
    outputStream.close() } catch (IOException e) { 
    e.printStackTrace() } } if (conn != null) { 
    conn.disconnect() } } } 

找到刚才新建的机器人并打开
在这里插入图片描述
复制Webhook地址可以看到accessToken字段。下面我们来把需要用的参数配置一下。
群组消息类型可以参考官方文档根据自己的需求调整下。代码中默认为link类型。

3、相关配置

打开根目录的build.gradle并填写一下代码:

ext { 
    android = [ versionCode: 1, versionName: "1.0.0.0" ] pgy = [ apiKey : "xxx", uploadUrl : "https://www.pgyer.com/apiv2/app/upload" ] dingding = [ accessToken: "xxx", ] } 

4、效果图:

在这里插入图片描述

5、SSL Bug修改

最近给电脑(windows)上装了OpenSSL,自动上传调用cur命令出现报错。

curl: (35) schannel: next InitializeSecurityContext failed: Unknown error (0x) 

问题原因:

windows版本的curl依靠WinSSL / WinTLS (也就是微软的 Secure Channel,见 https://msdn.microsoft.com/en-us/library/aa.aspx )来提供 https 支持,而Linux版本的curl依靠的是openssl 的版本,两者表现并不一致。

由于window本来内置了ssh,这次我又安装了OpenSSL猜测两者出现了冲突。

解决办法:

给curl添加--ssl-no-revoke参数,关闭证书吊销检查功能,修改后的curl上传代码如下:

private def uploadPGY(String filePath) { 
    def stdout = new ByteArrayOutputStream() exec { 
    executable = 'curl' args = ['--ssl-no-revoke','-F', "file=@${ 
     filePath}", '-F', "_api_key=${rootProject.ext.pgy["apiKey"]}", rootProject.ext.pgy["uploadUrl"]] standardOutput = stdout } String output = stdout.toString() def parsedJson = new groovy.json.JsonSlurper().parseText(output) println parsedJson.data.buildQRCodeURL println "蒲公英上传完成 版本号:" + parsedJson.data.buildVersion } 

6、钉钉消息@某人

官方文档:https://open.dingtalk.com/document/group/robot-message-type-staff-information-in-an-enterprise
支持钉钉消息@某人的消息格式有三种:textmarkdownactioncard。其中只有text会高亮,其他两种不会。

//发送到群,@所有人 def postAtSomeone(url, tips, qrcodeUrl, downloadUrl) { 
    //发送@某人消息 JsonBuilder atPersonBuilder = new JsonBuilder() atPersonBuilder { 
    msgtype 'text' text { 
    content "更新内容:\n${rootProject.ext.android["versionUpdateRemark"]}\n" + "@zfndm1v81" } at { 
    isAtAll false //@所有人 atDingtalkIds (["zfndm1v81"])//打开钉钉群,找到要@的人,复制他的钉钉号即可 //atMobiles (["135"]) } } String personData = JsonOutput.prettyPrint(atPersonBuilder.toString()) postDingDing(url, personData) } 

注意:
1、官方文档中@某人有两种方式,一是配置这个人的钉钉userid,另一个是配置这个人的手机号,前提要保证配置的userid或者手机号一定在这个群里,否则无效。
2、官方文档中的用户id的配置方式为atUserIds,经测试发现这个配置项无效,需改为atDingtalkIds 可能文档忘了更新吧。
3、在at中配置需要@人的信息之后,需要在发送的消息中加上@xx,否则@无效。

  • text消息:在content中拼接@xx
  • markdown消息|actionCard消息:在text中拼接@xx

4、atDingtalkIdsatMobiles 可以同时配置。
5、注意gradle中的数组配置方式([])。groovy的语法我也不是很懂,想详细了解的同学自行百度。

7、动态生成一键发布任务

/ * Sept 4 创建打包 Task * 遍历所有可执行的 variants 创建对应的打包 Task * 生成后的路径及名称:Tasks/build/pushApk[productFlavorsName][Release/Debug] * eg:Tasks/build/pushApkDevRelease */ android.applicationVariants.all { 
    variant -> String taskSuffix = variant.name.capitalize()//变种名称首字母大写 if (taskSuffix.contains("Release") || taskSuffix.contains("Debug")) { 
    task("pushApk${taskSuffix}") { 
    dependsOn ":app:assemble${taskSuffix}" group 'build' description 'Custom task for gradle' doLast { 
    variant.outputs.all { 
    output -> // 执行脚本任务 uploadPGY(output.outputFile.path) } } } } } 

8、build.gradle中一些参数设置和获取的方法总结

android.applicationVariants.all { 
    variant -> //variant.name: 获取变种名称 //variant.productFlavors[0].name: 获取渠道名称 //variant.mergedFlavor.versionName: 获取渠道版本名称,如1.0.1 //variant.mergedFlavor.versionCode: 获取渠道版本编号,如12 //variant.buildType.name: 构建类型名称,如Debug/Release } 

app build.gradle打包只关注当前打包渠道版本
android.applicationVariants.all 是一个Gradle插件的API,它在Android构建过程中的variant(构建类型和 product flavor 的组合)被创建时被调用。它会对所有的构建变体进行迭代。如果打包时只想关注某个特定版本需要自己添加逻辑判断;

//配置打包名称 android.applicationVariants.all { 
    variant -> //动态生成一键发布的任务 String taskSuffix = variant.name.capitalize() variant.outputs.all { 
   output-> // 检查是否正在执行assemble任务 def isAssembleTask = project.gradle.startParameter.taskNames.any { 
    taskName -> taskName.contains(taskSuffix); } if (isAssembleTask) { 
    // 判断当前正在执行的task // 这里写自定义逻辑 } } } 

app build.gradle中的一些配置信息获取

def appModule = project.rootProject.project(':app') def appVersionName = appModule.android.defaultConfig.versionName def appVersionCode = appModule.android.defaultConfig.versionCode 

获取当天提交日志

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() } 

动态设置根目录下build.gradle中的ext中的属性值:
rootProject.ext.apk["fileName"] = outputFileName

如果是数组的话,使用如下方法定义和传值:

//定义 gradleTask = [] //传值 rootProject.ext.gradleTask[index] = taskName 

在build.gradle中引用其他文件,如pyger.gradle中的方法uploadApk时,需要将该方法挂载到ext上,不挂载则找不到方法,代码如下:
ext.generateUploadApkTask = this.&generateUploadApkTask
由此可以改进上面的动态生成一键发布任务的代码,将任务的生成抽出到pyger.gradle中,完整代码如下:

//pyger.gradle def generateUploadApkTask(taskName) { 
    println "配置任务: uploadApk${taskName}" task("uploadApk${taskName}") { 
    dependsOn ":app:assemble${taskName}" group '一键发布APK' description '自定义任务,用于一键发布APK' doLast { 
    println "打包完成: ${apkFilePath}" println "开始上传蒲公英" uploadPGY(apkFilePath) } } } //导出该方法否则build.gradle中找不到 ext.generateUploadApkTask = this.&generateUploadApkTask //app/build.gradle android.applicationVariants.all { 
    variant -> //动态生成一键发布的任务 String taskSuffix = variant.name.capitalize() if (taskSuffix.contains("Release")) { 
    generateUploadApkTask(taskSuffix) } } 
今天的文章 Android——Gradle自动打包上传蒲公英并进行钉钉群提醒分享到此就结束了,感谢您的阅读。
编程小号
上一篇 2024-12-05 21:06
下一篇 2024-12-05 20:46

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/78520.html