iOS打包脚本手册【Jenkins远程构建】

缘起:公司最近推出大企业定制化的App产品,客户企业可以定制App名称、logo、文案及工程里的参数等,项目经理在禅道里上传图片素材,填写文案和参数,点击构建即可远程触发Jenkins服务器构建iOS工程,将构建好的ipa包上传服务器,并通知禅道构建结果。我负责iOS构建的Jenkins服务器的搭建。

基础功能

关于Jenkins服务的搭建网上已经有大量的文章介绍了,本文主要介绍一些实用的操作Xcode工程的shell指令和Jenkins插件

导图.png

常用操作指令

  1. 文件删除、创建路径
if [ -d dirPath ];then
rm -rf dirPath/*
else
mkdir dirPath
fi
  1. 文件查找、替换
    find(选项)(参数)
    find命令可以高效地替换工程中的图片,遍历客户提供的图片素材,利用find指令自动地在工程里的指定文件夹下替换和素材同名的图片
    每个图片文件夹下有2倍和3倍的图片
#指定工程里的图片路径
Find_Path="${WORKSPACE}/Resources/images/Configurable.xcassets ${WORKSPACE}/Resources/images/Proj.xcassets"
#客户提供的图片素材
Images_Path="${Project_Build_resource_path}/images_iOS"
cd ${Images_Path}
for itemFile in `ls`; do
    cd ${Images_Path}/$itemFile
    find ${Find_Path} -iname "${itemFile}.*" -exec cp -r ${Images_Path}/${itemFile}/* {} \;
done
  1. 文件下载、get请求
    wget命令用来从指定的URL下载文件
    下载文件:
    wget http://192.20.183.143/data/project/ios.zip
    发送get请求
    wget "http://sample.com/recFile?result=构建成功"
  2. 文件上传
    curl是一个利用URL规则在命令行下工作的文件传输工具,是一款很强大的http命令行工具(功能比wget更强大)
    上传文件到ftp服务器
#ftp服务器(两个都需要上传) 用户名 密码
ftp_domain="ftp://10.247.10.75/mixed"
ftp_user="ftpmixyun"
ftp_pw="ftpmixyun"

#ftp上传ipa的路径,如:ftp://10.247.10.75/wens/iOS/beta/
ftp_upload_path="${projectcode}/iOS/beta"

#ftp创建上传路径
curl -u ${ftp_user}:${ftp_pw} --ftp-create-dirs "${ftp_domain}/${ftp_upload_path}/"
#ftp上传ipa 
curl -u ${ftp_user}:${ftp_pw} -T ${IPAPath} "${ftp_domain}/${ftp_upload_path}/"
  1. 压缩文件解压缩
    unzip -o ./image_ios.zip
  2. 读取属性值,替换普通文件里的值
    sed是处理、编辑文本文件的指令,功能非常强大
    读取属性(例. properties文件)

读取属性值

appname=`sed '/^APPNAME=/!d;s/.*=//' ios.properties`

替换工程里的参数

# Config_project:工程里的 userConfig.m文件
# APPNAME_placeHolder:userConfig.m文件里的占位值
sed -i '' "s/APPNAME_placeHolder/$appname/g" $Config_project
  1. plist文件的增、删、改、查
    PlistBuddy的名字就可以看出,它是plist的小伙伴。PlistBuddy是Mac自带的专门解析plist的小工具
    替换info.plist里的App名称
    /usr/libexec/plistbuddy -c "Set :CFBundleDisplayName ‘${appname}’” ${WORKSPACE}/info.plist
    读取info.plist里的版本
    bundleShortVersion=$(/usr/libexec/PlistBuddy -c "print CFBundleShortVersionString" ${WORKSPACE}/info.plist)
    在info.plist里增加QQ分享AppKey
    /usr/libexec/plistbuddy -c "Add CFBundleURLTypes:0:CFBundleURLSchemes:1 string QQ${QQ_APPKEY}" ${WORKSPACE}/info.plist
  2. 导入iOS证书
    Security是Mac系统中钥匙串和安全模块的命令行管理工具
    导入发布证书
security unlock-keychain -p $mac_password /Users/${mac_user}/Library/Keychains/login.keychain
security list-keychains -s /Users/${mac_user}/Library/Keychains/login.keychain
security import $p12_distribution -k /Users/${mac_user}/Library/Keychains/login.keychain -P $Distribustion_PW -T /usr/bin/codesign
security find-identity -p codesigning /Users/${mac_user}/Library/Keychains/login.keychain

Ps:目前用脚本导入证书后电脑钥匙串里有该证书,但是第一次构建时依然提醒要输入电脑密码,这个问题未解决 —_—

  1. 解析iOS描述文件
# 获取描述文件.mobileprovision的详细信息,包括名称、ID、有效期等等
PROFILE_DATA=$(security cms -D -i ${pp_main})
# 解析AppGroup名称
APPGroup=$(/usr/libexec/PlistBuddy -c 'Print :Entitlements:com.apple.security.application-groups:0' /dev/stdin <<< $PROFILE_DATA)
# 解析TeamId
TeamId =$(/usr/libexec/PlistBuddy -c 'Print :ApplicationIdentifierPrefix:0' /dev/stdin <<< $PROFILE_DATA)
# .mobileprovision的名字
pp_name=$(/usr/libexec/PlistBuddy -c 'Print :Name' /dev/stdin <<< $PROFILE_DATA)
# .mobileprovision的UUID
pp_UUID=$(/usr/libexec/PlistBuddy -c 'Print :UUID' /dev/stdin <<< $PROFILE_DATA)
# .mobileprovision的AppID,即bundleId
CODE_SIGN_IDENTITY=$(/usr/libexec/PlistBuddy -c 'Print :Entitlements:application-identifier' /dev/stdin <<< $PROFILE_DATA)
pp_bundleId=${CODE_SIGN_IDENTITY#*.}
  1. xcodebuild编译(企业分发类型In-House)
    一般项目可以用Jenkins的插件Xcode integration xcode来打包。
    由于我们的app的target有多个extension,因此有多个描述文件,这个插件无法配置,采用纯脚本的方式
#选择Xcode版本
sudo xcode-select -s /Applications/Xcode9.0.app/Contents/Developer
## 打包
archivePath=${WORKSPACE}/build/${projectcode}-iphoneos/kdweibo.xcarchive
xcodebuild -scheme ${projectname} -workspace ${projectname}.xcworkspace -configuration Release archive -archivePath ${archivePath} DEVELOPMENT_TEAM=${TeamId}

企业分发类型的项目导出 ipa 包时需要一个enterprise.plist文件

enterprise="${Project_Build_resource_path}/enterprise-${TeamId}-${projectcode}.plist"
#设置enterprise.plist
/usr/libexec/plistbuddy -c "Set teamID ${TeamId}" ${enterprise}
/usr/libexec/plistbuddy -c "Add provisioningProfiles:${pp_main_bundleId} string ${pp_main_name}" ${enterprise}
/usr/libexec/plistbuddy -c "Add provisioningProfiles:${pp_extension_bundleId} string ${pp_extension_name}" ${enterprise}
/usr/libexec/plistbuddy -c "Add provisioningProfiles:${pp_widget_bundleId} string ${pp_widget_name}" ${enterprise}
/usr/libexec/plistbuddy -c "Add provisioningProfiles:${pp_message_bundleId} string ${pp_message_name}" ${enterprise}
/usr/libexec/plistbuddy -c "Add provisioningProfiles:${pp_call_bundleId} string ${pp_call_name}" ${enterprise}

导出ipa包
/usr/bin/xcodebuild -exportArchive -archivePath ${archivePath} -exportPath ${exportPath} -exportOptionsPlist ${enterprise}

  1. 比较版本号
currentVer="8.8.6"
targetVer="9.9.9"

if [ "$(printf '%s\n' "$currentVer" "$targetVer" | sort -V | head -n1)" = "$targetVer" ]; then 
    echo "Greater than or equal to $targetVer"
else
    echo "Less than $targetVer"
fi

备注:表达式$(printf '%s\n' "$a” "$a” | sort -V | head -n1) 返回$a$b中较小的一个值

实用Jenkins插件

Jenkins默认的构建历史列表只有构建号和日期:


当我们有大量的构建任务,并且有不同的项目,我们就很难从这个构建历史列表中找出某一个项目的某次构建任务了,下面两个插件可以自定义构建任务的标题,并且为构建任务添加描述,效果如下:


  1. build-name-setter 自定义任务名称


  2. description setter plugin 任务描述
    这个插件的原理是从构建日志中用正则找出想要在构建描述里显示的值,因此需要首先在构建脚本的最后面写上

#build信息(用于在构建历史列表里显示)
description="[description]分支:${definedBranch}, 版本:${bundleShortVersion}, 构建号:${buildno}"

然后“增加构建步骤”——Set build description


4444.png

由于description里需要换行,因此要设置Jenkins支持html格式

点击 Manage Jenkins 进入Jenkins管理配置界面:
然后在进入 Configure Global Security 配置界面:
修改Markup Formatter 中默认的Plain text ==> Safe HTML
保存配置即可

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

推荐阅读更多精彩内容