iOS批量自动打包和部署(Ⅱ):自动打包

网上有大把的文章讲了自动打包,其实无非就是那几条命令,但是我觉得有必要继续了解一下一个app包(即应用)的组成和app可执行文件的构建过程。这个里面非常复杂,也参考了一些文章,仅将自己了解的大概梳理出来备忘。

应用的构建过程和组成

想象一下平时的打包过程,在Xcode中选择对应的appid,bundleid,还要选择正确的配置文件(provisioning profile),然后点击run,我们看到Xcode上面有内容在不断的更新,正如猜想的,更新的内容实际就是app包编译的过程。

这个过程大概经过了:配置(编译器确定当前系统环境)-> 确定标准库和头文件的位置->确定依赖关系->头文件预编译(precompilation)->预处理(preprocessing)->编译(compilation)->连接(Linking)->打包,大致步骤是这些,但其中还有一些过程是没有讲的。

对于iOS的包来讲,在构建完成之后还会自动调用codesign命令进行签名,这个时候我们之前选择的bundleid啊,配置文件啊等等就排上用场了。经过签名后的应用是个相对来讲安全的应用,通过签名确保了包的来源合法,也能确保包的内容是否被修改过(理论知识上篇已讲过)。最后的包的本质实际上是一个Mach-O格式的二进制可执行文件(签名的数据就在这个二进制文件中)和一些资源文件。

Mach-O可执行文件

Mach是一种操作系统内核。它的大致历史是:Mach内核被NeXT公司的NeXTSTEP操作系统使用,NeXT是乔布斯苹果被赶出苹果后创建的公司。1996年,乔布斯将NeXTSTEP带回苹果,成为了OS X的内核基础。在Mach上,一种可执行的文件格是就是Mach-O(Mach Object file format)。iOS是从OS X演变而来,所以同样支持Mach-O格式的可执行文件。

搞iOS的肯定知道ipa包,它实际上就是一个zip压缩包,可以用mac自带的归档解压工具进行解压。解压之后会有一个Payload文件夹,其中有个XXX.app这样的.app文件,它实际上是文件夹,它里面除了有个各种资源、图片等,还有个和包名相同的文件——这个就是二进制可执行文件。可以用file命令查看文件类型,下图是微信包的截图:
wechat file

从上面看是支持arm7和arm64两种处理器架构的通用程序包,里面的格式是Mach-O。将微信的可执行文件WeChat用Sublime打开,二进制开始部分如下:

wechat file

开头的4个字节是cafebabe,这被称为“魔数”,反映文件的类型。查了下相关文章,OS X上还有如下几个标识:

cafebabe
feedface
feadfacf
还有一个格式,就是以#!开头的脚本

cafebabe就是跨处理器架构的通用格式,feedface和feedfacf则分别是某一处理器架构下的Mach-O格式,脚本的就很常见了,比如#!/bin/bash开头的shell脚本。

Mach-O可执行文件包含头部信息和加载命令。才疏学浅,这部分也没有深入了解,本篇也无法继续深入讲这块了。

其他资源文件

解压后的包中除了可执行文件还有其他资源文件,图片啊,plist啊等等。苹果对安全确实重视,这些资源文件其实大多数也是需要被设置签名的,可以见到的是包中还有一个_CodeSignature文件夹,这个文件夹中的CodeResources文件中存储了被签名的程序包中所有需要被签名文件的签名。更详细的介绍参见《代码签名探析》,从这些细节不难看出苹果对于安全的重视。

自动打包

苹果自带的xcodebuild命令行工具就可以打包,但是这里我更加推荐facebook出品的xctool,xctool的初衷就是要替代苹果的xcodebuild,它们的命令参数都是一样的,相比较xcodebuild,xctool有以下特点:

1.相比较xcodebuild输出的log杂乱,xctool更有结构
2.xctool有人性化的颜色输出
3.facebook声称xctool更快,据说能快2、3倍
4.完全用Ojbective-C实现

当然xctool只支持Xcode6及以上,并且Xcode Command Line Tools安装好。

xctool

xctool是可以使用homebrew安装的,或者下源码然后运行 xctool.sh脚本,homebrew安装命令如下:

brew install xctool

实战

接下来是实战篇,按照我的设想,如果想要实现自动化,需要攻克几个点:

1.自动打包
2.重新签名
3.分发部署

其中,自动打包是基础,打包完之后可以根据母包重新签名生成相似的包,生成的包可以自动部署。只要攻克这三个点就能实现全自动化,当然就需要写脚本了,带着这个性质我参考了一些文章并且在网上找到了一些脚本。最终,验证了这些东西都是实际可行的。但,下面的实战用到的脚本,一部分是网上找的,一部分是同事写的,当时虽然逐个研究了但是却没有精力在这个上,这部分的工作最后是同事做的。

