首页 > 技术 > 机器人

jenkins随时执行和取消任务丨jenkins 计划任务

人阅读 2023-07-09 18:40:10

【jenkins随时执行和取消任务丨jenkins 计划任务】lot物联网小编为你整理了的相关内容,希望能为你解答。

1. 介绍

主要介绍自由风格模式下,我们如何通过Jenkins实现一键编译,然后将编译后的app自动推送到蒲公英,然后将蒲公英相关信息,转到钉钉群里面告知相关更新信息。

1.1 准备

我们要提前准备以下内容:

安装 Groovy Post 插件。(可以通过jenkins插件市场进行搜索)安装 Upload to pgyer插件。(可以通过jenkins插件市场进行搜索)蒲公英账户,并得到APIKey 。(可以通过 后台页面头像点击,弹出的菜单中,选择API信息。可以看到我们的APIKey)钉钉机器人的webhook 和加密Sgin信息。(只有钉钉群才能创建机器人。配置一个普通机器人就可以了)(我们也可以下载DingTalk 插件)

相关插件在Jenkis上的地址:

https://plugins.jenkins.io/dingding-notifications/ 2.4.10版本

https://plugins.jenkins.io/upload-pgyer/ v2.1 版本

https://plugins.jenkins.io/groovy-postbuild/ v 2.5版本

如何安装Jenkins 插件,这里就不做介绍了。系统设置里面的插件功能。

但是这里有一个注意点,我们如果是安装的DingTalk插件,来实现推送到钉钉。那么安装完毕插件之后,一定要记得重启Jenkins服务器。

否则你的钉钉插件,只有在系统设置里面进行测试的时候,可以发送消息。而在具体的工作构建过程中,完全不会发送任何消息。

我们需要通过重启,才能让该插件在工作流中使用哦。否则无法正确的调用。

以下内容都基于jenkins 2.X系统。

2. 上传APK到蒲公英

jenkins 自动配置APk的过程,我就不展开进行介绍了。

当我们一切就绪,jenkins自动构造的apk已经生成了可参考:https://zinyan.com/?p=199

当我们执行打包编译完成后,(可以不进行归档成品。)在构建后操作模块中: 增加构建后操作步骤中选择:

Upload to pgyer with apiV2

注意: 如果你的插件比较老,可能还有 Upload to pgyer with apiV1 等。(建议升级。老版本接口会封)

老版本的apiV2 使用的上传http://www.pgyer.com/apiv2/app/upload 也即将废弃。

最新的上传接口:http://www.pgyer.com/apiv2/app/getCOSToken (速度很快)

那么在 Upload to pgyer with apiV2的面板中配置:

pgyer api_key: 蒲公英的 api_key (必填)。https://www.pgyer.com/account/api 可以查询你自己的蒲公英API Key,是一串32位字符串。例如:7s016c61234ec35239247e5c3ac24a19。scandir:apk 所在目录 (必填) (如果是ios 那么就是ipa的所在目录)。通常是固定的例如:${WORKSPACE}/app/build/outputs/apk/release/我们如果有不同的渠道包,那么可以将apk替换为变量。file wildcard :上传文件的通配符 (必填)。新的2.1版本插件需要配置成:**/*.apkbuildType:上传的应用程序类型,(接口注释上写的选填,蒲公英上官网介绍说是必填。)填写:android 就可以了。如果是ios就写ios。buildInstallType:上传的应用安装方式(选填),值为(1,2,3)默认值为1。1: 公开安装 2:密码安装,3:邀请安装。buildPassword:应用安装密码(选填),我们只有buildInstallType设置为密码安装的时候,就需要配置该参数。其他情况可以不用配置。buildUpdateDescription:更新内容(选填),我们上传到蒲公英的时候,填写的应用更新日志。可以通过Jenkins全局变量将git日志,或者我们每次编译自己填写的日志赋值到这里来实现。访问全局变量的方式为:${变量名称}。buildChannelShortcut:构建指定的下载短链接(选填),例如我们想更新到指定短链(你原先已经有了该短链的项目了。),那么就将该短链写上来。那么这两个apk即使不一致,也会将新的apk上传到这个项目中去。2.1.1 老版本蒲公英插件

如果我们的 Upload to pgyer 插件属于v1.34 等版本。

那么在file wildcard 中可以配置为:*.apk。

之后,构建成功上传到蒲公英上时会输出:

