トップ/記事一覧/Xcodeの旧バージョンを入れる方法。xcodesが2段階認証で止まったら.xipを--pathで渡す
xcode-old-version-install-xcodes-path-cover

Xcodeの旧バージョンを入れる方法。xcodesが2段階認証で止まったら.xipを--pathで渡す

現場のCIに合わせてXcode 26.3が必要になったが、App Storeには最新の27.1しかない。xcodesは2段階認証の6桁で止まった。ブラウザでサインインして.xipを落とし、xcodes install --pathで渡して入れるまでを、実際の画面と出力で載せる。

ラボ2026年10月23日公開
目次
この記事のポイント

現場のCIに合わせてXcode 26.3が必要になったが、App Storeには最新の27.1しかない。xcodesは2段階認証の6桁で止まった。ブラウザでサインインして.xipを落とし、xcodes install --pathで渡して入れるまでを、実際の画面と出力で載せる。

個人開発では、App Store から入れた最新の Xcode 27 系を使っています。ところが参画している現場の iOS アプリは、CI(変更のたびに自動でビルドする仕組み)が Xcode 26.3 で動いていて、手元も同じ版に揃える必要が出てきました。

旧版の Xcode は App Store には置かれていません。Apple のサイトから落とすか、版を指定して入れられる xcodes というコマンドを使うのが定番です。どちらも Apple アカウントへのサインインと2段階認証(パスワードのあとに6桁の確認コードを求める仕組み)が要ります。

私は10年近く前に iPhone から Android へ乗り換え、そのときのキャリアメールも放置したままでした。xcodes は6桁のコードを求めたところで止まり、コードはどこにも届きませんでした。最終的には、ブラウザでサインインして Xcode の .xip を自分で落とし、xcodes install 26.3 --path <xip> で渡すことで、コマンド側のサインインなしに入りました。

この記事は、最新の Xcode を入れる普通の手順から始めて、旧版が要る理由、2段階認証で止まったところ、ブラウザ経由で抜けた手順までを、実際の画面と出力で順に載せます。環境は Apple silicon の MacBook Air、macOS 26.6.2 です。

最新の Xcode は App Store から入れる

Mac には、Xcode 本体を入れなくても Command Line Tools(git やコンパイラなど、端末で使う最小限の開発道具)が入っていることがあります。ただし iOS アプリのビルドに使う xcodebuild は、Command Line Tools だけでは動きません。

Command Line Tools だけの状態で xcodebuild -version を実行すると、requires Xcode というエラーになる
Command Line Tools だけの状態を、DEVELOPER_DIR で切り替えて再現したもの

最新版を入れるなら App Store が一番手軽です。端末で済ませたい場合は、App Store を操作するコマンド mas(Homebrew で入ります)が使えます。Xcode の App Store での番号は 497799835 です。

mas info 497799835 の出力。Version は 27.1
App Store の Xcode は最新の 27.1 の1本だけ(2026年10月23日時点)

入れてから使える状態にするまでは、次の4つです。mas get は手元では sudo を求められました。

# App Store から Xcode を入れる
sudo mas get 497799835
# 使う Xcode をこれに切り替える
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
# 初回起動時の追加部品を入れる
xcodebuild -runFirstLaunch
# iOS シミュレーターを入れる
xcodebuild -downloadPlatform iOS

この手順で、Xcode 27.1 と iOS 27.0・27.1 のシミュレーターが入りました(合わせて約15GB)。個人開発ならここで終わりです。

現場の CI は 26.3 だった

現場のアプリを Xcode 27.1 でビルドすると、失敗しました。Swift 6 の並行処理の検査(複数の処理が同じデータを同時に触らないかを、コンパイル時に調べる仕組み)が厳しくなり、それまで通っていた書き方がエラーになったためです(型の名前は置き換えています)。

Testing failed:
	Conformance of 'ArrowHead' to protocol 'Shape' crosses into main actor-isolated code and can cause data races
	Conformance of 'BubbleTail' to protocol 'Shape' crosses into main actor-isolated code and can cause data races
	Testing cancelled because the build failed.

** TEST FAILED **

では CI はどの版で動いているのか。GitHub Actions の設定は、Xcode を切り替える setup-xcode に「最新の安定版」を指定していました。

runs-on: macos-15
  ...
      - uses: maxim-lobanov/setup-xcode@v1.7.0
        with:
          xcode-version: 'latest-stable'

直近のリリース用の実行ログを見ると、実際に選ばれていたのは 26.3 でした。

Image: macos-15-arm64
Switching Xcode to version 'latest-stable'...
Xcode 26.3

setup-xcode は、GitHub が用意した実行環境(ここでは macos-15)に最初から入っている Xcode の中から選ぶだけで、新しい版を入れはしません(README に "switch between pre-installed versions of Xcode" とあります)。そのため「最新の安定版」の指定でも、App Store の最新(27.1)ではなく、その実行環境で一番新しい 26.3 になります。手元は CI に合わせて 26.3 を入れることにしました。

