因为需要,最近在研究用脚本编译.ipa文件,在网上查找了不少资料,发现都是一些比较旧的操作了,在应用的时候难免会有一些问题。不过综合网上的各种说法和苹果最新的官方文档还是得到一个最终结果,记录下来,方便日后的使用。
1. 工具
- xcodebuild简介
xcodebuild
是苹果提供的打包项目或者工程的命令,可以使用man xcodebuild
或者xcodebuild -help
来了解该命令的具体操作与用法。
DESCRIPTION
xcodebuild builds one or more targets contained in an Xcode project, or builds a scheme contained in an Xcode workspace or Xcode project.
Usage
To build an Xcode project, run xcodebuild from the directory containing your project (i.e. the directory containing the name.xcodeproj package). If you have multiple projects in the this directory you will need to use -project to indicate which project should be built. By default, xcodebuild builds the first target listed in the project, with the default build configuration. The order of the targets is a property of the project and is the same for all users of the project.
To build an Xcode workspace, you must pass both the -workspace and -scheme options to define the build. The parameters of the scheme will control which targets are built and how they are built, although you may pass other options to xcodebuild to override some parameters of the scheme.
There are also several options that display info about the installed version of Xcode or about projects or workspaces in the local directory, but which do not initiate an action. These include -list, -showBuildSettings, -showsdks, -usage, and -version.
- xcodebuild用法
SYNOPSIS
xcodebuild [-project name.xcodeproj] [[-target targetname] ... | -alltargets] [-configuration configurationname] [-sdk [sdkfullpath | sdkname]] [action ...] [buildsetting=value ...] [-userdefault=value ...]
xcodebuild [-project name.xcodeproj] -scheme schemename [[-destination destinationspecifier] ...] [-destination-timeout value] [-configuration configurationname] [-sdk [sdkfullpath | sdkname]] [action ...] [buildsetting=value ...] [-userdefault=value ...]
xcodebuild -workspace name.xcworkspace -scheme schemename [[-destination destinationspecifier] ...] [-destination-timeout value] [-configuration configurationname] [-sdk [sdkfullpath | sdkname]] [action ...] [buildsetting=value ...] [-userdefault=value ...]
xcodebuild -version [-sdk [sdkfullpath | sdkname]] [infoitem]
xcodebuild -showsdks
xcodebuild -showBuildSettings [-project name.xcodeproj | [-workspace name.xcworkspace -scheme schemename]]
xcodebuild -list [-project name.xcodeproj | -workspace name.xcworkspace]
xcodebuild -exportArchive -archivePath xcarchivepath -exportPath destinationpath -exportOptionsPlist path
xcodebuild -exportLocalizations -project name.xcodeproj -localizationPath path [[-exportLanguage language] ...]
xcodebuild -importLocalizations -project name.xcodeproj -localizationPath path
比较常用的有:
- xcodebuild -list:可以查看Targets、Schemes、以及Configuration,这几个参数会在后续操作中用到。
- xcodebuild -showsdks:查看Xcode 所有可用的 SDKs信息。
-
xcodebuild -showBuildSettings:查看project所有的配置信息,已有的配置参数可以在build时添加
buildsetting=value
进行覆盖重新设置。 - xcodebuild [-project name.xcodeproj] -scheme:build指定的project。
- xcodebuild -workspace name.xcworkspace -scheme:build 指定 workspace,与上一条功能相同,看到有人说用到CocoaPod时会生成.xcworkspace文件,故而需要采用该方法。但是我发现没有使用CocoaPod时,也可以找到xxx.xcodeproj/project.xcworkspace文件,也可以使用该方法,而且得到的结果和第3条并没有什么差异。对此,本人还没什么深入研究,知道详情的大牛可以解释下当然更好啦~~~
- xcodebuild -exportArchive -archivePath:打包生成.ipa文件,需要在上述3/4步操作后执行。
注:在第3/4条操作时,需要添加一个参数[action ...]
,该参数有如下几种选择:
Specify one or more actions to perform. Available actions are:
build
Build the target in the build root (SYMROOT). This is the default action, and is used if no action is given.
build-for-testing
Build the target and associated tests in the build root (SYMROOT). This will also produce an xctestrun file in the build root. This requires specifying a scheme.
analyze
Build and analyze a target or scheme from the build root (SYMROOT). This requires specifying a scheme.
archive
Archive a scheme from the build root (SYMROOT). This requires specifying a scheme.
test
Test a scheme from the build root (SYMROOT). This requires specifying a scheme and optionally a destination.
test-without-building
Test compiled bundles. If a scheme is provided with -scheme then the command finds bundles in the build root (SRCROOT). If an xctestrun file is provided with -xctestrun then the command finds bundles at paths specified in the xctestrun file.
install-src
Copy the source of the project to the source root (SRCROOT).
install
Build the target and install it into the target's installation directory in the distribution root (DSTROOT).
clean
Remove build products and intermediate files from the build root (SYMROOT).
注:如果xcodebuild之后的内容涉及两种用法,ie:xcodebuild -project xxx.xcodeproj -scheme xxx clean build -showsdks
。当出现这种情况时,编译器只会执行后一种用法,也就是说示例中的操作在终端中执行后,不会build project,只会输出SDKs的信息。
2. 实现
- 旧方法
首先说一下找到的第一种方法,试了一下,确实是可以编出ipa包的,安装之后似乎也没有什么问题,至少生成的ipa文件安装到手机上之后APP的功能都运行正常。
该方法的操作是:切换到项目xxx.xcodeproj所在文件夹下,并在终端执行以下两句
$ xcodebuild -project 'xxx.xcodeproj' -target 'xxx' -configuration 'Release' -sdk 'iphoneos' build
$ xcrun -sdk 'iphoneos' -v PackageApplication './build/Release-iphoneos/xxx.app' -o '~/Desktop/xxx.ipa'
注:其中,单引号标示的内容是需要按照自己的项目进行更换的。
但是该方法主要的问题是,成功之后会有一条警告信息:
warning: PackageApplication is deprecated, use `xcodebuild -exportArchive` instead.
既然已经提示该方法被废弃,并由其他方法所替代,所以暂时就不考虑该方法了。
- 当前最新方法
接下来就是按照提示去查找最新可用的方法了。现在测试,该操作是可以成功编译出.ipa文件,并且安装之后APP操作都运行正常,最重要的是编译的时候没有要命的警告_。
该方法的操作是:切换到项目xxx.xcodeproj所在文件夹下,并在终端执行以下两句
$ xcodebuild -project 'xxx.xcodeproj' -scheme 'xxx' -configuration 'Release' -arch 'arm64' archive -archivePath '$PWD/build/xxx.xcarchive'
$ xcodebuild -exportArchive -archivePath '$PWD/build/xxx.xcarchive' -exportOptionsPlist 'export.plist' -exportPath '$PWD/build'
注:其中,单引号标示的内容是需要按照自己的项目进行更换的。
在第一步操作结束后,会看到** BUILD SUCCEEDED **
信息,表示编译成功。同时,向上拖动一段输出信息,可以看到以下两句信息:
Signing Identity: "iPhone Developer: UserName (User-Id)"
Provisioning Profile: "iOS Team Provisioning Profile: Bundle-Id"
(b1xxxx-xxxx-xxxx-xxxx-xxxxxx)
该信息是文件的签名信息,可以在第一步中以buildsetting=value
的方式进行设置,具体内容可以在Keychain Access -> Certificates -> 选中iPhone Developer:UserName(User-Id)证书右键弹出菜单 -> Get Info 中获取。
注:该操作中最重要的一点是对于export.plist
文件的配置,查看官方文档,里边有一段说明:
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, package, ad-hoc, 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.
有很多参数是不必要的,现在查看teamID和method似乎是比较需要的,写了一个示例:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>ad-hoc/enterprise/development</string>
<key>teamID</key>
<string>YOU_DISTRIBUTION_TEAM_ID</string>
<key>compileBitcode</key>//暂不支持bitcode
<string>NO</string>
</dict>
</plist>
因为我这边主要是企业账号开发,所以method是上述三项三选一。如果是个人账号,需要上传到App Store,需要设置method=app-store。
关于TeamID,可以去Keychain Access -> Certificates -> 选中前缀为iPhone Distribution:XXX的证书右键弹出菜单 -> Get Info 中获取组织ID即可。
3. 脚本文件
我是使用Makefile来编译ipa的,存放Makefile文件在xxx.xcodeproj所处文件夹下,然后直接执行make来编译,主要使用的就是这两句操作,所以在此就不给文件的示例了。
如果您需要shell脚本执行,可以自己写个.sh脚本哈,主要输入就是xxx.xcodeproj文件存放路径和ProjectName两项,其他需求可以针对不同情况随时调整。本人对脚本的研究还有点欠缺,就不在此献丑了。