本地部署iOS应用OTA安装 Go + Goland详细实现步骤
用一台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详细实现步骤相关推荐
- 在本地部署自己的漏洞文章武器库(详细步骤说明)
在本地部署自己的漏洞文章武器库 在平时我们进行web渗透的过程中,有些poc,CVE详细情况需要进行查询之后才能进行利用,对于初级渗透人员来说,对漏洞情况和利用方式掌握不足的情况下,打造属于自己的漏洞 ...
- inno setup安装制作软件详细使用步骤(含检测net版本环境)
一.下载inno setup软件(环境设置) 官方下载地址:https://jrsoftware.org/isinfo.php 我这里有个现成的inno setup下载包,可自提: 链接:https: ...
- vmware workstation pro15 安装win10系统详细无错步骤
1.准备Windows 10 x64.iso系统镜像文件,以及装机工具本文以装机助理为例,然后打开虚机机点击创建新的虚拟机 2. 3.这里选择稍后安装操作系统 4.根据要安装的系统选择响应的类型 5. ...
- window10下安装git的详细步骤
第一步:先从官网下载最新版本的Git 官网地址:https://git-scm.com/downloads 点击上图中表示的地方进行下载,得到Git-2.17.1.2-64-bit.exe文件.如果你 ...
- 本地部署Stable Diffusion教程,亲测可以安装成功
系列文章目录 Stable Diffusion界面参数及模型使用 谷歌Colab云端部署Stable Diffusion 进行绘图 文章目录 系列文章目录 前言 一.Stable Diffusion是 ...
- Cobbler部署指南之Cobbler安装操作系统篇
##################################################### ##如有转载,请务必保留本文链接及版权信息 ##欢迎广大运维同仁一起交流linux/unix ...
- django部署iiswin10_基于Windows平台的Django在本地部署和腾讯云服务器上部署的方法教程(一)...
环境: VS2015 IIS python3.6.1 django 1.11.14 打开VS2015,新建一个django项目. 这里注意一点:确保python的安装路径中没有中文,没有空格. 我的安 ...
- draw.io项目本地部署
最近想学习draw.io二次开发,而且这本来就是一个很有用的绘图工具,本地部署完成后,再也不用安装庞大的visio,也不用受制于processon了. 本文给出两种部署方法. 1. 使用本地的Inte ...
- VSTS2010部署一:TFS安装
VSTS2010部署一:TFS安装 说明: 费近三天多时间,经历很多煎熬,终于将TFS部署安装成功,在此将经验分享给大家.这段时间安装的过程中,参照了网上很多TFS部署安装的博客,但都是说的不是很全面 ...
- Exceptionless 本地部署
前两天看到了这篇文章免费开源分布式系统日志收集框架 Exceptionless,亲身体会了下,确实不错,按照官方的文档试了试本地部署,折腾一番后终于成功,记下心得在此,不敢独享. 本地部署官方wiki ...
最新文章
- 多传感器融合:自动驾驶(下)
- 企业级 SpringBoot 教程 (三)SpringBoot用JdbcTemplates访问Mysql
- HDU 4768 Flyer(二分法)
- CDH4.0安装及配置(二)配置网易yum源
- JSP简单练习-JSP指令
- LEGO EV3 中执行 VSCode Python 代码过程分析
- 最近重构公司消息服务的架构设计
- 封条格式用word怎么打_标书密封条格式全word.doc
- CVPR 2020 | 序列化的三维形状生成网络PQ-NET
- a标签无跳转的死链接
- 如何在前端中使用protobuf(vue篇)
- MySQL优化步骤和my.cnf优化配置
- 在php里怎么安装composer,怎么安装composer
- 张量分析初步和矢量恒等式
- Ghostscript的介绍和移植
- IT外包服务业各领域的未来前景和趋势
- Word插入参考文献
- AI视频增强,提高视频画面的清晰度
- 货币等额换算_换算单位和货币的最佳免费程序和网站
- 【实用技巧】知网文献不限量免费下载方法,亲测可用