揃えるのは Xcode だけではありません。コードの書式を整える SwiftFormat も、Homebrew の最新版で走らせると、変更していないのに大量の書き換えが出ました。版を順に試し、現場のコードと一致する版を使うことにしています。

SwiftFormat の版書き換えが必要と言われたファイル(全603)
0.64.1(Homebrew の最新)131
0.64.0126
0.63.1・0.63.0120
0.62.1・0.62.0115
0.61.1・0.60.10

コードの書き方を検査する SwiftLint も、0.65.1 では違反が8件出て、0.65.0 では現場の状態と一致しました。

旧版は App Store に無い

App Store で入るのは最新の1本だけです。旧版は Apple の開発者向けダウンロードページに置かれています。Apple の Xcode Resources には、旧版を見るには Apple アカウントでサインインすればよく、有料の Apple Developer Program への加入は要らない、と書かれています。

端末から入れるなら xcodes が便利です。版を並べて入れておき、切り替えられます。xcodes list で、入れられる版が一覧になります。

xcodes list の出力。26.3 の正式版と候補版から、27.2 の候補版まで並ぶ
xcodes list は旧版や Beta も含めて並べる(26.3 と 27 系だけに絞って表示)

入れ方は3通りあり、違いは Apple アカウントのサインインをどこで通すかです。今回は真ん中の道で止まり、一番下の道で抜けました。

Xcode を入れる3つの道。App Store は最新版だけ。xcodes は自分でサインインし、6桁のところで止まる。ブラウザでサインインして .xip を落とし、xcodes --path で渡すと入る
違いは、サインインの関所をどこで越えるか

なお、Xcode を切り替えると Mac 全体の設定が変わり(sudo が要ります)、1本で十数GBを使います。版をいくつも並べるのはやめ、手元には 26.3 の1本だけを置くことにしました。App Store 版は自動で新しい版に上がってしまうので、あとで消します。

xcodes は「6桁」で止まった

xcodes install 26.3 を実行すると、Apple アカウントのパスワードまでは通り、次の表示で止まりました。

Apple ID Password:
Two-factor authentication is enabled for this account.

Enter "sms" without quotes to exit this prompt and choose a phone number to send an SMS security code to.
Enter the 6 digit code from one of your trusted devices:

「信頼済みデバイス(そのアカウントでサインイン済みで、確認コードが表示される Apple 製品)から6桁を入れて」という意味です。私の手元にある Apple 製品はこの Mac だけで、Mac は個人の Apple アカウントで iCloud にサインインしていました。それでも、待っても Mac に通知は出ませんでした。システム設定のアカウントの画面にも、コードを自分で表示する項目は見当たりませんでした。

表示にあるとおり sms と打てば電話番号へ送る道もありますが、アカウントに登録した番号で今も受け取れることが前提です。

