分享一个xcode9 ipa打包脚本

写在前面

之前写了一个很简单的ipa打包脚本,主要是用Xcode命令中的xcodebuild和xcrun命令来完成的,其中打包ipa的命令用了PackageApplication,本来用的好好的,升级了Xcode9之后,发现苹果把PackageApplication这个东西给删了,于是脚本就跪了。。。

所以,这两个月我用了一个很原始的方法来打ipa包。大家也可以试试(大家常用的直接用Xcode中的Product->Archive的方法我就懒得说了,大家都懂):

1.自己在Xcode配置好项目的签名

2.用Generic iOS Device来build工程

3.找到生成的.app包,然后新建一个名为Payload的文件夹,将.app包放到文件夹里面

4.压缩Payload文件夹,然后将压缩包的后缀从.zip改成.ipa。

然后就可以将ipa包安装到手机上测试了。

用Generic iOS Device来build工程

压缩Payload文件夹,然后将压缩包的后缀从.zip改成.ipa

为什么需要一个ipa打包脚本

嗯,因为想偷懒。

直接在Xcode上点击Product->Archive->此处省略n步选择.......这种方式确实是挺方便的,估计很多人也是这么干的。但是,当你多次打包了之后你就发现,打包这事好无聊。每次都是同样的配置,同样的操作步骤,同样的选择,这么简单的操作我居然要重复N遍。。。而且有时候要等很久才能进行下一步。总之我觉得这种方式操作多了很是蛋疼。

我一直秉承一个理念:能用机器自动解决的问题尽量不用人工操作

要是有一个东西,只要我配置好了一次之后,以后直接双击就能直接打包,是不是比之前的方式更好?

嗯,有挺多这种工具的,比如shenzhen,fastlane等等。

不过我是自己写了一个简单的shell脚本来实现功能的,比较简单,而且不会对项目有侵入性。借此还可以顺便学习下shell脚本使用。

自动打包脚本如何使用?

脚本的github地址为:https://github.com/shixueqian/AutoPackageScript

使用方法:

1.将脚本复制到工程的根目录

2.用代码编辑软件(比如Xcode)打开脚本,然后根据情况修改脚本内的一些参数

3.打开终端,输入 sh ${打包脚本的全路径}就可执行打包脚本。

比如我的项目工程在

/Users/mac/Desktop/AutoPackageScriptDemo,

那么我的脚本路径应该是

/Users/mac/Desktop/AutoPackageScriptDemo/AutoPackageScript.sh,

所以我要执行的命令是

sh /Users/mac/Desktop/AutoPackageScriptDemo/AutoPackageScript.sh

sh ${打包脚本的全路径}这行命令的作用是执行shell打包脚本。

除了这样执行,我们还可以直接双击脚本文件就执行脚本,不过在这之前我们需要进行一些设置。

首先,将AutoPackageScript.sh文件的扩展名去掉,变成AutoPackageScript

然后,打开终端,执行命令 chmod +x ${打包脚本的全路径},这样可以给脚本加上可执行权限,并且默认的打开方式是终端。

例如:chmod +x /Users/mac/Desktop/AutoPackageScriptDemo/AutoPackageScript

以后,直接鼠标双击就可以执行脚本了

脚本参数配置

看了脚本的使用,其中有一个很关键的东西,脚本参数配置。我对多种情况都有适配,所以脚本参数会稍微有点复杂,以下我们慢慢道来。

项目的工程结构

我也不知道怎么称呼这个东西,简单来讲就是你的工程里面是不是使用xcworkspace(工作空间)来管理你的工程。

我们在Xcode直接新建一个iOS工程,这个时候仅仅只有一个.xcodeproj文件,是没有.xcworkspace文件的。

而很多的项目都采用了cocoapods来管理项目,这个时候是有.xcworkspace文件的,cocoapods通过xcworkspace来管理了第三方库。

这两种结构的参数配置是不一样的。(因为写脚本的时候有区别)

# 是否编译工作空间 (例:若是用Cocopods管理的.xcworkspace项目,赋值true;用Xcode默认创建的.xcodeproj,赋值false)is_workspace="false"# .xcworkspace的名字,如果is_workspace为true,则必须填。否则可不填workspace_name=""# .xcodeproj的名字,如果is_workspace为false,则必须填。否则可不填project_name="AutoPackageScriptDemo"# 指定项目的scheme名称(也就是工程的target名称),必填scheme_name="AutoPackageScriptDemo"

