当前位置:   article > 正文

TN2339: 使用 Xcode 命令行构建的常见问题_xcode-select --switch

xcode-select --switch

Apple Developer Documentation Archive 是 Apple 已归档的开发者文档,具有很大的参考价值。adat 项目选取了一些典型文章进行翻译,摒弃了部分过时的内容,并在 Xcode 13.0 上进行实践。这是该项目的第一篇文章,后续文章将会逐步深入,探究使用命令行工具进行企业级构建的最佳实践。


内容概览

  • 命令行工具包是什么?
  • macOS 10.9 及以后的版本上的 Xcode 不再提供命令行工具下载入口,应该如何安装?
  • 如何卸载命令行工具?
  • 多个 Xcode 并存的情况下,如何查看命令行工具使用的 Xcode 版本?
  • 如何修改命令行工具使用的 Xcode 版本?
  • 如何使用命令行构建 Xcode 项目?
  • 如果有多个 Configurations ,如何给 xcodebuild 设置一个默认的 Configuration ?
  • 如何利用命令行实施单元测试?
  • 如何利用命令行实现 Xcode 中的 Build For Testing 和 Test Without Building 功能?
  • exportOptionsPlist 文件可以包含哪些配置?
  • 如何归档并导出应用?

命令行工具包是什么?

命令行工具包是一个小型的自包含工具包,可以独立下载,可以在 macOS 上进行命令行开发。它由 macOS SDK 和命令行工具(例如 Clang,位于 /Library/Developer/CommandLineTools)组成。


macOS 10.9 及以后的版本上的 Xcode 不再提供命令行工具下载入口,应该如何安装?

在 macOS 10.9 及以后的版本上,Xcode 的偏好设置中的下载面板不再支持命令行工具直接下载,可以使用下面任意一种方式来安装:

安装 Xcode

Xcode 已经包含命令行工具,因此只要安装了 Xcode,就无需额外安装命令行工具。

从 Apple 开发者网站下载

下载地址:https://developer.apple.com/download/all/,需要使用 Membership Account 登录,搜索并下载和系统版本匹配的命令行工具版本。
在这里插入图片描述

在 macOS 10.9 及以后,当有新的命令行版本可用时,将会收到软件更新的通知。

通过 Terminal 安装

在 Terminal 中执行如下命令进行安装:

xcode-select --install
  • 1

macOS 自带 xcode-select 命令,在 /usr/bin 目录下。


如何卸载命令行工具?

  • 删除 Xcode 应用
  • 删除 /Library/Developer/CommandLineTools 目录

多个 Xcode 并存的情况下,如何查看命令行工具使用的 Xcode 版本?

在 Terminal 中执行如下命令:

xcode-select --print-path
  • 1

示例:

$ xcode-select --print-path
/Applications/Xcode.app/Contents/Developer
  • 1
  • 2

表示当前命令行工具使用的Xcode位于 /Applications/Xcode.app


如何修改命令行工具使用的 Xcode 版本?

在 Terminal 中执行如下命令:

sudo xcode-select -switch <path/to/>Xcode.app
  • 1

示例:

$ sudo xcode-select -switch /Applications/Xcode.app
  • 1

如何使用命令行构建 Xcode 项目?

使用 xcodebuild 命令,它可以对 Xcode 项目和工作空间进行编译、查询、分析、测试和归档。如果操作的是 Xcode 项目,需要指定至少一个 target 或一个 scheme,而如果是工作空间,则只需指定一个 scheme。在 Terminal 中执行 man xcodebuild 可以查看 xcodebuild 使用手册。xcodebuild 执行的结果默认存储位置定义在:Xcode > Preferences > Locations。

注意:在执行命令前,要先切换到包含项目或工作空间的目录下,或指定完整的项目或工作空间的路径。

下面是一些用法举例:

列出工作空间包含的所有 scheme
xcodebuild -list -workspace <your_workspace_name>.xcworkspace
  • 1

示例:

$ cd /Users/username/Desktop/MyApplication
$ xcodebuild -list -workspace MyApplication.xcworkspace
Information about workspace "MyApplication":
    Schemes:
        iOSApp
        tvOSApp
        macOSApp
        iOSWithWatchApp
        iOSWithWatchApp WatchKit App
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
列出项目包含的所有 target 、configuration 和 scheme
xcodebuild -list -project MyProject.xcodeproj
  • 1