************************************************************************************************************************************************************************************************************************************ UPLOAD TO PGYER **************************************************************** https://www.pgyer.com ************************************************************************************************************************************************************************************************************************************[UPLOAD TO PGYER] - upload:app-release.apk to https://www.pgyer.com/apiv2/app/upload[UPLOAD TO PGYER] - upload file size: 47.9 MB[UPLOAD TO PGYER] - upload progress: 0 %[UPLOAD TO PGYER] - upload progress: 0 %[UPLOAD TO PGYER] - upload progress: 3 %[UPLOAD TO PGYER] - upload progress: 6 %[UPLOAD TO PGYER] - upload progress: 9 %[UPLOAD TO PGYER] - upload progress: 11 %[UPLOAD TO PGYER] - upload progress: 14 %[UPLOAD TO PGYER] - upload progress: 17 %[UPLOAD TO PGYER] - upload progress: 20 %[UPLOAD TO PGYER] - upload progress: 23 %[UPLOAD TO PGYER] - upload progress: 26 %[UPLOAD TO PGYER] - upload progress: 28 %[UPLOAD TO PGYER] - upload progress: 31 %[UPLOAD TO PGYER] - upload progress: 34 %[UPLOAD TO PGYER] - upload progress: 37 %[UPLOAD TO PGYER] - upload progress: 40 %[UPLOAD TO PGYER] - upload progress: 43 %[UPLOAD TO PGYER] - upload progress: 46 %[UPLOAD TO PGYER] - upload progress: 49 %[UPLOAD TO PGYER] - upload progress: 52 %[UPLOAD TO PGYER] - upload progress: 54 %[UPLOAD TO PGYER] - upload progress: 57 %[UPLOAD TO PGYER] - upload progress: 60 %[UPLOAD TO PGYER] - upload progress: 63 %[UPLOAD TO PGYER] - upload progress: 67 %[UPLOAD TO PGYER] - upload progress: 70 %[UPLOAD TO PGYER] - upload progress: 72 %[UPLOAD TO PGYER] - upload progress: 75 %[UPLOAD TO PGYER] - upload progress: 78 %[UPLOAD TO PGYER] - upload progress: 81 %[UPLOAD TO PGYER] - upload progress: 84 %[UPLOAD TO PGYER] - upload progress: 87 %[UPLOAD TO PGYER] - upload progress: 90 %[UPLOAD TO PGYER] - upload progress: 93 %[UPLOAD TO PGYER] - upload progress: 96 %[UPLOAD TO PGYER] - upload progress: 99 %[UPLOAD TO PGYER] - upload progress: 100 %[UPLOAD TO PGYER] - Uploaded successfully![UPLOAD TO PGYER] - 应用名称:[你的App的名称][UPLOAD TO PGYER] - 应用类型:2[UPLOAD TO PGYER] - 版本号:1.0[UPLOAD TO PGYER] - build号:24[UPLOAD TO PGYER] - Build Key:219e5f3915fe71648b1d1c9b1245bf25[UPLOAD TO PGYER] - 版本编号:1[UPLOAD TO PGYER] - 文件大小:50229239[UPLOAD TO PGYER] - 应用介绍:[UPLOAD TO PGYER] - 应用主页:https://www.pgyer.com/ZINY[UPLOAD TO PGYER] - 应用短链接:30GE[UPLOAD TO PGYER] - 应用上传时间:2022-10-28 15:32:12[UPLOAD TO PGYER] - 应用更新时间:2022-10-28 15:32:12[UPLOAD TO PGYER] - 应用构建主页:https://www.pgyer.com/219e5f3915fe71648b1d1c9b1245bf25[UPLOAD TO PGYER] - 应用更新说明:[UPLOAD TO PGYER] - 是否是最新版:1[UPLOAD TO PGYER] - 应用程序包名:com.zinyan.demo[UPLOAD TO PGYER] - 应用截图的key:[UPLOAD TO PGYER] - 应用二维码地址:https://www.pgyer.com/app/qrcodeHistory/302ce905e75e78cf8336f2fe2302ce905e75e78cf8336f2fe2302ce905e75e78cf8336f2fe[UPLOAD TO PGYER] - 是否是第一个App:2[UPLOAD TO PGYER] - 应用的Icon图标key:https://www.pgyer.com/image/view/app_icons/18a924628542d3329c67aefa0d08e776[UPLOAD TO PGYER] - The Jenkins environment variable is being set.[UPLOAD TO PGYER] - The ${buildKey} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildType} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildIsFirst} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildIsLastest} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildFileKey} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildFileName} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildFileSize} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildName} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildVersion} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildVersionNo} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildBuildVersion} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildIdentifier} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildIcon} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildDescription} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildUpdateDescription} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildScreenshots} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildShortcutUrl} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildCreated} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildUpdated} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildQRCodeURL} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${appQRCodeURL} set up successfully! You can use it anywhere now.![UPLOAD TO PGYER] - The ${appPgyerURL} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${appBuildURL} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - congratulations!

