自建iOS内测分发平台

原文参见:https://cba023.github.io

需要什么

  • XCode编译环境:用于编译iOS应用程序
  • openssl环境(用于生成自签SSL证书)
  • HTML分发网页(本文附相应文件链接,可以直接下载部署)
  • nginx环境:用于配置http和https服务
  • Jenkins 用于持续集成(远程构建)
  • 可用于分发的iOS证书签名(如:adhoc签名,appstore签名)
  • 本地git环境和远程git仓库(用于代码托管和持续集成代码拉取)

创建App

使用XCode创建一个iOS应用工程,命名App1。这里我们以Swift语言创建该工程。
我们将要对项目配置三个运行环境(Objective-C配置环境变量有稍许差异),分别如下:

名称 环境
DEV 开发环境
UAT 预发布环境
PROD 生产环境
创建一个Swift工程取名为App1

接下来使用CocoaPods对工程进行管理。
打开终端,进入到工程目录,执行pod initpod install。如下图:

使用CocoaPods管理项目

为了让应用在分发时可以构建多个渠道的安装包,这里我们可以对它的环境进行参数化配置。
打开工程的xcworkspace文件,现在我们要对工程配置2个Scheme,创建完成后加上原有的Scheme总计3个。

创建多个Scheme

创建好的Sheme列表如下:

创建好Sheme的效果

在原有的两个Build configuration基础上再创建4个,分别让DebugRelease对应DEVUAT环境。

创建多个Build configuration

为了让App变得完整接下来配置项目的图标信息。

配置项目的图标

接下来关联Sheme和Build Configuraion(Debug和Release两种情况)。

对应关系如表所示:

Scheme Debug Release
App1 Debug Release
App1_DEV Debug_DEV Release_DEV
App1_UAT Debug_UAT Release_UAT

效果如下:

关联Scheme和Build configuration

接着在项目工程中配置环境变量,如图所示:

配置环境变量
Build configuration 环境变量
Debug DEBUG
Debug_DEV DEBUG ENVIOMENT_DEV
Debug_UAT DEBUG ENVIOMENT_UAT
Release
Release_DEV ENVIOMENT_DEV
Debug ENVIOMENT_UAT

然后就可以在代码中加入环境变量判断来控制源码编译实现不同环境的App的差异配置。

这里我们在不同环境下分别让App首页背景为不同颜色

环境 首页背景色
DEV
UAT 绿
PROD

首页使用环境变量来控制预编译。源码如下:

#if ENVIROMENT_DEV
view.backgroundColor = .red
enviromentLabel.text = "DEV"
#elseif ENVIROMENT_UAT
view.backgroundColor = .green
enviromentLabel.text = "UAT"
#else
view.backgroundColor = .blue
enviromentLabel.text = "PROD"
#endif

例如:将Sheme选择为App_UAT,编译运行,即可看到设备上运行的App首页被金色变成了绿色,说明环境变量关联Scheme已经生效。

将Sheme选择为App_UAT

页面展示效果:

运行效果

显然,通过选择不同的Sheme来关联环境变量还可以做更多的操作,比如网络接口地址等。

工程仓库已经上传到GitHub,可以下载参考。

仓库地址:https://github.com/cba023/App1.git

使用XCode自带的Archive工具分发App

更改应用的版本相关信息

更改应用的版本相关信息

选着指定的Scheme执行归档,注意设备要选择Any iOS Device

归档
归档完成,手动分发
adhoc
分发选项
手动签名
选择签名
签名信息确认
导出到目录

备份ExportOptions.plist到iOS_Distribution,重命名为ExportOptions_adhoc.plist

生成的文件

分发应用时涉及到证书配置、签名、和分发途径的相关信息,先使用Archive工具通过adhoc途径分发一次adhoc,获取ExportOptions.plist文件并备份。此处不细说,若有不熟之处,可上互联网搜索相关资料。

导入分发网页

将之前已经编写好的Web网页导入指定目录,这里我们指定/Users/chenbo/DAPP为Web服务根目录。Web网页的文件结构如下:

/Users/chenbo/DAPP 
├── detail.html
├── index.html
└── source
    ├── qrcode.min.js
    ├── reset.css
    ├── style.css
    └── vue.global.prod.js

1 directory, 6 files

