持续集成系列 - Xcode 的脚本世界

基础知识

现在有两个需求:

  • 打一个 AdHoc 测试包,发送给测试人员进行测试
  • 打一个 生产包,上线 ITC

以上如果人工手动操作,挺耗时耗力的,而自动化则可以完美解决.自动化打包包括两种途径:

  • 使用 Apple 自出品的脚本语言: AppleScript;
  • 使用 shell 或者 python

以下的操作基本是基于 Xcode 自带的命令行工具: Command Line Tools ,其包含两个重要的工具: xcodebuild 和 xcrun.相关工具及概念如下:

  • xcodebuild 主要用于编译和打包,$ xcodebuild -help 可以查看用法
  • xcrun 主要用于打包 xcrun -h
  • 以及 altool ,用于上传二进制文件到 ITC
  • Workspace、Project、Scheme、Target的区别:

Workspace: 是最大的集合,可以包含多个Project,可以管理不同的Project之间的关系.Workspace是以xcworkspace的文件形式存在的(和Project一致).Workspace的存在是为了解决原来仅有Project的时候不同的Project之间的引用和调用困难的问题.同时,一个Workspace的Project共用一个编译路径。比如使用CocoaPod或者使用其他开发库\框架.

Project: 是一个仓库,包含编译一个或多个product所需的文件\资源和信息,保持和聚合这些元素间的关系(每个Target能指定自己的Build Settings来覆盖Project),一般包含的内容如下:

Source code, including header files and implementation files Libraries and frameworks, internal and external Resource files Image files Interface Builder (nib) files

Scheme: 包含了一些要构建的Scheme,一些构建时用到的设置,一些要运行的测试.同时只能有一个Scheme是有效的.

Target: 是对应了具体一个想要构建的Product,包含了一些构建这个Product所需的配置和文件(build settings和build phases).一个Project可以包含多个Target.

1. 嵌入 Xcode 项目的脚本
  • 脚本的位置:

Build Phases -> 点击左上角+ -> 添加 Run Script (运行脚本) -> 添加脚本即可 374E29EC-49D9-4348-BA45-56B665CA4448.png 81EB716F-2F50-426D-BDBF-C0E2C1EF566E.png

默认的是 shell 脚本.需要修改成 py 脚本.

# 查看 python 解释器的位置:
$ whereis python
/usr/bin/python
  • 首先将上方的脚本解释器 由 /bin/sh 修改为 /usr/bin/python

  • 然后添加脚本:在编译时,修改一个main.cpp文件的内容:

#-*- coding:utf-8 -*-
import os
cppfile = open('/Users/jiangxiaocai/Desktop/Test/main.cpp','w')
outstr = "// 修改.cpp 文件"
cppfile.write(outstr)
cppfile.close()

C34DFE25-2477-457F-B57A-26D805A55F96.png 06809A1C-87D3-4E9F-AC10-4FFB63193CE6.png

2. Xcodebuild
# 功能选项没有放进来,主要是用于编译的命令

Available keys for -exportOptionsPlist:

    compileBitcode : Bool

        # For non-App Store exports, should Xcode re-compile the app from bitcode? Defaults to YES.

    embedOnDemandResourcesAssetPacksInBundle : Bool

        # For non-App Store exports, if the app uses On Demand Resources and this is YES, asset packs are embedded in the app bundle so that the app can be tested without a server to host asset packs. Defaults to YES unless onDemandResourcesAssetPacksBaseURL is specified.

    iCloudContainerEnvironment

        # For non-App Store exports, if the app is using CloudKit, this configures the "com.apple.developer.icloud-container-environment" entitlement. Available options: Development and Production. Defaults to Development.

    manifest : Dictionary

        # For non-App Store exports, users can download your app over the web by opening your distribution manifest file in a web browser. To generate a distribution manifest, the value of this key should be a dictionary with three sub-keys: appURL, displayImageURL, fullSizeImageURL. The additional sub-key assetPackManifestURL is required when using on demand resources.

    method : String

        # Describes how Xcode should export the archive. Available options: app-store, ad-hoc, package, enterprise, development, and developer-id. The list of options varies based on the type of archive. Defaults to development.

    onDemandResourcesAssetPacksBaseURL : String

        # For non-App Store exports, if the app uses On Demand Resources and embedOnDemandResourcesAssetPacksInBundle isn't YES, this should be a base URL specifying where asset packs are going to be hosted. This configures the app to download asset packs from the specified URL.

    teamID : String

        # The Developer Portal team to use for this export. Defaults to the team used to build the archive.

    thinning : String

        # For non-App Store exports, should Xcode thin the package for one or more device variants? Available options: <none> (Xcode produces a non-thinned universal app), <thin-for-all-variants> (Xcode produces a universal app and all available thinned variants), or a model identifier for a specific device (e.g. "iPhone7,1"). Defaults to <none>.

    uploadBitcode : Bool

        # For App Store exports, should the package include bitcode? Defaults to YES.

    uploadSymbols : Bool

        # For App Store exports, should the package include symbols? Defaults to YES.