我们会发现,老插件使用的https://www.pgyer.com/apiv2/app/upload 接口地址,而该接口地址在蒲公英官方介绍中,即将被删除。

同时速度也比较慢。

后面的输出内容:The ${buildKey} set up successfully! You can use it anywhere now! 等等。

都是蒲公英在将插件返回得到的数据,设置为全局变量。我们可以通过${名称}进行获取相关的配置值哦

在下面,有详细介绍返回的各种参数的信息。

2.1.2 新版 2.1 插件

新版和老版本的插件区别并不大,就是file widcard 的参数值调整为:**/*.apk 就可以了。

我们如果通过新版接口上传日志输入效果:

************************************************************************************************************************************************************************************************************************************ UPLOAD TO PGYER **************************************************************** https://www.pgyer.com ************************************************************************************************************************************************************************************************************************************[UPLOAD TO PGYER] - upload:getToken to https://www.pgyer.com/apiv2/app/getCOSToken[UPLOAD TO PGYER] - upload:app-release.apk to Pgyer[UPLOAD TO PGYER] - upload file size: 47.9 MB[UPLOAD TO PGYER] - upload progress: 0 %[UPLOAD TO PGYER] - upload progress: 59 %[UPLOAD TO PGYER] - upload progress: 100 %[UPLOAD TO PGYER] - upload:Wait for the PGYER synchronization result[UPLOAD TO PGYER] - upload:Pgyer is synchronizing data……[UPLOAD TO PGYER] - upload:Pgyer is synchronizing data……[UPLOAD TO PGYER] - upload:Pgyer is synchronizing data……[UPLOAD TO PGYER] - Uploaded successfully![UPLOAD TO PGYER] - 应用名称:[你的App的名称][UPLOAD TO PGYER] - 应用类型:2[UPLOAD TO PGYER] - 版本号:1.0[UPLOAD TO PGYER] - build号:25[UPLOAD TO PGYER] - Build Key:219e5f3915fe71648b1d1c9b1245bf25[UPLOAD TO PGYER] - 版本编号:1[UPLOAD TO PGYER] - 文件大小:50229239[UPLOAD TO PGYER] - 应用介绍:[UPLOAD TO PGYER] - 应用主页:https://www.pgyer.com/ZINY[UPLOAD TO PGYER] - 应用短链接:30GE[UPLOAD TO PGYER] - 应用上传时间:2022-10-29 10:16:23[UPLOAD TO PGYER] - 应用更新时间:2022-10-29 10:16:23[UPLOAD TO PGYER] - 应用构建主页:https://www.pgyer.com/219e5f3915fe71648b1d1c9b1245bf25[UPLOAD TO PGYER] - 应用更新说明:蒲公英上传插件修改,使用getCosToken[UPLOAD TO PGYER] - 是否是最新版:1[UPLOAD TO PGYER] - 应用程序包名:com.dasoundgen.identification[UPLOAD TO PGYER] - 应用截图的key:[UPLOAD TO PGYER] - 应用二维码地址:https://www.pgyer.com/app/qrcodeHistory/302ce905e75e78cf8336f2fe2302ce905e75e78cf8336f2fe2302ce905e75e78cf8336f2fe[UPLOAD TO PGYER] - 是否是第一个App:2[UPLOAD TO PGYER] - 应用的Icon图标key:https://www.pgyer.com/image/view/app_icons/18a924628542d3329c67aefa0d08e776[UPLOAD TO PGYER] - The Jenkins environment variable is being set.[UPLOAD TO PGYER] - The ${buildKey} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildType} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildIsFirst} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildIsLastest} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildFileKey} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildFileName} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildFileSize} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildName} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildVersion} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildVersionNo} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildBuildVersion} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildIdentifier} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildIcon} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildDescription} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildUpdateDescription} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildScreenshots} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildShortcutUrl} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildCreated} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildUpdated} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${buildQRCodeURL} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${appQRCodeURL} set up successfully! You can use it anywhere now.![UPLOAD TO PGYER] - The ${appPgyerURL} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - The ${appBuildURL} set up successfully! You can use it anywhere now![UPLOAD TO PGYER] - congratulations!

上述的蒲公英返回的链接地址和返回参数都进行过脱敏处理,大家不用尝试哦。

我们可以发现,两个接口在速度方面天差地别。建议大家尽快升级到新的接口中来。老版本接口也即将被蒲公英废弃哦。

如果应用发布成功,返回的参数列表为:

参数

类型

说明

buildKey

String

Build Key是唯一标识应用的索引ID

buildType

Integer

应用类型(1:iOS; 2:Android)

buildIsFirst

Integer

是否是第一个App(1:是; 2:否)

buildIsLastest

Integer

是否是最新版(1:是; 2:否)

buildFileSize

Integer

App 文件大小

buildName

String

应用名称

buildVersion

String

版本号, 默认为1.0 (是应用向用户宣传时候用到的标识,例如:1.1、8.2.1等。)

buildVersionNo

String

上传包的版本编号,默认为1 (即编译的版本号,一般来说,编译一次会变动一次这个版本号, 在 Android 上叫 Version Code。对于 iOS 来说,是字符串类型;对于 Android 来说是一个整数。例如:1001,28等。)

buildBuildVersion

Integer

蒲公英生成的用于区分历史版本的build号

buildIdentifier

String

应用程序包名,iOS为BundleId,Android为包名

buildIcon

String

应用的Icon图标key,访问地址为 https://www.pgyer.com/image/view/app_icons/[应用的Icon图标key]

buildDescription

String

应用介绍

buildUpdateDescription

String

应用更新说明

buildScreenShots

String

应用截图的key,获取地址为 https://www.pgyer.com/image/view/app_screenshots/[应用截图的key]

buildShortcutUrl

String

应用短链接

buildQRCodeURL

String

应用二维码地址

buildCreated

String

应用上传时间

buildUpdated

String

应用更新时间

而这些返回参数,被蒲公英插件给设置为全局环境变量了。在其他地方可以通过${变量名}进行访问操作。

3 发送到钉钉群

我们有两种方式,可以将得到的结果,发送到钉钉通知群中,一种是采用groovy脚本。写一个接口调用的过程。

还有一种是使用DingTalk 插件。(其实也是作者封装了一个groovy脚本而已。)

两种方法各有千秋。通过groovy脚本比较简单和清晰而已。

执行发送的前提,需要我们在钉钉群里面创建了一个自定义机器人。创建方式可以参考;https://open.dingtalk.com/document/robots/custom-robot-access 了解哦。

3.1 groovy脚本发送

我们如果通过Groovy脚本发送,那需要安装插件:groovy postbuild

然后在 构建后操作中选择: Groovy Postbuild。在打开的Groovy Script面板中输入:

import javax.crypto.Macimport javax.crypto.spec.SecretKeySpec//构建结果 - 这个是jenkins 默认就有的全局属性def buildResult = manager.getResult()//构建用户 - 这个是jenkins 默认就有的全局属性def buildUser= manager.getEnvVariable("BUILD_USER")//项目名称 - 这个是jenkins 默认就有的全局属性def jobName= manager.getEnvVariable("JOB_NAME")//构建结果页面- 这个是jenkins 默认就有的全局属性def buildUrl= manager.getEnvVariable("BUILD_URL")//GIT分支-这个是jenkins 默认就有的全局属性def gitBranch = manager.getEnvVariable("GIT_BRANCH")def DingTalkWebHook="可以配置我们自己的钉钉机器人的WebHook地址"def DingTalkSecret="配置我们自己的钉钉机器人的群加签值"if(buildResult == "SUCCESS"){ //将蒲公英上传得到的数据进行封装成mk文件,让钉钉进行发送 apkDownloadUrl = "https://www.pgyer.com/" manager.getEnvVariable("buildShortcutUrl") //apk下载地址 apkQrCode = manager.getEnvVariable("buildQRCodeURL")//apk二维码 apkbuildIdentifier = manager.getEnvVariable("buildIdentifier")//apk应用程序包 apkbuildVersion = manager.getEnvVariable("buildVersion")//apk 版本号 apkbuildVersionNo= manager.getEnvVariable("buildVersionNo") //构建日期 apkbuildCreateTime = manager.getEnvVariable("buildCreated") //更新日志 apkbuildUpdateDescription = manager.getEnvVariable("buildUpdateDescription") dingdingTask("Zinyan自动构建工具","## [ZinyanApp] 构建成功" "nn**下载地址:**" apkDownloadUrl "nn**构建日期:**" apkbuildCreateTime "nn**构建用户:**" buildUser "nn**应用程序包:**" apkbuildIdentifier "nn**应用版本号:**" apkbuildVersion "nn**应用版本编号:**" apkbuildVersionNo "nn**更新内容:**" apkbuildUpdateDescription "nn**查看详情:**[项目地址](" buildUrl ")" "nn![扫码下载](" apkQrCode ")" ,DingTalkWebHook,DingTalkSecret) }else{ dingdingTask("Zinyan自动构建工具","## [ZinyanApp] 构建失败n分支:" gitBranch "nn" " " " nn[查看失败详情](" buildUrl ")",DingTalkWebHook,DingTalkSecret)}//发送钉钉任务 ,第一个为钉钉消息,第二个参数为 消息内容主体 def dingdingTask(mk_title,mk_test,webhook,secret){ def json = new groovy.json.JsonBuilder() json{ msgtype "markdown" markdown { title mk_title text mk_test } at { atMobiles([]) isAtAll false } } //消息准备完毕,执行发送请求 manager.listener.logger.println("钉钉内容:" json) def timestamp =System.currentTimeMillis() //得到系统时间 def sign = getSign(timestamp,secret) def url =webhook "&sign=" sign "×tamp=" timestamp manager.listener.logger.println("钉钉请求参数:" url ) def connection = new URL(url).openConnection() connection.setRequestMethod('POST') connection.doOutput = true connection.setRequestProperty('Content-Type', 'application/json') def writer = new OutputStreamWriter(connection.outputStream) writer.write(json.toString()) writer.flush() writer.close() connection.connect() def respText = connection.content.text manager.listener.logger.println("钉钉服务器返回结果:" respText ) } def getSign(timestamp,secret){ def stringToSign = timestamp "n" secret Mac mac = Mac.getInstance("HmacSHA256") mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256")) byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8")) return URLEncoder.encode(new String(Base64.encoder.encode(signData)),"UTF-8") }

执行构建后,就会在输出日志中,打印钉钉的发送内容和钉钉的接口回调内容哦

我在上面的事例中使用的markdown类型。发送的消息样式类似于下面这种。

3.2 DingTalk 插件

使用插件就比较简单了。当我们安装插件完毕后,在系统管理界面滑动到最后,你就会发现一个未分类的项目 : 钉钉。效果图如下:

然后,我们在钉钉全局配置中,通知时机,可以全选,后面的具体任务通知,可以再重新配置哦。

建议勾选日志模块的详细日志功能。这样我们能够看到插件的使用日志。

代理面板中参数不用修改,保持默认的DIRECT代理类型就可以了。(如果有代理服务需求,那根据时机进行修改即可)。

然后就是添加机器人:

id值,可以默认不进行填写。(但是如果我们通过pipeline 进行主动调用,那么建议配置一个id,手写需要确保唯一性。不手写,插件会自动生成一个)。

名称:随便写,可以写中文。建议写机器人通知的钉钉群名称。我们在具体调用的时候,只会显示机器人名称。

webhook :从钉钉群里面获取

安全设置中的关键字,加密(就是加签参数值)。

配置完毕后,点击右下角的测试,可以进行验证信息配置是否正确,如果正确将会给指定钉钉群发送一个测试消息哦。

后面的使用就很简单了。

在General面板中,勾选你要通知的机器人

然后打开高级设置。

勾选要通知的时机,通知人(没有具体的,就勾选atAll就可以了。)

然后在自定义内容中,填写文本信息了。该文本信息需要使用markdown 格式填写哦。

(PS:插件的使用,比较简单,唯一需要注意的就是安装完毕插件之后记得重启jenkins。然后后面的配置插件有各种介绍)

如果想了解插件的使用,可以看插件的官方文档。介绍的比我详细哦。

参考链接

蒲公英文档中心-API 2.0 接口说明

蒲公英文档中心-Jenkins插件使用

jenkins-DingTalk插件官方使用说明

钉钉开放平台-自定义机器人接口

钉钉开放平台-自定义机器人安全设置

以上内容为【jenkins随时执行和取消任务丨jenkins 计划任务】的相关内容,更多相关内容关注lot物联网。

LOT物联网

iot产品 iot技术 iot应用 iot工程

Powered By LOT物联网  闽ICP备2024036174号-1

联系邮箱:support1012@126.com