Jenkins+Nginx+Python搭建iOS打包下载平台

前言:
Jenkins自动打包针对提交测试不需要每次都手动真机打包或者导包耗时, 可以节省很多时间, 提高开发的效率
本解决方案还有很多优化空间, 比如html的样式、html显示的信息、build版本等等
测试人员只需要在手机连内网WiFi,并到对应网址即可下载对应的包进行测试
搭建主要思路:

  1. 通过Jenkins自动打包功能,使用轮询机制判断分支上是否有修改记录,从而进行打包操作
  2. 打包完成后主要文件有3个:ipa包、plist文件、打包信息文本environment.txt
  3. 使用python bs4脚本对html文件进行修改
  4. 使用nginx搭建html访问和ipa包下载功能

开始搭建

1. 安装Jenkins

  • 使用homeBrew安装
# jenkins常用命令
brew install jenkins # 安装jenkins
brew services start jenkins  # 启动jenkins
brew services restart jenkins  # 重新启动jenkins
brew upgrade jenkins  # 更新jenkins
brew services stop jenkins  # 停止jenkins服务
  • 在浏览器访问http://localhost:8080,就会出现以下页面:

    17070225-6b1017371b6141df.png

  • 输入密码后选择安装推荐插件


    9622367-cb1be9d4eebe9780.png
  • 进入系统管理->插件管理,

  • 安装XcodeBuild, Envinject API Plugin 插件


    localhost_8080_pluginManager_installed.png

安装完成后重启Jenkins

brew services restart jenkins  # 重新启动jenkins

新建项目, 输入任务名称, 选择构建自由风格软件项目, 配置如下


localhost_8080_job_MiracleEats_configure.png

Xcode build 其他具体设置


localhost_8080_job_MiracleEats_configure (1).png

获取版本号:

# 获取app版本号
APP_VERSION=`xcodebuild -showBuildSettings | grep MARKETING_VERSION | tr -d 'MARKETING_VERSION ='`
# 构建变量写入文件
echo "APP_VERSION=${APP_VERSION}" > BuildVariable

Inject environment variables

${WORKSPACE}/BuildVariable

Properties Content

STORAGE= /Users/myg/Desktop/download/MiracleEats
BUILDPATH=/Users/myg/Desktop/download/MiracleEats/build

构建后执行的shell脚本
plist文件内字段说明
software-package: ipa包下载地址
display-image: 下载时显示的图片 5757
full-size-image: 下载时显示的图片 512
512
bundle-identifier: 项目的bundleId
bundle-version: 版本号
title: 标题

#!/bin/bash -ilex
# 生成download.plist文件
echo '<?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://download.crazymai.top/miracleEats/release/'${JOB_NAME}'_'${APP_VERSION}'.ipa</string>
    </dict>
    <dict>
    <key>kind</key>
    <string>display-image</string>
    <key>url</key>
    <string>https://source-app.miracle.com/download/image/57.jpg</string>
    </dict>
    <dict>
    <key>kind</key>
    <string>full-size-image</string>
    <key>url</key>
    <string>https://source-app.miracle.com/download/image/512.jpg</string>
    </dict>
  </array>
  <key>metadata</key>
  <dict>
    <key>bundle-identifier</key>
    <string>com.xxxx.xxxx</string>
    <key>bundle-version</key>
    <string>'${APP_VERSION}'</string>
    <key>kind</key>
    <string>software</string>
    <key>title</key>
    <string>MiracleEats</string>
  </dict>
  </dict>