分发网页Git仓库地址:https://github.com/cba023/iOS_DistributionAssets.git

生成自签SSL证书

首先获取本机IP地址方便项目的配置与部署。Mac上查看IP地址非常简单,可在系统偏好设置->网络中可以查看。

获取IP

创建公私钥文件夹

mkdir -p /usr/local/etc/ssl/private
mkdir -p /usr/local/etc/ssl/certs

创建秘钥和证书

sudo openssl req \
  -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /usr/local/etc/ssl/private/self-signed.key \
  -out /usr/local/etc/ssl/certs/self-signed.crt

输入指定后需要填写证书的一些信息,Common Name需要填写为自定义的域名,这里我把它设成了本机的IP地址。

生成自签证书

然后打开/usr/local/etc/ssl目录,privatecerts文件夹分别生成了私钥和证书。

/Users/chenbo/DAPP目录下创建一个ssl子目录,再把self-signed.crt拷贝一份到ssl中,用于分发网页中的SSL证书下载。

安装和使用nginx

安装nginx

安装nginx有多种方式,这里我们使用brew来安装,如果你的Mac上没有安装brew环境,可以去网上了解下brew的安装教程。

执行以下指令,brew会自动安装nginx:

brew install nginx

安装完成后在终端输入:

nginx -version
nginx版本查看

如果显示了nginx版本即表示已经安装成功。

配置nginx的http和https服务

由于苹果官方要求分发应用必须使用https协议,而我们自己搭建服务使用了自签证书,需要先使用http服务下载证书后才能正常使用https服务,所以这里我们同时配置http和https服务。

使用访达打开/usr/local/etc/nginx目录,编辑nginx.conf文件。如下:

server {
        listen       80;
        listen       443 ssl;
        server_name  localhost;
        # ssl on;
        # location of ssl certificate
        ssl_certificate /usr/local/etc/ssl/certs/self-signed.crt;
        # location of ssl key
        ssl_certificate_key /usr/local/etc/ssl/private/self-signed.key;

        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;

        ssl_ciphers  HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers  on;

        location / {
            root   /Users/chenbo/DAPP;
            index  index.html index.htm;
        }
    }

上述配置开启了80和443端口,即开启了http和https服务, ssl_certificate和ssl_certificate_key分别对应的自签名证书和私钥的路径,和openssl生成的路径保持一致。
这里有一点要注意,/Users/chenbo/DAPP是我设定的nginx服务根目录,该目录和上一小节中的HTML存放路径保持一致。

接下来就可以启动nginx服务了。

brew services start nginx

如下图所示,nginx成功启动。

启动nginx

打开Mac的系统偏好设置->安全与隐私->防火墙->关闭,即关闭Mac的防火墙。

接着在浏览器中打开我们之前设定的服务地址。

http://192.168.0.103

打开分发网页

配置iOS应用分发Shell脚本

Shell脚本下载地址:https://github.com/cba023/iOS_DistributionAssets.git

iOS_Distribution目录拷贝到用户文件夹。

/Users/chenbo/iOS_Distribution
├── AutoSh
│   ├── ExportOptions_adhoc.plist
│   └── distribute.sh
└── Others
    ├── base.plist
    └── blank.plist

2 directories, 4 files
  • ExportOptions_adhoc.plist是之前使用XCode打包时生成的ExportOptions.plist重命名而来,包含了项目的构建信息。

  • distribute.sh文件需做稍许更改

    • __APP_NAME="APP1" # 应用的名称这里固定
    • __HOST="192.168.0.103" # Host指定为nginx服务的IP地址
  • Other目录下有两个plist文件,后面在脚本运行时能调用到,请不要自行修改文件内容

    • blank.plist: 空属性列表文件,用于脚本执行写入分发记录信息
    • base.plist: 用于写入App远程安装时的远程配置信息

检查完善DAPP目录的文件与配置

DAPP即/Users/chenbo/DAPP目录,从上文已经得知在DAPP中已经包含了下列文件:

  • 分发网页相关文件
  • ssl证书文件

在DAPP中创建images目录,并导入应用分发时要用到的两个尺寸的Logo文件,格式png。

文件名 分辨率
image_57x57.png 57 * 57
image_512x512.png 512 * 512

导入后DAPP目录内容如下:

检查DAPP目录

现在就可以通过脚本来构建分发应用了。