示例:

$ cd /Users/username/Desktop/MyProject
$ xcodebuild -list -project MyProject.xcodeproj
Information about project "MyProject":
    Targets:
        iOS
        iOSTests
        iOSUITests
        watchOS App
        watchOS App Extension
        tvOS
        tvOSTests
        tvOSUITests
        macOS
        macOSTests
        macOSUITests

    Build Configurations:
        Debug
        Release

 If no build configuration is specified and -scheme is not passed then "Debug" is used.

    Schemes:
        iOS
        watchOS App
        tvOS
        macOS
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
编译项目中的一个 scheme
xcodebuild -scheme <your_scheme_name> build
  • 1

示例:

$ xcodebuild -scheme tvOS build
=== BUILD TARGET tvOS OF PROJECT MyProject WITH CONFIGURATION Debug ===
...
  • 1
  • 2
  • 3

注意:xcodebuild 支持编译、分析、测试和归档等操作,当不指定任何操作时,默认执行编译操作。

构建时指定 configuration 文件
xcodebuild -target <your_target_name> -xcconfig <your_configuration_file>.xcconfig
  • 1

示例:

$ xcodebuild -target iOS -xcconfig configuration.xcconfig
Build settings from configuration file 'configuration.xcconfig':
   IPHONEOS_DEPLOYMENT_TARGET = 10
   SWIFT_TREAT_WARNINGS_AS_ERRORS = YES
=== BUILD TARGET watchOS Extension OF PROJECT MyProject WITH THE DEFAULT CONFIGURATION (Debug) ===
...
=== BUILD TARGET watchOS App OF PROJECT MyProject WITH THE DEFAULT CONFIGURATION (Debug) ===
...
=== BUILD TARGET iOS OF PROJECT MyProject WITH THE DEFAULT CONFIGURATION (Debug) ===
...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
修改 xcodebuild 的输出位置

可以在命令行中指定 SYMROOT(构建路径,存放 debug 包和 .dSYM 文件)和 DSTROOT(安装位置,存放 release 包和 .dSYM 文件)的值来达到修改目的。

修改 debug 版本的输出位置:

$ xcodebuild -scheme iOS SYMROOT="/Users/username/Desktop/DebugLocation"
Build settings from command line:
    SYMROOT = "/Users/username/Desktop/DebugLocation"
=== BUILD TARGET watchOS Extension OF PROJECT MyProject WITH CONFIGURATION Debug ===
...
=== BUILD TARGET watchOS App OF PROJECT MyProject WITH CONFIGURATION Debug ===
...
=== BUILD TARGET iOS OF PROJECT MyProject WITH CONFIGURATION Debug ===
...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

修改 release 版本的输出位置:

$ xcodebuild -scheme iOS  DSTROOT="/Users/username/Desktop/ReleaseLocation" archive
Build settings from command line:
    DSTROOT = /Users/username/Desktop/ReleaseLocation
=== BUILD TARGET watchOS Extension OF PROJECT MyProject WITH CONFIGURATION Release ===
...
=== BUILD TARGET watchOS App OF PROJECT MyProject WITH CONFIGURATION Release ===
...
=== BUILD TARGET iOS OF PROJECT MyProject WITH CONFIGURATION Release ===
...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

如果有多个 Configurations ,如何给 xcodebuild 设置一个默认的 Configuration ?

导航到 Project > Info > Configurations ,选择一个 configuration 即可:
在这里插入图片描述

如何利用命令行实施单元测试?

xcodebuild 也支持单元测试,使用如下命令实现:

xcodebuild test [-workspace <your_workspace_name>]
                [-project <your_project_name>]
                -scheme <your_scheme_name>
                -destination <destination-specifier>
                [-only-testing:<test-identifier>]
                [-skip-testing:<test-identifier>]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

test 操作需要同时指定 schemedestination
-workspace 指向 .xcworkspace 文件路径。
-project 指向 .xcodeproj 文件路径。
-destination 确定了单元测试的运行环境, <destination-specifier> 是对用于测试的设备、模拟器或 Mac 的描述,用 key=value 来确定,多个键值对以逗号分隔。
-only-testing 是可选的,指定了只测试哪些用例,-skip-testing 也是可选的,指定了跳过测试哪些用例,<test-identifier> 是对测试用例的描述,格式为:

TestTarget[/TestClass[/TestMethod]]
  • 1