为了讲的更清楚,新建了一个项目PackageExample(Demo已上传到这里),并且使用了CocoaPods(实验起见仅引用了AFNetworking),项目的证书是dev状态的。PackageExample项目在我机器上的路径和目录如下截图:

PackageExample同目录的还有PackageShell,里面的buildipa.sh为编译脚本,由于最后的目标是要做成可以随意配置的,所以还有一个PackageConfig文件夹,里面有配置文件packageExample.mobileprovisionpackageExample.plist,配置文件主要用来签名,plist文件的内容为可配置的,例如里面有app_Prefix、app_Name、app_ID等信息。Package文件夹为打的包的存放的地方。

完整的编译脚本如下:

#!/bin/sh

#从plist文件中读取ipa包名和配置文件名
profile_Name=`/usr/libexec/PlistBuddy -c "print profile_Name" ./PackageConfig/packageExample.plist`
ipa_Name=`/usr/libexec/PlistBuddy -c "print app_Name" ./PackageConfig/packageExample.plist`

#进入工程目录
cd ../PackageExample
echo "go to packageExample workspace path"

#报名时根据时间戳命名的,所以这里有用到
buildTime=$(date +%Y%m%d%H%M)

profile="${profile_Name}"

echo $profile $ipa_Name

#一下方法主要是创建打包的路径和最后导出的ipa的路径
if [ ! -d "../PackageShell/Package" ]; then
    mkdir ../PackageShell/Package
fi

if [ ! -d "../PackageShell/Package/ArchiveProduction" ]; then
    mkdir ../PackageShell/Package/ArchiveProduction
fi

if [ ! -d "../PackageShell/Package/ArchiveProduction/QA" ]; then
    mkdir ../PackageShell/Package/ArchiveProduction/QA
    echo "Create ArchiveProduction path"
fi

if [ ! -d "../PackageShell/Package/ipa" ]; then
    mkdir ../PackageShell/Package/ipa
fi

if [ ! -d "../PackageShell/Package/ipa/QA" ]; then
    mkdir ../PackageShell/Package/ipa/QA
    echo "Create ipa path"
fi

buildConfiguration="QA"

buildPath="../PackageShell/Package/ArchiveProduction/QA/${ipa_Name}_${buildTime}.xcarchive"
ipaName="../PackageShell/Package/ipa/QA/${ipa_Name}_${buildTime}.ipa"

#先进行clean操作
xctool -workspace PackageExample.xcworkspace -scheme PackageExample -configuration ${buildConfiguration} clean

#打包的命令
xctool -workspace PackageExample.xcworkspace -scheme PackageExample -configuration ${buildConfiguration} archive -archivePath ${buildPath}
#导出ipa包的命令,
xcodebuild -exportArchive -exportFormat IPA -archivePath ${buildPath} -exportPath ${ipaName} -exportProvisioningProfile "$profile"

做一些解释,脚本的开头有PlistBuddy命令,它是Mac下一个用来读写plist文件的工具,在/usr/libexec/下。xctool -workspace PackageExample.xcworkspace -scheme PackageExample -configuration ${buildConfiguration} clean,由于项目是workspace,所以这里必须要对应,如果是project则是project,clean的目的是进行清理缓存等。xctool -workspace PackageExample.xcworkspace -scheme PackageExample -configuration ${buildConfiguration} archive -archivePath ${buildPath}archive命令主要用来打包,最后包的格式为xcarchive。可以进入这个包里,目录结构如图:

主要是产生了 dsYM和 .app文件,并且可以看到的是它是已经经过签名的。虽然从命令中没有指定profile,但是我看到编译的log输出有以下这段:

Sign PackageExample.app,推测这步是进行签名了,至于为什么命令中没有指定也可以编译那是因为在Xcode中进行过手动设置(?:猜测是)。最后一步导入ipa主要用xcodebuild命令,至少在当时我找到的是这个命令而不是xctool。经过导出的ipa包,简单点的,可以邮件群发给同事进行测试。

小结

至此,差不多介绍完自动打包的一种方案。但其实还可以延伸,主要反映在两点上:

1.虽然能够成功打一个包,但是本系列文章第一篇开始部分中提到的,如何快速复制两个很相似但又不同的包?
2.导出来的ipa包,用邮件群发是否仍然麻烦,能否继续实现自动化?

上面的两点实际上都能很好的解决,也就是前面说到的要攻克2.重新签名 和 3.分发部署,下篇文章会介绍我的解决思路,里面涉及重新签名和一些上传工具。

转载于:https://my.oschina.net/hejunbinlan/blog/721184

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值