注释其实已经写得很清楚了。举个例子,github上的workspace_demo是通过.xcworkspace来管理的:

need-to-insert-img

通过.xcworkspace来管理

need-to-insert-img

项目的scheme_name为AutoPackageScriptDemo

所以这几个参数就是

is_workspace="true"workspace_name="AutoPackageScriptDemo"project_name=""scheme_name="AutoPackageScriptDemo"

否则,像github上面的project_demo里面的单工程结构就是

is_workspace="false"workspace_name=""project_name="AutoPackageScriptDemo"scheme_name="AutoPackageScriptDemo"

method,打包的方式。

证书签名的方式,是通过脚本中的method变量控制的。

分别为 development, ad-hoc, app-store, enterprise 。看到这几个参数估计都明白了吧?还不是不太了解的话建议看下蒲公英的这篇文档

# method,打包的方式。方式分别为 development, ad-hoc, app-store, enterprise 。必填method="development"

profile文件的管理方式

一般来说,证书管理方式,如今应该挺多人使用Xcode自动管理的。省心而且方便(老实说,由于工作原因,我平常比较少用自动管理,都是手动管理的,所以理解有误的话请提出)。

在Xcode->Preferrence->Account里面添加开发者账号,然后在工程的General->勾选Automatically manage signing->选择开发者账号。就可以自动管理了。

另外一种就是古老的手动管理方式了。

在开发者后台上面创建BundleID,然后创建mobileprovision文件,安装到Xcode上面选择使用。

针对这两种方式有不同的配置。

#  下面两个参数只是在手动指定Pofile文件的时候用到,如果使用Xcode自动管理Profile,直接留空就好# (跟method对应的)mobileprovision文件名,需要先双击安装.mobileprovision文件.手动管理Profile时必填mobileprovision_name=""# 项目的bundleID,手动管理Profile时必填bundle_identifier=""

注释讲得很清楚,使用Xcode自动管理profile的话直接留空就好了。

如果使用手动管理的话就需要填写对应的参数了。

源码解析

脚本代码其实很简单的。主要讲解一下关键代码。

先把源码放出来:

#!/bin/sh# 使用方法:# step1: 将该脚本放在工程的根目录下(跟.xcworkspace文件or .xcodeproj文件同目录)# step2: 根据情况修改下面的参数# step3: 打开终端,执行脚本。(输入sh ,然后将脚本文件拉到终端,会生成文件路径,然后enter就可)# =============项目自定义部分(自定义好下列参数后再执行该脚本)=================== ## 是否编译工作空间 (例:若是用Cocopods管理的.xcworkspace项目,赋值true;用Xcode默认创建的.xcodeproj,赋值false)is_workspace="false"# .xcworkspace的名字,如果is_workspace为true,则必须填。否则可不填workspace_name=""# .xcodeproj的名字,如果is_workspace为false,则必须填。否则可不填project_name="AutoPackageScriptDemo"# 指定项目的scheme名称(也就是工程的target名称),必填scheme_name="AutoPackageScriptDemo"# 指定要打包编译的方式 : Release,Debug。一般用Release。必填build_configuration="Release"# method,打包的方式。方式分别为 development, ad-hoc, app-store, enterprise 。必填method="development"#  下面两个参数只是在手动指定Pofile文件的时候用到,如果使用Xcode自动管理Profile,直接留空就好# (跟method对应的)mobileprovision文件名,需要先双击安装.mobileprovision文件.手动管理Profile时必填mobileprovision_name=""# 项目的bundleID,手动管理Profile时必填bundle_identifier=""echo"--------------------脚本配置参数检查--------------------"echo"\033[33;1mis_workspace=${is_workspace}"echo"workspace_name=${workspace_name}"echo"project_name=${project_name}"echo"scheme_name=${scheme_name}"echo"build_configuration=${build_configuration}"echo"bundle_identifier=${bundle_identifier}"echo"method=${method}"echo"mobileprovision_name=${mobileprovision_name}\033[0m"# =======================脚本的一些固定参数定义(无特殊情况不用修改)====================== ## 获取当前脚本所在目录script_dir="$( cd "$( dirname "$0"  )"&&pwd)"# 工程根目录project_dir=$script_dir# 时间DATE=`date '+%Y%m%d_%H%M%S'`# 指定输出导出文件夹路径export_path="$project_dir/Package/$scheme_name-$DATE"