TestTarget 是测试 Target 的名称,必须要指定。TestClassTestMethod 都是可选的,表示要进行测试的类和方法。

对于 macOS 应用,destinationspecifier 用 platform 和 arch 两个值表示
KeyDescriptionValue
platform测试运行的平台macOS
arch测试使用的架构i386 或 x86_64

示例,在 macOS 平台的 x86_64 架构上进行测试:

xcodebuild test -scheme macOS -destination 'platform=macOS,arch=x86_64'
  • 1
对于 iOS 和 tvOS 应用,destinationspecifier 用 platform、name 和 id 表示,name 和 id 只能指定其中一个
KeyDescriptionValue
platform测试运行的平台iOS(针对 iOS 应用),tvOS(针对 tvOS 应用)
name测试使用的设备全称Xcode 设备管理器中显示的设备名称
id测试使用的设备IDXcode 设备管理器中显示的设备ID

示例,在 ID 为 965058a1c30d845d0dcec81cd6b908650a0d701c 的 iOS 设备上进行测试:

xcodebuild test -workspace MyApplication.xcworkspace -scheme iOSApp -destination 'platform=iOS,id=965058a1c30d845d0dcec81cd6b908650a0d701c'
  • 1

示例,在名为 iPhone 的 iOS 设备上进行测试:

$ xcodebuild test -workspace MyApplication.xcworkspace -scheme iOSApp -destination 'platform=iOS,name=iPhone'
...
=== BUILD TARGET iOSApp OF PROJECT iOSApp WITH CONFIGURATION Debug ===
...
=== BUILD TARGET iOSAppTests OF PROJECT iOSApp WITH CONFIGURATION Debug ===
...
=== BUILD TARGET iOSAppUITests OF PROJECT iOSApp WITH CONFIGURATION Debug ===
...
Test Suite 'All tests' started at ...
Test Suite 'iOSAppTests.xctest' started at ...
Test Suite 'SecondTestClass' started at ...
Test Case '-[iOSAppTests.SecondTestClass testExampleA]' started.
Test Case '-[iOSAppTests.SecondTestClass testExampleB]' started.
Test Suite 'SecondTestClass' passed at ...
...
Test Suite 'iOSAppTests' started at ...
Test Case '-[iOSAppTests.iOSAppTests testExample]' started.
Test Case '-[iOSAppTests.iOSAppTests testPerformanceExample]' started.
Test Suite 'iOSAppTests' passed at ...
...
Test Suite 'iOSAppUITests.xctest' started at ...
Test Suite 'iOSAppUITests' started at ...
Test Case '-[iOSAppUITests.iOSAppUITests testLabels]' started.
Test Case '-[iOSAppUITests.iOSAppUITests testToolbar]' started.
...
** TEST SUCCEEDED **
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

示例,在名为 iPhone 的 iOS 设备上进行测试,但跳过对 iOSAppUITests 的测试:

xcodebuild test -workspace MyApplication.xcworkspace -scheme iOSApp -destination 'platform=iOS,name=iPhone' -skip-testing:iOSAppUITests
  • 1

示例,在名为 iPhone 的 iOS 设备上进行测试,但只测试 iOSAppTests 中的 SecondTestClass 类的 testExampleB 方法:

$ xcodebuild test -workspace MyApplication.xcworkspace -scheme iOSApp -destination 'platform=iOS,name=iPhone' -only-testing:iOSAppTests/SecondTestClass/testExampleB
...
=== BUILD TARGET iOSApp OF PROJECT iOSApp WITH CONFIGURATION Debug ===
...
=== BUILD TARGET iOSAppTests OF PROJECT iOSApp WITH CONFIGURATION Debug ===
...
=== BUILD TARGET iOSAppUITests OF PROJECT iOSApp WITH CONFIGURATION Debug ===
...
Test Suite 'Selected tests' started at ...
Test Suite 'iOSAppTests.xctest' started at ...
Test Suite 'SecondTestClass' started at ...
Test Case '-[iOSAppTests.SecondTestClass testExampleB]' started.
Test Case '-[iOSAppTests.SecondTestClass testExampleB]' passed (0.007 seconds).
Test Suite 'SecondTestClass' passed at ...
    ...