</array>
</dict>
</plist>
' > ${STORAGE}/${JOB_NAME}_${APP_VERSION}Download.plist
# 生成打包信息文件, 用于Python获取当前打包信息并生成下载链接
echo ''${JOB_NAME}'_'${APP_VERSION}'
xxxx_'${APP_VERSION}'
'${APP_VERSION}'
'${SCM_CHANGELOG}'
正式環境
' > ${STORAGE}/environment.txt
# 移动ipa包到对应目录
mv ${BUILDPATH}/*.ipa ${STORAGE}/release/${JOB_NAME}_${APP_VERSION}.ipa
# 移动下载plist文件到对应目录
mv ${STORAGE}/${JOB_NAME}_${APP_VERSION}Download.plist ${STORAGE}/plist/${JOB_NAME}_${APP_VERSION}Download.plist
# 执行Python脚本
python3 ${STORAGE}/EditHtml.py
# 构建完成后钉钉通知
curl 'https://oapi.dingtalk.com/robot/send?access_token=token' \
-H 'Content-Type: application/json' \
-d "{\"msgtype\": \"link\",  \"link\": { \"text\": \"提交記錄:\n${SCM_CHANGELOG}\",\"title\": \"iOS自動打包\n點擊下載最新包 ${APP_VERSION}\", \"picUrl\": \"\", \"messageUrl\": \"https://download.crazymai.top/miracleEats/AppDownLoad.html\"}}"

恭喜你, 至此, Jenkins打包已完成~~~但是你会发现Python执行失败, 哈哈哈哈哈哈!!!

2. 那接下来开始配置Python

mac系统自带Python2, 但是由于插件只支持Python3, 所以使用homebrew安装Python3

brew install python3

安装pip3

curl https://bootstrap.pypa.io/get-pip.py | python3

安装Beautifulsoup4

pip3 install beautifulsoup4

BeautifulSoup使用方法解析, 或自行Google

到这里Python所需的环境已经配置好, 接下来编写Python脚本代码

#encoding=utf-8 所有域名问题请看最后Nginx配置
import os
import re
from bs4 import BeautifulSoup
import datetime
#打包信息文件路径
environmentFilePath = '/Users/myg/Desktop/download/xxxx/environment.txt'
#html文件路径
htmlFilePath = '/Users/myg/Desktop/download/xxxx/AppDownLoad.html'
#获取打包信息变量
appId = ''
appName = ''
appVersion = ''
commit = ''
environment = ''
with open(environmentFilePath, 'r', encoding='utf-8') as environmentVariables:
    appId = environmentVariables.readline()
    appName = environmentVariables.readline()
    appVersion = environmentVariables.readline()
    commit = environmentVariables.readline()
    environment = environmentVariables.readline()
print(appId)
print(appName)
print(appVersion)
print(commit)
print(environment)
#updateTime = (datetime.datetime.now() - datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S')
#获取当前时间
updateTime = (datetime.datetime.now()).strftime('%Y-%m-%d %H:%M:%S')
with open(htmlFilePath, 'r', encoding="utf-8") as file:
    fcontent = file.read()
    soup = BeautifulSoup(fcontent, 'html.parser')
    table = soup.find_all('tr', id=appId)
    #如果查找到直接替换标签
    if len(table) > 0:
        for td in table[0]:
            if '2022' in td.string:
                td.string = updateTime
            elif '提交人' in td.string:
                td.string = commit
    #找不到就插入
    else:
        tr_tag = soup.new_tag('tr', id=appId)
        appid_tag = soup.new_tag('td')
        appid_tag.string = appName
        appEnvironment_tag = soup.new_tag('td')
        appEnvironment_tag.string = environment
        appTime_tag = soup.new_tag('td', id='updateTime')
        appTime_tag.string = updateTime
        appLink_tag = soup.new_tag('td')
        #plist地址路径, 所有域名问题请看最后Nginx配置
        appa_tag = soup.new_tag('a', href='itms-services://?action=download-manifest&amp;url=https://download.crazymai.top/download/plist/' + appId + 'Download.plist')
        appa_tag.string = '立即下载'
        appLink_tag.append(appa_tag)
        appCommit_tag = soup.new_tag('td', id='commit')
        appCommit_tag.string = commit
        tr_tag.append(appid_tag)
        tr_tag.append(appEnvironment_tag)
        tr_tag.append(appTime_tag)
        tr_tag.append(appLink_tag)
        tr_tag.append(appCommit_tag)
        table = soup.find('table', id='demo')
        table.append(tr_tag)
    #重新写入文件
    change_content = str(soup).encode(encoding='utf-8')
    change_html = open(htmlFilePath, "w+b")
    change_html.write(change_content)
    change_html.close()

python已配置完成, 别着急回去Jenkins点击build, 因为你会发现html还没存在

3. HTML文件

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>App下载</title>
</head>
<body>
<div align="center">
<table cellpadding="20">
<th>App下载</th>
</table>
<table cellpadding="20" frame="below" id="demo">
<tr id="MiracleEats_1.4.1
"><td>閃送外賣_1.4.1
</td><td>正式環境
</td><td id="updateTime">2022-10-09 00:30:55</td><td><a href="itms-services://?action=download-manifest&amp;amp;url=https://download.crazymai.top/miracleEats/plist/MiracleEats_1.4.1
Download.plist">立即下载</a></td><td id="commit">
</td></tr></table>
<table cellpadding="20">
<td> </td>
</table>
<div>©️ CarzyMai</div>
</div>
</body>
</html>

最简单的一个table, 可根据自身情况优化对应html代码
到这里Jenkins+Python+HTML更新已经完成, 可以到Jenkins去尝试build, 你会发现已经build成功
那接下来可以让公司的运维给你配置服务器资源, 然后对应修改以上所有域名相关地址

Nginx配置

1.安装Nginx

# nginx常用命令
brew install nginx # 安装nginx
brew info nginx    # nginx的配置
sudo nginx        # nginx启动
sudo nginx -s reload # 重载配置文件
sudo nginx -s stop # 停止nginx服务器

安装完成后

vi /usr/local/etc/nginx/nginx.conf

conf文件配置如下

user root owner;
worker_processes  1;
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
#pid        logs/nginx.pid;
events {
    worker_connections  1024;
}
http {
    include      mime.types;
    default_type  application/octet-stream;
    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';
    #access_log  logs/access.log  main;
    sendfile        on;
    #tcp_nopush    on;
    #keepalive_timeout  0;
    keepalive_timeout  65;
    #gzip  on;
    # server {
    #    listen      8080;
    #    server_name  localhost;
    #    #charset koi8-r;
    #    #access_log  logs/host.access.log  main;
    #    location / {
    #        root  html;
    #        index  index.html index.htm;
    #    }
    #    #error_page  404              /404.html;
    #    # redirect server error pages to the static page /50x.html
    #    #
    #    error_page  500 502 503 504  /50x.html;
    #    location = /50x.html {
    #        root  html;
    #    }
    #    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #    #
    #    #location ~ \.php$ {
    #    #    proxy_pass  http://127.0.0.1;
    #    #}
    #    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #    #location ~ \.php$ {
    #    #    root          html;
    #    #    fastcgi_pass  127.0.0.1:9000;
    #    #    fastcgi_index  index.php;
    #    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    #    include        fastcgi_params;
    #    #}
    #    # deny access to .htaccess files, if Apache's document root
    #    # concurs with nginx's one
    #    #
    #    #location ~ /\.ht {
    #    #    deny  all;
    #    #}
    # }
    # another virtual host using mix of IP-, name-, and port-based configuration
    #server {
    #    listen      8000;
    #    listen      somename:8080;
    #    server_name  somename  alias  another.alias;
    #    location / {
    #        root  html;
    #        index  index.html index.htm;
    #    }
    #}

#必须使用HTTPS
    #HTTPS server
    server {
      listen      443 ssl;
      server_name  download.crazymai.top; #域名
#https证书
      ssl_certificate      /Users/myg/Desktop/8512975_download.crazymai.top_nginx/8512975_download.crazymai.top.pem; #ssl.pem文件路径
      ssl_certificate_key  /Users/myg/Desktop/8512975_download.crazymai.top_nginx/8512975_download.crazymai.top.key; #ssl.key文件路径
      ssl_session_cache    shared:SSL:1m;
      ssl_session_timeout  5m;
      ssl_ciphers  HIGH:!aNULL:!MD5;
      ssl_prefer_server_ciphers  on;
# html目录路径
      location / {
          root  /Users/myg/Desktop/download;
          index  AppDownLoad.html;
      }
    }
    include servers/*;
}

苹果下载需要https验证, 所以这里需要到阿里云上申请免费https证书和域名

  1. 登录阿里云

  2. 进入控制台

  3. 先购买域名并实名认证

  4. 等待实名认证后

  5. 进入云解析DNS, 添加记录, 输入具体的信息
    主机记录: 具体域名
    记录值: 打包机网络ip地址, 让运维帮忙配置一个固定的地址, 不要使用自动获取, 不然主机地址会变化, 每次变化需要到这里修改


    image-20221009141537372.png
  6. 进入SSL 证书 (应用安全), 创建免费ssl证书


    image-20221009142056083.png
  7. 填写证书申请信息
    域名: 需要填写完整域名!!!!


    image-20221009142211520_副本.png
  8. 验证DNS, 通过后提交审核


    image-20221009142406391.png
  9. 通过后在列表上会显示已签发证书


    image-20221009142538880.png
  10. 下载ssl证书到本地


    image-20221009142627146.png

下载完成后将key和pem文件绝对路径填入到nginx.conf文件对应的位置内

最后的最后, 配置nginx可能会遇到的问题

  1. 如果通过域名访问, 显示503, 解决方法:
  • 通过终端, 切换root用户, 启动nginx
  • 将电脑的防火墙全部关掉
  • 更改html目录文件夹访问权限
    chmod 777 文件夹绝对路径
    
  1. 访问显示404
  • 查看路径是否正确

到这里整个搭建已完成~

PS: - 本人不是专业的运维, 对nginx安全理解较浅, 本nginx搭建只针对内网使用!!!!!!!

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

推荐阅读更多精彩内容