xcodes の 2.x 系はサインインの仕組みを作り替えており、2段階認証まわりの不具合の報告が続いています(例: issue #480)。手元は 2.1.0 でした。今回の「通知が来ない」が同じ原因かは確かめていません。

ブラウザなら、同じ Mac に確認が届いた

同じ個人のアカウントで、ブラウザから developer.apple.com にサインインしてみると、こちらは通りました。以下は記事用にあとから同じ流れを撮り直したもので、Apple アカウントのサインイン画面(account.apple.com)を使っています。

Apple アカウントのサインイン画面。メールアドレスはモザイクで隠している
記事用に account.apple.com で撮り直した画面。メールアドレスは隠しています

パスワードを入れると、2段階認証の画面に「MacBook Air へ送信された確認コード」と出ます。届け先は、いまブラウザを開いているこの Mac 自身です。

2ファクタ認証の画面。MacBook Air へ送信された確認コードを入力してください、と表示されている

直後に Mac 本体へ、どこからのサインインかを地図で示す確認が出ました。xcodes のときには一度も出なかったものです。

Mac 本体に出た確認。Apple アカウントが新しいデバイスのサインインに使われている、と表示されている。地図と場所はモザイクで隠している
Mac 本体に出た確認。「許可する」を押す(地図と場所は隠しています)

「許可する」を押すと6桁のコードが表示されるので、ブラウザの入力欄へ入れればサインインが終わります。

許可すると Mac の画面に6桁の確認コードが表示される。コードはモザイクで隠している
許可すると6桁が出るので、ブラウザの入力欄へ入れる(コードは隠しています)

ちなみに、現場の開発用の Apple アカウントで同じようにサインインしたときは、登録してある Android のスマホに SMS で6桁が届きました。コードの届け先はアカウントごとに違います。

ここで混乱しやすいのが、Apple アカウントの使い道が3つあることです。Mac 本体のサインイン、Xcode のダウンロード、Xcode の中でアプリに署名するためのアカウントは、別々のアカウントで構いません。ダウンロードは個人のアカウントで済ませ、現場の開発用アカウントはあとから Xcode の設定に足せば足ります。

Apple アカウントの3つの使い道。Mac 本体のサインイン、Xcode のダウンロード、Xcode の署名。ダウンロードはどのアカウントでもよく、署名用の仕事のアカウントは後から足せる
3つは別々のアカウントでよい

.xip を落として署名を確かめる

サインインできたら、ダウンロードページで版を検索します。URL に検索語を付けて https://developer.apple.com/download/all/?q=Xcode%2026.3 を開くと早いです。Apple silicon の Mac なら「Apple silicon」の方を選びます(2.11GB)。「Universal」は Intel の Mac 用、またはほかの人と共有する場合の版です。

developer.apple.com のダウンロードページ。Xcode 26.3 Apple silicon.xip は 2.11GB、Universal.xip は 2.67GB
developer.apple.com/download/all/ で Xcode 26.3 を検索した結果

落としたファイルは、入れる前に Apple の署名が付いているかを pkgutil --check-signature で確かめます。「signed Apple Software」と出て、証明書が「Apple Root CA」までつながっていれば、Apple が配ったものです。

$ pkgutil --check-signature ~/Downloads/Xcode_26.3_Apple_silicon.xip
Package "Xcode_26.3_Apple_silicon.xip":
   Status: signed Apple Software
   Certificate Chain:
    1. Software Update
       Expires: 2029-04-14 21:28:23 +0000
    2. Apple Software Update Certification Authority
       Expires: 2031-10-15 00:00:00 +0000
    3. Apple Root CA
       Expires: 2035-02-09 21:40:36 +0000

(実際の出力には各証明書の SHA256 フィンガープリントも並びます。ここでは省きました。)

xcodes に --path で渡す

xcodes には、手元の .xip を渡す --path があります。ファイルを自分で用意しているので、xcodes は Apple へサインインしに行きません。実際、パスワードも6桁も聞かれずに進みました。

xcodes install --help の抜粋。--path は手元の Xcode の .xip を渡すオプション
xcodes install --help の抜粋

実行したのは次のとおりです。最後の sudo rm -rf /Applications/Xcode.app は、先に入れた App Store 版(27.1)を消すためです。App Store 版も残したい人は、この行を外してください。

# 入れて、使う版に選び、展開を速め、終わったら .xip を完全に消す
xcodes install 26.3 \
  --path ~/Downloads/Xcode_26.3_Apple_silicon.xip \
  --select --experimental-unxip --empty-trash
# 利用規約に同意する
sudo xcodebuild -license accept
# 初回起動時の追加部品を入れる
xcodebuild -runFirstLaunch
# この版に合う iOS シミュレーターを入れる
xcodebuild -downloadPlatform iOS
# App Store 版(27.1)を消す
sudo rm -rf /Applications/Xcode.app
# 入っている版を確かめる
xcodes installed

--empty-trash を付けると、入れ終わった .xip はゴミ箱にも残りません。もう一度使う可能性があるなら外しておくと、2GB を落とし直さずに済みます。

27.1 用に入れた iOS 27 のシミュレーターは、xcrun simctl runtime delete で消しました。xcrun simctl runtime list の合計は、iOS 26.3.1・27.0・27.1 の3つで 22.7G だったのが、26.3.1 だけの 7.8G になりました。

xcodes installed で 26.3 が選ばれている。xcodebuild -version は Xcode 26.3。シミュレーターの合計は 7.8G
入れ終わったあとの状態

あとから版を切り替えたくなったら xcodes select を使います。プロジェクトに .xcode-version というファイルがあれば、引数なしの xcodes select がそこに書かれた版を選びます。

26.3 でビルドとテストが通った

26.3 に替えると、27.1 で失敗したアプリ本体のビルドは通りました。一方でテストのコードは、5か所が 26.3 ではコンパイルできませんでした。Swift Testing の #expect の中で #require を使う書き方です(変数などの名前は置き換えています)。

// 26.3 でエラー: call can throw, but it is executed in a non-throwing autoclosure
try #expect(model.destination == .detail(id: #require(UUID(uuidString: idString))))

// 先に取り出してから比べると通る
let id = try #require(UUID(uuidString: idString))
#expect(model.destination == .detail(id: id))

この5か所を書き直すと、テスト1944件がすべて通りました(失敗0件)。新しい Xcode で書いたテストが、古い Xcode ではコンパイルできないことがある、という例です。

手順のおさらい

  • 1.CI のログで、実際に使われている Xcode の版を確かめる(「latest-stable」の指定は、App Store の最新とは限らない)
  • 2.ブラウザで developer.apple.com/download/all/ にサインインし、その版の .xip を落とす
  • 3.pkgutil --check-signature で Apple の署名を確かめる
  • 4.xcodes install <版> --path <xip> --select で入れる
  • 5.SwiftFormat・SwiftLint などの道具も、現場のコードと一致する版に揃える

カバー写真: Wilfredor 撮影・CC0(文字を重ねる加工あり)

avatar-m-1

Backend Engineer / AWS / Django / Go