脚本打包

一般来说实现实现方式有两种:

  • xcodebuild 和 xcrun 实现:

xcodebuild -workspace XXX -scheme XXX -configuration Release

xcrun -sdk iphoneos PackageApplication -v “/XXX/XXX.app” -o “/XXX/XXX”

  • xcodebuild 和 exportOptionsPlist 实现:

准备两个Plist文件,用于导出不同ipa包时使用

获取命令行参数,区分上传到Fir还是App Store

清理构建目录

编译打包

导出包

上传到Fir或者验证并上传到App Store

发邮件通知

下边是基于第二种方式的方法: 首先因为不了解这种自动化打包,所以要看官方的资料,最直接的方式就是: $ xcodebuild -help,得知如下信息:

Available keys for -exportOptionsPlist:以下每个 key 的详细解释可以$ xcodebuild -help查看即可.

  • 测试包导出: compileBitcode\embedOnDemandResourcesAssetPacksInBundle\iCloudContainerEnvironment\manifest\onDemandResourcesAssetPacksBaseURL\thinning
  • 用于 App Store 导出: uploadBitcode\uploadSymbols
  • 共用: method\teamID
  • method 可选值: app-store\ package\ ad-hoc\ enterprise\ development and developer-id

步骤为:

1.准备Plist文件:
AppStoreExportOptions.plist: method=app-store,uploadBitcode=YES,uploadSymbols=YES
AdHocExportOptions.plist: method=ad-hoc,compileBitcode=NO

xcodebuild -exportArchive -archivePath ./xxx.xcarchive -exportOptionsPlist ./AdHocExportOptions.plist -exportPath ./

脚本打测试包
脚本打生产包

shell 脚本打包实战

这里参考了 博文,代码

备份脚本

下载完脚本之后,解读如下:

ipa-build:  编译xcode工程并生成ipa文件
ipa-publish: 生成符合itms-services协议的文件,并发布到服务器
sendEmail:  stmp发送email的脚本
sftpDownloadFile: 通过sftp协议下载文件
sftpUploadFile: 通过sftp协议上传文件
updateLocalIndexHtml:  对索引文件进行处理(二进制文件,非shell脚本)
uploadItemsServicesFiles:   将itms-services协议文件上传到服务器

而实际使用的脚本是: ipa-build 和 ipa-publish ,其他文件是,ipa-publish这个脚本调用的依赖文件

ipa-build 使用方法如下:

# 1. $ cd ipa-build 所在的目录
# 2. 执行脚本:sh ipa-build 绝对路径 ipa类型(Debug\ AdHoc\Release\Distribution)
$ sh ipa-build /Users/guoyinjinrong1/Git_Projecrt/JenkinsTest AdHoc

ipa-build 脚本运行后,会在 iOS 工程根路径下生成名为 “build” 的文件夹,在这个文件夹中又有一个名为 “ipa-build” 的文件夹,打包所生成的最新 ipa 包就在其中.

ipa-publish 使用方法如下:

# 1. $ cd ipa-build 所在的目录
# 2. 执行脚本:sh ipa-build 绝对路径 ipa类型 打包 ipa(如果已经生成过,忽略)
# 3. 上传 ftp.
$ sh ipa-build /Users/guoyinjinrong1/Git_Projecrt/JenkinsTest AdHoc

支持一下

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码支持一下

打开支付宝扫一扫,即可进行扫码打赏哦