** TEST SUCCEEDED **
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
对于 iOS 模拟器和 tvOS 模拟器应用,destinationspecifier 用 platform、name、id 和 OS 表示,name 和 id 只能指定其中一个,OS 是可选的
KeyDescriptionValue
platform测试运行的平台iOS Simulator(针对 iOS 应用),tvOS Simulator(针对 tvOS 应用)
name测试使用的模拟器全称Xcode 设备管理器中显示的模拟器名称
id测试使用的模拟器IDXcode 设备管理器中显示的模拟器ID
OSiOS 或 tvOS 的版本号,或 latest 字符串具体的 iOS 版本、 tvOS 版本,或者是 latest

示例,在名为 iPad Pro (12.9 inch)、版本号为 10.2 的 iOS 模拟器上进行测试:

xcodebuild test -scheme iOS -destination 'platform=iOS Simulator,name=iPad Pro (12.9-inch),OS=10.2'
  • 1

示例,在 ID 为 D6FA2C2A-E297-406A-AA22-624B4834ACB2 的 tvOS 模拟器上进行测试:

xcodebuild test -scheme tvOS -destination 'platform=tvOS Simulator,id=D6FA2C2A-E297-406A-AA22-624B4834ACB2'
  • 1

一个测试用例允许指定多个 -destination 选项,xcodebuild 将会按顺序在每个 -destination 指定的环境上测试。
示例,在 iOS 模拟器和 iPod touch 上依次进行测试:

xcodebuild test -scheme iOS -destination 'platform=iOS Simulator,name=iPhone 6s,OS=10.3' -destination 'platform=iOS,name=iPod touch'
  • 1

如何利用命令行实现 Xcode 中的 Build For Testing 和 Test Without Building 功能?

xcodebuild 的 build-for-testing 操作实现了 Xcode菜单中的 Product > Build For > Testing 功能,需要指定一个 scheme

具体命令:

xcodebuild build-for-testing [-workspace <your_workspace_name>]
                             [-project <your_project_name>]
                             -scheme <your_scheme_name>
                             -destination <destination-specifier>
  • 1
  • 2
  • 3
  • 4

示例,在 ID 为 D6FA2C2A-E297-406A-AA22-624B4834ACB2 的 tvOS 模拟器上构建一个测试:

xcodebuild build-for-testing -scheme tvOS -destination 'platform=tvOS Simulator,id=D6FA2C2A-E297-406A-AA22-624B4834ACB2'
  • 1

build-for-testing 操作会生成一个 xctestrun 文件,保存在 DerivedData 目录下。

xcodebuild 的 test-without-building 操作实现了 Xcode 菜单中的 Product > Perform Action > Test Without Building 功能,需要指定一个 scheme 或者一个 xctestrun 文件

指定 scheme 的用法:

xcodebuild test-without-building [-workspace <your_workspace_name>]
                                 [-project <your_project_name>]
                                 -scheme <your_scheme_name>
                                 -destination <destination-specifier>
                                 [-only-testing:<test-identifier>]
                                 [-skip-testing:<test-identifier>]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

test-without-building 在指定 scheme 进行测试时,它会在构建根目录(SYMROOT)寻找可以测试的包,因此请确保项目已经编译过或构建根目录已经存在可以测试的包。

示例,在名为 iPhone SE、版本为 10.1 的 iOS 模拟器上执行 test-without-building 测试:

xcodebuild test-without-building -workspace MyApplication.xcworkspace -scheme iOSApp -destination 'platform=iOS Simulator,name=iPhone SE,OS=10.1'
  • 1

指定 xctestrun 文件的用法:

xcodebuild test-without-building -xctestrun <your_xctestrun_name>.xctestrun
                                 -destination <destination-specifier>
                                 [-only-testing:<test-identifier>]
                                 [-skip-testing:<test-identifier>]
  • 1
  • 2
  • 3
  • 4

test-without-building 在指定 xctestrun 进行测试时,它会寻找 xctestrun 文件中指定的包,因此请确保这些包存在。

示例,在 ID 为 6DC4A7BA-EA7F-40D6-A327-A0A9DF82F7F6 的 iOS 模拟器上测试iOSApp_iphonesimulator.xctestrun 文件指定的包:

