Jenkins+Nginx+Python搭建iOS打包下載平臺(tái)

前言:
Jenkins自動(dòng)打包針對(duì)提交測(cè)試不需要每次都手動(dòng)真機(jī)打包或者導(dǎo)包耗時(shí), 可以節(jié)省很多時(shí)間, 提高開發(fā)的效率
本解決方案還有很多優(yōu)化空間, 比如html的樣式、html顯示的信息、build版本等等
測(cè)試人員只需要在手機(jī)連內(nèi)網(wǎng)WiFi,并到對(duì)應(yīng)網(wǎng)址即可下載對(duì)應(yīng)的包進(jìn)行測(cè)試
搭建主要思路:

  1. 通過(guò)Jenkins自動(dòng)打包功能,使用輪詢機(jī)制判斷分支上是否有修改記錄,從而進(jìn)行打包操作
  2. 打包完成后主要文件有3個(gè):ipa包、plist文件、打包信息文本environment.txt
  3. 使用python bs4腳本對(duì)html文件進(jìn)行修改
  4. 使用nginx搭建html訪問(wèn)和ipa包下載功能

開始搭建

1. 安裝Jenkins

  • 使用homeBrew安裝
# jenkins常用命令
brew install jenkins # 安裝jenkins
brew services start jenkins  # 啟動(dòng)jenkins
brew services restart jenkins  # 重新啟動(dòng)jenkins
brew upgrade jenkins  # 更新jenkins
brew services stop jenkins  # 停止jenkins服務(wù)
  • 在瀏覽器訪問(wèn)http://localhost:8080,就會(huì)出現(xiàn)以下頁(yè)面:

    17070225-6b1017371b6141df.png

  • 輸入密碼后選擇安裝推薦插件


    9622367-cb1be9d4eebe9780.png
  • 進(jìn)入系統(tǒng)管理->插件管理,

  • 安裝XcodeBuild, Envinject API Plugin 插件


    localhost_8080_pluginManager_installed.png

安裝完成后重啟Jenkins

brew services restart jenkins  # 重新啟動(dòng)jenkins

新建項(xiàng)目, 輸入任務(wù)名稱, 選擇構(gòu)建自由風(fēng)格軟件項(xiàng)目, 配置如下


localhost_8080_job_MiracleEats_configure.png

Xcode build 其他具體設(shè)置


localhost_8080_job_MiracleEats_configure (1).png

獲取版本號(hào):

# 獲取app版本號(hào)
APP_VERSION=`xcodebuild -showBuildSettings | grep MARKETING_VERSION | tr -d 'MARKETING_VERSION ='`
# 構(gòu)建變量寫入文件
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

構(gòu)建后執(zhí)行的shell腳本
plist文件內(nèi)字段說(shuō)明
software-package: ipa包下載地址
display-image: 下載時(shí)顯示的圖片 5757
full-size-image: 下載時(shí)顯示的圖片 512
512
bundle-identifier: 項(xiàng)目的bundleId
bundle-version: 版本號(hào)
title: 標(biāo)題