# 指定输出归档文件路径

export_archive_path="$export_path/$scheme_name.xcarchive"

# 指定输出ipa文件夹路径

export_ipa_path="$export_path"

# 指定输出ipa名称

ipa_name="${scheme_name}_${DATE}"

# 指定导出ipa包需要用到的plist配置文件的路径

export_options_plist_path="$project_dir/ExportOptions.plist"

echo "--------------------脚本固定参数检查--------------------"

echo "\033[33;1mproject_dir=${project_dir}"

echo "DATE=${DATE}"

echo "export_path=${export_path}"

echo "export_archive_path=${export_archive_path}"

echo "export_ipa_path=${export_ipa_path}"

echo "export_options_plist_path=${export_options_plist_path}"

echo "ipa_name=${ipa_name}\033[0m"

# =======================自动打包部分(无特殊情况不用修改)====================== #

echo "------------------------------------------------------"

echo "\033[32m开始构建项目  \033[0m"# 进入项目工程目录cd${project_dir}# 指定输出文件目录不存在则创建if [ -d "$export_path" ] ; then    echo$export_pathelse    mkdir -pv$export_pathfi# 判断编译的项目类型是workspace还是projectif$is_workspace; then# 编译前清理工程xcodebuild clean -workspace${workspace_name}.xcworkspace \                -scheme${scheme_name}\                -configuration${build_configuration}xcodebuild archive -workspace${workspace_name}.xcworkspace \                  -scheme${scheme_name}\                  -configuration${build_configuration}\                  -archivePath${export_archive_path}else# 编译前清理工程xcodebuild clean -project${project_name}.xcodeproj \                -scheme${scheme_name}\                -configuration${build_configuration}xcodebuild archive -project${project_name}.xcodeproj \                  -scheme${scheme_name}\                  -configuration${build_configuration}\                  -archivePath${export_archive_path}fi#  检查是否构建成功#  xcarchive 实际是一个文件夹不是一个文件所以使用 -d 判断if [ -d "$export_archive_path" ] ; then

    echo "\033[32;1m项目构建成功 🚀 🚀 🚀  \033[0m"

else

    echo "\033[31;1m项目构建失败 😢 😢 😢  \033[0m"

    exit 1

fi

echo "------------------------------------------------------"

echo "\033[32m开始导出ipa文件 \033[0m"

# 先删除export_options_plist文件

if [ -f "$export_options_plist_path" ] ; then

    #echo "${export_options_plist_path}文件存在,进行删除"    rm -f$export_options_plist_pathfi# 根据参数生成export_options_plist文件/usr/libexec/PlistBuddy -c  "Add :method String${method}"$export_options_plist_path/usr/libexec/PlistBuddy -c  "Add :provisioningProfiles:"$export_options_plist_path/usr/libexec/PlistBuddy -c  "Add :provisioningProfiles:${bundle_identifier}String${mobileprovision_name}"$export_options_plist_pathxcodebuild  -exportArchive \            -archivePath${export_archive_path}\            -exportPath${export_ipa_path}\            -exportOptionsPlist${export_options_plist_path}\            -allowProvisioningUpdates# 检查ipa文件是否存在if [ -f "$export_ipa_path/$scheme_name.ipa" ] ; then

    echo "\033[32;1mexportArchive ipa包成功,准备进行重命名\033[0m"

else

    echo "\033[31;1mexportArchive ipa包失败 😢 😢 😢    \033[0m"    exit 1fi# 修改ipa文件名称mv$export_ipa_path/$scheme_name.ipa$export_ipa_path/$ipa_name.ipa# 检查文件是否存在if [ -f "$export_ipa_path/$ipa_name.ipa" ] ; then

    echo "\033[32;1m导出${ipa_name}.ipa 包成功 🎉  🎉  🎉  \033[0m"    open$export_pathelse    echo "\033[31;1m导出${ipa_name}.ipa 包失败 😢 😢 😢    \033[0m"

    exit 1

fi

# 删除export_options_plist文件(中间文件)