使用Shell直接构建App并分发

把iOS_Distribution目录下的AutoSh目录拷贝到App1的工程根目录,然后使用终端打开工程根目录下的AutoSh,执行:

sh distribute.sh -h

可以看到:

分发脚本选项列表

终端显示了脚本的使用方法,这里我们执行下列指令:

sh distribute.sh -b Release -s App1 -u "修复问题若干;优化性能若干;增加功能若干;XXX xx,XXX_XX"

执行,如下图所示,终端窗口自动将更更新内容显示出来了,并展示了更多的日志信息。

执行分发脚本后的效果

直到构建完成。

构建完成脚本展示提示

此时我们打开分发的网页地址,发现历史版本中多了一项记录,即刚才构建的项目。

构建分发完成后分发网页会多一条构建记录

尝试更改App1工程内的版本信息,再次执行分发指令,并尝试更改工程的Scheme为App1_DEV或App1:


更改XCode工程中的版本号
  • 分发DEV环境的包
sh distribute.sh -b Release_DEV -s App1_DEV -u "版本改 为1.0.1;"
  • 分发UAT环境的包
sh distribute.sh -b Release_UAT -s App1_UAT -u "UAT;"

分发的网页地址多了两条记录,而且筛选菜单也有了多种选项可以筛选版本号和构建类型。

多次构建不同版本和渠道的应用

我们点击一条记录。

Mac端上的分发详情页

即跳转到了单次分发的详情页,该页面真实了APP1本次构建的详细信息,包括构建的一些参数和更新内容。
如果手机和构建的Mac主机是处于一个局域网内且Mac主机关机了防火墙,则可以实现扫码安装该应用包(保证当前签名已经录入了安装手机的UDID情况方能使用)。

iOS移动设备上的分发详情页

手机扫码后Safari浏览器打开分发详情页,首次安装App前需要点击页面左下角的安装SSL证书(描述文件),并去手机设置->通用->关于本机中信任该描述文件,然再点击点击安装字样按钮。

点击安装

然后就自动安装到手机上了。

安装完成

使用Jenkins来管理应用分发

Jenkins安装教程:https://gitee.com/jenkins-zhhttps://www.jenkins.io
Jenkins安装好后需要配置环境变量才能保证可以调用Shell中的指令,可进入Jenkins系统管理->系统配置->全局属性->环境变量中配置PATH,PATH内容可以从Mac终端中输入echo $PATH打印的内容拷贝过来。

Jenkins首页
创建任务
配置构建参数Scheme
配置构建参数下载HOST
配置构建参数更新内容
源码管理
选择配置Shell
配置Shell内容

Jenkins中配置的Shell,可以实现Jenkins参数化运行。

#!/bin/bash

export LANG="en_US.UTF-8"
if [[ ${SCHEME} == "App1_DEV" ]]; then
    __BUILD_CONF="Release_DEV"
elif [[ ${SCHEME} == "App1_UAT" ]]; then
    __BUILD_CONF="Release_UAT"
else
    __BUILD_CONF="Release"
fi

__UPDATES=${UPDATES}
echo "__UPDATES:${__UPDATES}"
__UPDATES_LENGTH=${#__UPDATES}
if [[ ${__UPDATES_LENGTH} -lt 1 ]]; then
    __UPDATES=$(git log --format=%B -n 1 HEAD)
fi
echo "Jenkins -> SCHEME: ${SCHEME}, __BUILD_CONF: ${__BUILD_CONF}"
cp -rf /Users/`whoami`/iOS_Distribution/AutoSh/ ${WORKSPACE}/AutoSh/
cd ${WORKSPACE}/AutoSh/

sh ${WORKSPACE}/AutoSh/distribute.sh -a ${DOWNLOAD_HOST} -s ${SCHEME} -b ${__BUILD_CONF} -u "${__UPDATES}"

点击保存。

点击保存

参数化构建。

参数化构建

设定构建的参数。

执行参数化构建

开始构建后可以看到构建进度。

选择构建参数

可从构建任务重选择查看控制台输出的日志。

选择控制台展示

日志显示任务完成。

控制台展示

构建成功,然后进入分发网页,即看到分发记录里又多了一条记录。接着就可以使用逸动设备扫码安装应用了。

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

推荐阅读更多精彩内容