#!/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獲取當(dāng)前打包信息并生成下載鏈接
echo ''${JOB_NAME}'_'${APP_VERSION}'
xxxx_'${APP_VERSION}'
'${APP_VERSION}'
'${SCM_CHANGELOG}'
正式環(huán)境
' > ${STORAGE}/environment.txt
# 移動(dòng)ipa包到對(duì)應(yīng)目錄
mv ${BUILDPATH}/*.ipa ${STORAGE}/release/${JOB_NAME}_${APP_VERSION}.ipa
# 移動(dòng)下載plist文件到對(duì)應(yīng)目錄
mv ${STORAGE}/${JOB_NAME}_${APP_VERSION}Download.plist ${STORAGE}/plist/${JOB_NAME}_${APP_VERSION}Download.plist
# 執(zhí)行Python腳本
python3 ${STORAGE}/EditHtml.py
# 構(gòu)建完成后釘釘通知
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自動(dòng)打包\n點(diǎn)擊下載最新包 ${APP_VERSION}\", \"picUrl\": \"\", \"messageUrl\": \"https://download.crazymai.top/miracleEats/AppDownLoad.html\"}}"

恭喜你, 至此, Jenkins打包已完成~~~但是你會(huì)發(fā)現(xiàn)Python執(zhí)行失敗, 哈哈哈哈哈哈!!!

2. 那接下來(lái)開始配置Python

mac系統(tǒng)自帶Python2, 但是由于插件只支持Python3, 所以使用homebrew安裝Python3

brew install python3

安裝pip3

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

安裝Beautifulsoup4

pip3 install beautifulsoup4

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

到這里Python所需的環(huán)境已經(jīng)配置好, 接下來(lái)編寫Python腳本代碼

#encoding=utf-8 所有域名問(wèn)題請(qǐng)看最后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')
#獲取當(dāng)前時(shí)間
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)
    #如果查找到直接替換標(biāo)簽
    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地址路徑, 所有域名問(wèn)題請(qǐng)看最后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點(diǎn)擊build, 因?yàn)槟銜?huì)發(fā)現(xiàn)html還沒(méi)存在

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>正式環(huán)境
</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>

最簡(jiǎn)單的一個(gè)table, 可根據(jù)自身情況優(yōu)化對(duì)應(yīng)html代碼
到這里Jenkins+Python+HTML更新已經(jīng)完成, 可以到Jenkins去嘗試build, 你會(huì)發(fā)現(xiàn)已經(jīng)build成功
那接下來(lái)可以讓公司的運(yùn)維給你配置服務(wù)器資源, 然后對(duì)應(yīng)修改以上所有域名相關(guān)地址

Nginx配置

1.安裝Nginx

# nginx常用命令
brew install nginx # 安裝nginx
brew info nginx    # nginx的配置
sudo nginx        # nginx啟動(dòng)
sudo nginx -s reload # 重載配置文件
sudo nginx -s stop # 停止nginx服務(wù)器

安裝完成后

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驗(yàn)證, 所以這里需要到阿里云上申請(qǐng)免費(fèi)https證書和域名

  1. 登錄阿里云

  2. 進(jìn)入控制臺(tái)

  3. 先購(gòu)買域名并實(shí)名認(rèn)證

  4. 等待實(shí)名認(rèn)證后

  5. 進(jìn)入云解析DNS, 添加記錄, 輸入具體的信息
    主機(jī)記錄: 具體域名
    記錄值: 打包機(jī)網(wǎng)絡(luò)ip地址, 讓運(yùn)維幫忙配置一個(gè)固定的地址, 不要使用自動(dòng)獲取, 不然主機(jī)地址會(huì)變化, 每次變化需要到這里修改


    image-20221009141537372.png
  6. 進(jìn)入SSL 證書 (應(yīng)用安全), 創(chuàng)建免費(fèi)ssl證書


    image-20221009142056083.png
  7. 填寫證書申請(qǐng)信息
    域名: 需要填寫完整域名!!!!


    image-20221009142211520_副本.png
  8. 驗(yàn)證DNS, 通過(guò)后提交審核


    image-20221009142406391.png
  9. 通過(guò)后在列表上會(huì)顯示已簽發(fā)證書


    image-20221009142538880.png
  10. 下載ssl證書到本地


    image-20221009142627146.png

下載完成后將key和pem文件絕對(duì)路徑填入到nginx.conf文件對(duì)應(yīng)的位置內(nèi)

最后的最后, 配置nginx可能會(huì)遇到的問(wèn)題

  1. 如果通過(guò)域名訪問(wèn), 顯示503, 解決方法:
  • 通過(guò)終端, 切換root用戶, 啟動(dòng)nginx
  • 將電腦的防火墻全部關(guān)掉
  • 更改html目錄文件夾訪問(wèn)權(quán)限
    chmod 777 文件夾絕對(duì)路徑
    
  1. 訪問(wèn)顯示404
  • 查看路徑是否正確

到這里整個(gè)搭建已完成~

PS: - 本人不是專業(yè)的運(yùn)維, 對(duì)nginx安全理解較淺, 本nginx搭建只針對(duì)內(nèi)網(wǎng)使用!!!!!!!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容