用一台Mac Mini部署了Jenkins之后,打完包要下载到自己电脑用iTunes安装。

因此决定用Go在Mini 上也配置一个OTA在线安装环境

1. 下载安装Go

https://golang.org/dl/

默认安装路径在/usr/local/go,添加环境

vi ~/.bash_profile

添加内容  export PATH=$PATH:/usr/local/go/bin

source  ~/.bash_profile

2. 安装Goland

使用量并不大,使用Goland直接run

建一个工程文件夹GoProject,下面都在这个文件夹下

新建ota.go

菜单->run->edit configurations 添加go build

接下来参考https://blog.csdn.net/sydnash/article/details/54691878

3.自建https证书

新建文件夹myssl

cd myssl
sudo openssl genrsa -out server.key 1024
sudo openssl req -new -key server.key -out server.csr //填写信息时Common Name为本机ip地址,服务器有域名使用域名
sudo openssl genrsa -out ca.key 1024
sudo openssl req -new -x509 -days 365 -key ca.key -out ca.crt

在myssl中新建文件夹demoCA

在demoCA新建文件夹newcerts,新建文件index.txt和serial,serial添加文本内容:01

生成ca文件

sudo openssl ca -in server.csr -out server.crt -cert ca.crt -keyfile ca.key 

如果出现错误

Using configuration from /private/etc/ssl/openssl.cnf

variable lookup failed for ca::default_ca

首先确保安装 openssl。安装: brew install openssl
拷贝文件
sudo cp /usr/local/etc/openssl/openssl.cnf /private/etc/ssl/openssl.cnf

生成证书后,在GoProject中新建文件夹ssl,将ca.crt拷贝一份过来

4. OTA现在必须使用https

固定链接格式读取plist安装

链接:itms-services://?action=download-manifest&url=https://xxx/xxx.plist

Jenkins打包后没有提供ota的plist文件 需要靠自己创建

在GoProject中新建文件夹OtaInstall,用于保存创建的plist文件。同时存放57*57和512*512两张应用icon图片

plist内容

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict><key>items</key><array><dict><key>assets</key><array><dict><key>kind</key><string>software-package</string><key>url</key><string>https://xxx/xxx.ipa</string></dict><dict><key>kind</key><string>display-image</string><key>url</key><string>https://xxx/57*57.png</string></dict><dict><key>kind</key><string>full-size-image</string><key>url</key><string>https://xxx/512*512.png</string></dict></array><key>metadata</key><dict><key>bundle-identifier</key><string>应用buildle-id</string><key>bundle-version</key><string>版本号</string><key>kind</key><string>software</string><key>title</key><string>应用名</string></dict></dict></array>
</dict>
</plist>

5. Go实现

