Xcodeのスキームは、.xcschemeのファイルに保存される。xcodebuild -schemeでビルドやテストをするCIでは、スキームを共有して、.xcschemeのファイルをGitで管理しておくと確実である。

[プロジェクト名].xcodeproj/xcshareddata/xcschemes/[スキーム名].xcscheme

Xcode 27のxcodebuildは、.xcschemeのファイルがなくても、暗黙のスキームでビルドできる。ただし、暗黙のスキームには、テストターゲットが含まれない。

実行例はXcode 27.0、macOS 27.0.1のもの。

スキームを一覧する

プロジェクトのターゲットとスキームは、xcodebuild -listで確認できる。

$ xcodebuild -list -project [プロジェクト名].xcodeproj
Information about project "[プロジェクト名]":
    Targets:
        [アプリ名]
        [アプリ名]Tests

    Build Configurations:
        Debug
        Release

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

    Schemes:
        [アプリ名]

-schemeに指定できる名前は、Schemes:に表示された名前である。存在しない名前を指定すると、終了コード65で失敗する。

xcodebuild: error: The project named "[プロジェクト名]" does not contain a scheme named "Nope". The "-list" option can be used to find the names of the schemes in the project.

ローカルのパッケージを使うプロジェクトでは、パッケージのスキームも一覧に表示される。

スキームの種類

スキームには、次の3種類がある。

種類保存先Gitで管理
共有スキームxcshareddata/xcschemes/[スキーム名].xcschemeする
ユーザーのスキームxcuserdata/[ユーザー名].xcuserdatad/xcschemes/しない
暗黙のスキームファイルなしなし

Xcodeは、ファイルのない暗黙のスキームを、ターゲットから自動で作る。Scheme Managerの「Autocreate schemes」が、この動作の設定である。

共有スキームがないとき

共有スキームの.xcschemeを削除したプロジェクトでも、xcodebuild -listは、暗黙のスキームを表示した。

$ find . -name "*.xcscheme"
$ xcodebuild -list -project [プロジェクト名].xcodeproj
...
    Schemes:
        [アプリ名]
        [アプリ名]Tests

実行後も、.xcschemeとxcuserdataは作成されなかった。暗黙のスキームは、ファイルとして保存されない。-schemeに指定したビルドも、成功した。

$ xcodebuild build-for-testing -project [プロジェクト名].xcodeproj -scheme [アプリ名] -destination 'platform=macOS'
...
** TEST BUILD SUCCEEDED **

参考: 【xcodebuild】MACOSX_DEPLOYMENT_TARGETの優先関係を-showBuildSettingsで確認する

暗黙のスキームにテストターゲットは含まれない

共有スキームのTestActionには、実行するテストターゲットがTestablesとして登録されている。

<TestAction
   buildConfiguration = "Debug"
   ...
   <Testables>
      <TestableReference
         ...
            BlueprintName = "[アプリ名]Tests"

同じプロジェクトを、共有スキームがある状態と、ない状態でビルドした。build-for-testingの結果は次のとおりである。

共有スキーム-scheme [アプリ名]のbuild-for-testing[アプリ名]Tests.xctest
あり成功作成される
なし成功作成されない

暗黙のスキームでは、テストターゲットが、[アプリ名]Testsという別のスキームになる。-scheme [アプリ名]でテストを実行したいCIでは、共有スキームが必要である。

自動作成をオフにすると見つからない

ワークスペースの設定IDEWorkspaceSharedSettings_AutocreateContextsIfNeededをfalseにすると、暗黙のスキームは作られない。この設定は、project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettingsに保存される。

<?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>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
	<false/>
</dict>
</plist>

共有スキームがないプロジェクトは、スキームが空になる。

$ xcodebuild -list -project [プロジェクト名].xcodeproj
...
    This project contains no schemes.
$ xcodebuild -project [プロジェクト名].xcodeproj -scheme [アプリ名] build
xcodebuild: error: The project named "[プロジェクト名]" does not contain a scheme named "[アプリ名]". The "-list" option can be used to find the names of the schemes in the project.
$ echo $?
65

共有スキームがあるプロジェクトは、共有スキームだけが一覧に表示される。暗黙のスキームの[アプリ名]Testsは表示されない。

共有スキームをGitで管理する

Xcodeでは、「Product」メニューの「Scheme」から「Manage Schemes…」を開き、スキームの「Shared」にチェックを入れる。スキームは、xcshareddata/xcschemes/に.xcschemeのファイルとして保存される。

参考: Shared Schemes and Source Control(Apple Documentation Archive)

.xcschemeのファイルは、通常のファイルと同じようにコミットする。

$ git add [プロジェクト名].xcodeproj/xcshareddata/xcschemes/[スキーム名].xcscheme
$ git commit -m "Add shared scheme"

xcuserdataは、ユーザーごとの設定なので、.gitignoreに追加する。

xcuserdata/

xcuserdataの中には、Scheme Managerでのスキームの並び順を保存するxcschememanagement.plistがある。

$ plutil -p [プロジェクト名].xcodeproj/xcuserdata/[ユーザー名].xcuserdatad/xcschemes/xcschememanagement.plist
{
  "SchemeUserState" => {
    "[スキーム名].xcscheme_^#shared#^_" => {
      "orderHint" => 1
    }
  }
}

xcschememanagement.plistは、共有スキームの.xcschemeの代わりにならない。

CIで使う

共有スキームをコミットしたリポジトリは、cloneした直後でも、xcodebuild -schemeでビルドできる。スキーム名が分からないときは、ワークフローに-listのステップを入れておくと、ログで確認できる。

- name: List schemes
  run: xcodebuild -list -project [プロジェクト名].xcodeproj

- name: Build
  run: xcodebuild build -project [プロジェクト名].xcodeproj -scheme [スキーム名] -destination 'platform=macOS'

参考: 【GitHub Actions,Xcode】CIで使うXcodeのバージョンを固定する (xcode-select)

古い情報との違い

古い情報には、xcodebuildはスキームを自動で作らないため、共有してコミットしないと使えない、と書かれたものがある。

参考: Project does not contain a scheme(Bitrise Discuss、2017年)

Xcode 27のxcodebuildは、前述のとおり、暗黙のスキームでビルドできた。動作は、Xcodeのバージョンや自動作成の設定で変わる可能性がある。

どちらの方法を選ぶか

状況方法
CIでテストを実行する共有スキームをコミットする
スキームの設定(ビルド構成、引数)をチームで揃える共有スキームをコミットする
ビルドだけできればよい暗黙のスキームでも動く

CIでは、Xcodeのバージョンや設定に左右されないよう、共有スキームをコミットする。ユーザーごとの設定であるxcuserdataは、.gitignoreに追加する。