if [ -f "$export_options_plist_path" ] ; then

    #echo "${export_options_plist_path}文件存在,准备删除"    rm -f$export_options_plist_pathfi# 输出打包总用时echo "\033[36;1m使用AutoPackageScript打包总用时:${SECONDS}s \033[0m"

exit 0

clean工程

以单工程项目为例(wordspace结构是相似的),参数配置完成之后,clean下工程,用以清除缓存,保证我们的项目是纯净的。

跟我们在Xcode中Product->Clean这个命令是一样的功能。

xcodebuild clean -project${project_name}.xcodeproj \                -scheme${scheme_name}\                -configuration${build_configuration}

project_name就是我们之前配置的工程的名称,

scheme_name就是之前配置的工程的target名称

build_configuration为之前配置的设置,Debug或者Release

以我们demo中的单工程为例,就是这样的

xcodebuildclean-projectAutoPackageScriptDemo.xcodeproj-schemeAutoPackageScriptDemo-configurationRelease

archive工程

build工程,然后archive到一个文件夹里面。

xcodebuild archive -project${project_name}.xcodeproj \                  -scheme${scheme_name}\                  -configuration${build_configuration}\                  -archivePath${export_archive_path}

其中, export_archive_path就是我们存放archive结果的文件夹。

这条命令执行以后,会在指定的位置生成.xcarchive文件(其实这个是文件夹来的。里面会有.app包和dSYM符号文件等内容)

以我们的单工程demo为例:

export_archive_path=/Users/mac/Desktop/简书/AutoPackageScript/project_demo/AutoPackageScriptDemo/Package/AutoPackageScriptDemo_20180108/AutoPackageScriptDemo.xcarchivexcodebuild archive -project AutoPackageScriptDemo.xcodeproj -scheme AutoPackageScriptDemo -configuration Release -archivePath ${export_archive_path}

need-to-insert-img

命令执行成功会生成.xcarchive文件

need-to-insert-img

.xcarchive文件里面的内容

exportArchive,从xcarchive中导出ipa包

将刚才archive出来的.xcarchive文件,导出成一个ipa包。

xcodebuild  -exportArchive \            -archivePath${export_archive_path}\            -exportPath${export_ipa_path}\            -exportOptionsPlist${export_options_plist_path}\            -allowProvisioningUpdates

export_archive_path就是刚才导出.xcarchive文件路径

export_ipa_path是要导出的ipa文件的文件夹路径

export_options_plist_path这是一个plist配置文件路径。这个plist配置文件是必须的,不加的话会报错的。经过我的测试发现,主要是需要配置method这个key。如果是手动管理的话,还需要配置bundleID和mobileprovision_name。其他的key是可以不配置的,如果不配置的话,会自动根据项目里面的配置进行生成。另外,这个文件我在脚本中用PlistBuddy命令直接生成了,不需要用户自己指定文件。

-allowProvisioningUpdates主要目的是自动更新profile文件,在Xcode自动管理profile的时候用。

以我们的单工程demo为例:

export_ipa_path=/Users/mac/Desktop/简书/AutoPackageScript/project_demo/AutoPackageScriptDemo/Package/AutoPackageScriptDemo_20180108export_options_plist_path=/Users/mac/Desktop/简书/AutoPackageScript/project_demo/AutoPackageScriptDemo/ExportOptions.plistxcodebuild  -exportArchive \            -archivePath ${export_archive_path} \            -exportPath ${export_ipa_path} \            -exportOptionsPlist ${export_options_plist_path} \            -allowProvisioningUpdates

其中,ExportOptions.plist配置文件我只设置了method 。

need-to-insert-img

ExportOptions.plist配置文件

命令执行成功之后会生成我们需要的ipa文件和其他的几个东西。

need-to-insert-img

exportArchive成功之后生成的文件

其中,

ipa文件就是我们需要的安装包。

DistributionSummary.plist文件是一些详细的签名信息。

ExportOptions.plist文件其实就是我们在exportArchive命令时要用的,但在exportArchive之后会自动生成一个完整的文件。如果不知道该怎么写这个配置文件的话,可以直接参考我demo中生成的这个plist文件。

Packaging.log这个文件就是打包的时候产生的log了,可以查看日志记录。

参考

脚本和demo都放到github上面去了。https://github.com/shixueqian/AutoPackageScript

本脚本主要参考了自动打包ipa文件并上传fir.im托管平台的shell脚本

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

推荐阅读更多精彩内容