package mainimport ("bufio""fmt""io""io/ioutil""log""net/http""os""strings"
)var installTemplate = `
<!DOCTYPE html>
<html>
<head lang="en"><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, minimum-scale=1, user-scalable=no"><meta content="telephone=no" name="format-detection"/><title>应用名-在线安装</title>
</head>
<style>html {width: 100%;height: 100%}body {background-color: #fafafa;font-family: "Microsoft YaHei";color: #0a0909;-webkit-touch-callout: none;-webkit-user-select: none;margin-right:auto;margin-left:auto;text-align:center;}div, p, header, footer, h1, h2, h3, h4, h5, h6, span, i, b, em, ul, li, dl, dt, dd, body, input, select, form, button {margin: 0;padding: 0}ul, li {list-style: none}img {border: 0 none}input, img {vertical-align: middle}* {-webkit-tap-highlight-color: rgba(0, 0, 0, 0);outline: 0;box-sizing: border-box;}a {text-align:center;margin-right:auto;margin-left:auto;}h1, h2, h3, h4, h5, h6 {font-weight: normal;}.title {font-size: 18px;margin-bottom: 20px;}.install {width: 300px;height: 40px;border: 1px solid #ccc;background: transparent;border-radius: 6px;font-size: 14px;margin-bottom: 10px;display: block;margin-right:auto;margin-left:auto;}
</style>
<body>
</br></br></br><p class="title">iOS应用OTA安装</p></br></br><a title="iPhone" href="http://ip:1717/static/ca.crt"><button class="install">证书信任</button></a>
</br></br><a href="https://ip:1718/ipalist"><button class="install">打包列表</button></a>
</body>
</html>
`var ipalistHtml  =  `<!DOCTYPE html><html><head lang="en"><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, minimum-scale=1, user-scalable=no"><meta content="telephone=no" name="format-detection"/><title>应用名-打包列表</title></head><style>html {width: 100%;height: 100%}body {width: 100%;height: 100%;background-color: #fafafa;font-family: "Microsoft YaHei";color: #0a0909;-webkit-touch-callout: none;-webkit-user-select: none;}</style><body></br></br></br>
`func main() {///安装页和列表页,两个静态页面http.Handle("/install/", http.HandlerFunc(install))http.Handle("/ipalist/", http.HandlerFunc(ipalist))///静态文件服务///将ca证书文件夹开放提供下载 设置安装后 需要在设备 设置-关于本机-证书信任,信任证书http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./ssl"))))///开放打包存放路径http.Handle("/ota/", http.StripPrefix("/ota/", http.FileServer(http.Dir("/xxx/Package"))))///开放存放ota plist文件夹http.Handle("/otainstall/", http.StripPrefix("/otainstall/", http.FileServer(http.Dir("./OtaInstall"))))///监听1717端口 提供http服务 用于证书安装go func() {http.ListenAndServe(":1717", nil)}()///使用之前自建的证书,监听1718端口 提供https服务 用于应用安装 err := http.ListenAndServeTLS(":1718", "./myssl/server.crt", "./myssl/server.key", nil)if err != nil {log.Fatal("ListenAndServe:", err)}
}///install 页面 证书信任 包列表
func install(w http.ResponseWriter, req *http.Request) {fmt.Fprint(w, installTemplate)
}///包列表 从Jenkins打包保存路径读取所有打包文件夹
func ipalist(w http.ResponseWriter, req *http.Request)  {dir_list, e := ioutil.ReadDir("/xxx/Package")if e != nil {fmt.Fprintf(w, "get ipa list error:%s", e.Error())return}///文件列表倒序dir_list = reverse(dir_list)var html  string = ipalistHtmlfor _, f := range dir_list {///不是文件夹过滤掉if f.IsDir() == false {continue}var name string = f.Name()subList, _ := ioutil.ReadDir("/xxx/Package/" + name)///如果文件夹里没有子文件 则忽略(这里只是粗略的过滤,过滤掉空文件夹)if len(subList) == 0 {continue}///从.xcarchive文件里读取info.plist获取version和buildvar version, build  = getIPAVersionWithFileName(name)///如果没有ota在线安装的plist配置文件则创建一个createOTAPlistIfNeededWithFileName(name)///作为一个a标签拼接到htmlvar a = "<div style=\"text-align:center;\"><a" + " href=\"itms-services://?action=download-manifest&url=https://ip:1718/otainstall/"+ name + ".plist\" >"  + name + "   [" + version + "]" + "[build " + build + "]" +  "</a></div> </br>"html += a}html += "</body></html>"///显示html静态页面fmt.Fprintf(w, html)
}///将文件列表倒序
func reverse(s [] os.FileInfo) []os.FileInfo {for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {s[i], s[j] = s[j], s[i]}return s
}///判断是否已经有ota安装plist文件,如果没有创建则创建并写入内容
func createOTAPlistIfNeededWithFileName(filename string)  {var path = "./OtaInstall/" + filename + ".plist"exist, err := pathExists(path)if err != nil {return}if exist {return}var version,_  = getIPAVersionWithFileName(filename)///拼接plist内容var content = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict><key>items</key><array><dict><key>assets</key><array><dict><key>kind</key><string>software-package</string><key>url</key><string>https://ip:1718/ota/`+ filename + "/" + filename + `.ipa</string></dict><dict><key>kind</key><string>display-image</string><key>url</key><string>https://ip:1718/otainstall/icon57.png</string></dict><dict><key>kind</key><string>full-size-image</string><key>url</key><string>https://ip:1718/otainstall/icon512.png</string></dict></array><key>metadata</key><dict><key>bundle-identifier</key><string>com.xxx.xxx</string><key>bundle-version</key><string>` + version + `</string><key>kind</key><string>software</string><key>title</key><string>应用名</string></dict></dict></array>
</dict>
</plist>`f, err := os.Create(path) //创建文件if err != nil{return}///写入文件io.WriteString(f,content)
}///读取包version和build
///内容比较简单,用比较笨的办法做的
///一行一行读取 找到<key>CFBundleShortVersionString</key>和<key>CFBundleVersion</key>
func getIPAVersionWithFileName(filename string)(v string, build string){var path = "/xxx/Package/" + filename + "/xxx.xcarchive/Info.plist"fi, err := os.Open(path)if err != nil {fmt.Printf("Error: %s\n", err)return "1.0.0","1"}defer fi.Close()br := bufio.NewReader(fi)var version string = "1.0.0"var buildNum string = "1"for {a, _, c := br.ReadLine()if c == io.EOF {break}var text = string(a)if strings.Contains(text, "<key>CFBundleShortVersionString</key>") {a, _, _ := br.ReadLine()text = string(a)var sub string = strings.Split(text,"<string>")[1]version = strings.Split(sub, "</string>")[0]}if strings.Contains(text, "<key>CFBundleVersion</key>") {a, _, _ := br.ReadLine()text = string(a)var sub string = strings.Split(text,"<string>")[1]buildNum = strings.Split(sub, "</string>")[0]}}return version, buildNum
}///判断文件或者文件夹是否存在
func pathExists(path string) (bool, error) {_, err := os.Stat(path)if err == nil {return true, nil}if os.IsNotExist(err) {return false, nil}return false, err
}

运行后,在同一局域网络下就可以使用了

Jenkins打包后刷新列表页,第一次因为写plist文件比较慢一点,然后就可以选择安装了

代码耦合的,路径写在代码里,自行解耦合

本地部署iOS应用OTA安装 Go + Goland详细实现步骤相关推荐

  1. 在本地部署自己的漏洞文章武器库(详细步骤说明)

    在本地部署自己的漏洞文章武器库 在平时我们进行web渗透的过程中,有些poc,CVE详细情况需要进行查询之后才能进行利用,对于初级渗透人员来说,对漏洞情况和利用方式掌握不足的情况下,打造属于自己的漏洞 ...

  2. inno setup安装制作软件详细使用步骤(含检测net版本环境)

    一.下载inno setup软件(环境设置) 官方下载地址:https://jrsoftware.org/isinfo.php 我这里有个现成的inno setup下载包,可自提: 链接:https: ...

  3. vmware workstation pro15 安装win10系统详细无错步骤

    1.准备Windows 10 x64.iso系统镜像文件,以及装机工具本文以装机助理为例,然后打开虚机机点击创建新的虚拟机 2. 3.这里选择稍后安装操作系统 4.根据要安装的系统选择响应的类型 5. ...

  4. window10下安装git的详细步骤

    第一步:先从官网下载最新版本的Git 官网地址:https://git-scm.com/downloads 点击上图中表示的地方进行下载,得到Git-2.17.1.2-64-bit.exe文件.如果你 ...

  5. 本地部署Stable Diffusion教程,亲测可以安装成功

    系列文章目录 Stable Diffusion界面参数及模型使用 谷歌Colab云端部署Stable Diffusion 进行绘图 文章目录 系列文章目录 前言 一.Stable Diffusion是 ...

  6. Cobbler部署指南之Cobbler安装操作系统篇

    ##################################################### ##如有转载,请务必保留本文链接及版权信息 ##欢迎广大运维同仁一起交流linux/unix ...

  7. django部署iiswin10_基于Windows平台的Django在本地部署和腾讯云服务器上部署的方法教程(一)...

    环境: VS2015 IIS python3.6.1 django 1.11.14 打开VS2015,新建一个django项目. 这里注意一点:确保python的安装路径中没有中文,没有空格. 我的安 ...

  8. draw.io项目本地部署

    最近想学习draw.io二次开发,而且这本来就是一个很有用的绘图工具,本地部署完成后,再也不用安装庞大的visio,也不用受制于processon了. 本文给出两种部署方法. 1. 使用本地的Inte ...

  9. VSTS2010部署一:TFS安装

    VSTS2010部署一:TFS安装 说明: 费近三天多时间,经历很多煎熬,终于将TFS部署安装成功,在此将经验分享给大家.这段时间安装的过程中,参照了网上很多TFS部署安装的博客,但都是说的不是很全面 ...

  10. Exceptionless 本地部署

    前两天看到了这篇文章免费开源分布式系统日志收集框架 Exceptionless,亲身体会了下,确实不错,按照官方的文档试了试本地部署,折腾一番后终于成功,记下心得在此,不敢独享. 本地部署官方wiki ...

最新文章

  1. 多传感器融合:自动驾驶(下)
  2. 企业级 SpringBoot 教程 (三)SpringBoot用JdbcTemplates访问Mysql
  3. HDU 4768 Flyer(二分法)
  4. CDH4.0安装及配置(二)配置网易yum源
  5. JSP简单练习-JSP指令
  6. LEGO EV3 中执行 VSCode Python 代码过程分析
  7. 最近重构公司消息服务的架构设计
  8. 封条格式用word怎么打_标书密封条格式全word.doc
  9. CVPR 2020 | 序列化的三维形状生成网络PQ-NET
  10. a标签无跳转的死链接
  11. 如何在前端中使用protobuf(vue篇)
  12. MySQL优化步骤和my.cnf优化配置
  13. 在php里怎么安装composer,怎么安装composer
  14. 张量分析初步和矢量恒等式
  15. Ghostscript的介绍和移植
  16. IT外包服务业各领域的未来前景和趋势
  17. Word插入参考文献
  18. AI视频增强,提高视频画面的清晰度
  19. 货币等额换算_换算单位和货币的最佳免费程序和网站
  20. 【实用技巧】知网文献不限量免费下载方法,亲测可用

热门文章

  1. supp(),支持集理解
  2. 自媒体账号如何注册申请
  3. 广度优先遍历搜索的最通俗介绍,如何实现广度优先搜索算法?广度优先遍历搜索可用于哪些行业?
  4. linux下使用LVM合并挂载硬盘以及扩容
  5. 《有效的单元测试》第三章
  6. Oracle SYSAUX 表空间 说明
  7. 5款最好的安卓界面设计工具推荐
  8. 国内智能手机市场寒风凛冽,华米OV谁更受伤?
  9. windows10下使用mencoder将y4m文件转换为YUV文件
  10. 国内外汽车道路行驶工况数据