xcodebuild 脚本打包导出错误

iOS 工程在云服务器打包, 打普通的体验包没问题, 但是打 TestFlight 包就报错, 错误日志如下

1
2
3
4
IDEDistribution: -[IDEDistributionLogging _createLoggingBundleAtPath:]: Created bundle at path '/var/folders/rw/4zvtml0922j4k36bbjxbny380000gp/T/App_2022-03-03_18-38-20.927.xcdistributionlogs'.
xcodebuild[39445:78833] [MT] IDEDistributionMethodManager: -[IDEDistributionMethodManager orderedDistributionMethodsForTask:archive:]: Error = Error Domain=IDEDistributionMethodManagerErrorDomain Code=2 "Unknown Distribution Error" UserInfo={NSLocalizedDescription=Unknown Distribution Error}
exportArchive: exportOptionsPlist error for key 'method': expected one of {}, but found app-store
Error Domain=IDEFoundationErrorDomain Code=1 "exportOptionsPlist error for key 'method': expected one of {}, but found app-store" UserInfo={NSLocalizedDescription=exportOptionsPlist error for key 'method': expected one of {}, but found app-store}

从上面日志粗略看是编译错误, 搜索相关的错误描述, 网上会有不少相关案例, 在问题分析定位结束后, 解决方案是这一个xcodebuild -exportArchive: exportOptionsPlist error for key ‘method’: expected one of {}, 将子工程的 SKIP_INSTALL 设置为 YES. 但是要注意的是 子工程的 Project 设置以及 Target 设置都应该设置为 YES, 我一开始只设置了 Target 的, 子工程 Project 设置的 SKIP_INSTALL 未设置, 默认值是 NO, 导致后续浪费了很多时间. 以及移除子工程中 “Build Phase” 的’Headers’选项, 两个改动后 tf 可以正常打包.

正常问题溯源步骤

编译问题出错的原因会有很多, 但是应该如何定位具体原因

TestFlight 有什么特殊的?

  1. 我们工程的 TestFlight 打包使用的 archieve 模式, 跟最终提交到 AppStore 一样
  2. 普通的体验包是 build 模式, 打包脚本主要是基于 xcodebuild 工具编写, 其他差异不大.
  3. TestFlight 使用的证书和本地调试/普通的体验包不一样.

怎么在本地打 TestFlight 包

  1. 下载 TestFlight 证书并安装
  2. 工程目录下执行打包命令 xcodebuild archive -workspace App.xcworkspace -scheme AppScheme -configuration TestFlight -derivedDataPath ./DerivedData -archivePath ./Archive/App.xcarchive -verbose 进行打包 最后会在Archive目录下生成App.xcarchive 文件
  3. 继续执行导出命令 xcodebuild -exportArchive -archivePath ./Archive/App.xcarchive -exportPath result/ -exportOptionsPlist ./Path_To_Archive_Option.plist, 会从App.xcarchive 导出 App.iparesult目录下.

定位问题

导出失败原因

使用出问题的提交记录前后各执行一次上述步骤, 打包成功但是导出失败, 因此比较App.xcarchive 有什么不一样的, 对比后发现Archive/App.xcarchive/Info.plist 这个文件丢失了 applicationproperties 字段, 在出错的 Archive 中覆盖正确的 Info.plist 可以导出成功. 确定问题为打包过程中Info.plist字段缺失.

TestFlight 打包 Info.plist 字段缺失原因

现在知道 TestFlight 失败的直接原因了, 以 “xcodebuild info.plist applicationproperties missing” 为关键词搜索, 确定了最后的修复方法:

  1. 子工程 skip_install置为 YES, 参考 so 回答
  2. 移除子工程中 “Build Phase” 的 ‘Headers’ 这一项. 由于我们主工程引用子工程是使用一个 LocalPod 来实现, 在 podspec 文件中指定子工程的路径, 以达成主工程引用子工程文件的目的, 这样就不需要设置主工程的 HeaderSearchPath.
  3. 以上两步修改完成后, TestFlight 包导出正常, 问题修复.

xcodebuild 常用命令

细节查看man xcodebuild即可, 下面记录常用的一些命令

xcodebuild -version

查看 Xcode 版本

xcodebuild -showsdks

列出 Xcode 所有可用的 sdk 信息

xcodebuild -list

列出当前目录下工程的信息, 包括 Target 列表(App, Today, WatchExtension, NotificationService 等), 可用配置Configurations(Debug/Release 等), 以及 Schemes.

xcodebuild -showBuildSettings

返回当前的构建

打包相关命令(action)

action 作用
build 默认选项, 构建Target
analyze 构建并分析 target 或者 scheme,需要指定一个 scheme
archive 从构建目录(SYMROOT) 存档, 也需要指定一个 scheme
clean 从构建目录SYMROOT)删除构建产物和中间文件

打包的方法

1. build Action
1
2
3
4
5
6
xcoderun build \
-workspace "App.xcworkspace" \
-scheme "AppScheme" \
-configuration "Debug/Release/..." \
-derivedDataPath "DerivedDataPath" \
-verbose

然后生成 ipa 文件

1
2
3
4
5
mkdir -p ResultDir/Payload
productDir=DerivedDataPath/Build/Products/App-iphoneos
cp -R ${productDir}/App.app ResultDir/Payload
cd ResultDir
zip -qry App.ipa Payload
2. archieve Action
1
2
3
4
5
6
7
xcoderun archive \
-workspace "App.xcworkspace" \
-scheme "AppScheme" \
-configuration "Debug/Release/..." \
-derivedDataPath "DerivedDataPath" \
-archivePath "ArchiveFilePath" \
-verbose

存档后导出,

1
2
3
4
xcoderun -exportArchive \
-archivePath "ArchiveFilePath" \
-exportPath "ResultDir" \
-exportOptionsPlist "exportOptionsPlistPath"
-------------本文结束感谢您的阅读-------------

欢迎关注我的其它发布渠道