$ cat iOSApp_iphonesimulator.xctestrun
<?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>iOSAppTests</key>
    <dict>
        <key>BundleIdentifiersForCrashReportEmphasis</key>
        <array>
            <string>com.myapps.iOSApp</string>
            <string>com.myapps.iOSAppTests</string>
            <string>com.myapps.iOSAppUITests</string>
        </array>
        …
        <key>TestBundlePath</key>
        <string>__TESTHOST__/PlugIns/iOSAppTests.xctest</string>
        <key>TestHostBundleIdentifier</key>
        <string>com.myapps.iOSApp</string>
        <key>TestHostPath</key>
        <string>__TESTROOT__/Debug-iphonesimulator/iOSApp.app</string>
        …
    </dict>
    <key>iOSAppUITests</key>
    …
</dict>
</plist>

$ xcodebuild test-without-building -xctestrun iOSApp_iphonesimulator.xctestrun -destination 'platform=iOS Simulator,id=6DC4A7BA-EA7F-40D6-A327-A0A9DF82F7F6'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

示例,在 ID 为 3D95DF14-E8B7-4A05-B65B-78F381B74B22 的 iOS 模拟器上测试iOSApp_iphonesimulator.xctestrun 文件指定的所有包,但跳过对 iOSAppUITests 的测试:

xcodebuild test-without-building -xctestrun iOSApp_iphonesimulator.xctestrun -destination 'platform=iOS Simulator,id=3D95DF14-E8B7-4A05-B65B-78F381B74B22' -skip-testing:iOSAppUITests
  • 1

注意:build-for-testing 和 test-without-building 也支持持续集成系统。


exportOptionsPlist 文件可以包含哪些配置?

在 Terminal 中执行如下命令进行查看:

xcodebuild -help
  • 1

示例:

$ xcodebuild -help
Usage: xcodebuild [-project <projectname>] [[-target <targetname>]...|-alltargets] [-configuration <configurationname>] [-arch <architecture>]
     ...
Available keys for -exportOptionsPlist:
    compileBitcode : Bool
         ...
    embedOnDemandResourcesAssetPacksInBundle : Bool
         ...
    iCloudContainerEnvironment
         ...
    manifest : Dictionary
         ...
    method : String
         ...
    onDemandResourcesAssetPacksBaseURL : String
         ...
    teamID : String
         ...
    thinning : String
         ...
    uploadBitcode : Bool
         ...
    uploadSymbols : Bool
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

示例:
在这里插入图片描述

如何归档并导出应用?

归档
xcodebuild -project <xcodeprojpath> -scheme <scheme_name> -archivePath <xcarchivepath> archive
  • 1

<xcodeprojpath> 指向工程的 .xcodeproj 文件路径。如果操作的是工作空间,将 -project 替换为 -workspace 即可。
<scheme_name> 是工程中定义的 scheme 名称,它确定了具体要操作的 targetconfiguration 等信息。
<xcarchivepath> 是导出的归档文件路径,包含 .appdSYM 等文件,它也是下一步操作的参数。

示例:

$ xcodebuild -project iOSApp.xcodeproj -scheme iOSApp -archivePath iOSApp.xcarchive archive

Command line invocation:
   /Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -project iOSApp.xcodeproj -scheme iOSApp -archivePath iOSApp.xcarchive archive

User defaults from command line:
   IDEArchivePathOverride = /Users/username/iOSApp/iOSApp.xcarchive
   IDEPackageSupportUseBuiltinSCM = YES

note: Using new build system
note: Building targets in parallel
note: Planning build
note: Analyzing workspace
note: Constructing build description
note: Build preparation complete
...

** ARCHIVE SUCCEEDED **
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
导出
xcodebuild -exportArchive -archivePath <xcarchivepath> -exportPath <destinationpath> -exportOptionsPlist <path>
  • 1

<xcarchivepath> 指向第一步中归档后的文件。
<destinationpath> 指向即将导出的 .ipa 文件路径。
<path> 指向 ExportOptions.plist 文件路径。ExportOptions.plist 文件可以在 Xcode 中手动 Archive 并 Export 一次获得。

示例:

$ xcodebuild -exportArchive -archivePath iOSApp.xcarchive -exportPath Release/MyApp -exportOptionsPlist ExportOptions.plist
...
Exported iOSApp to: /Users/virusbee/Desktop/iOSApp/Release/MyApp

** EXPORT SUCCEEDED **
  • 1
  • 2
  • 3
  • 4
  • 5

参考文档

英文原文:https://developer.apple.com/library/archive/technotes/tn2339

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/519755
推荐阅读
相关标签
  

闽ICP备14008679号