Xcode 26 に上げたとき、私は Info.plist に UIDesignRequiresCompatibility を書き足して、見た目の変更を先送りしました。手元の壁紙アプリは全画面の画像ビューアと独自の下部バーで構成されていて、Liquid Glass をそのまま浴びると何が起きるか読めなかったからです。
そのフラグを、先日 false に戻しました。理由は単純で、このフラグは Xcode 27 で無視される見込みだからです。外される日を待つより、外す日を自分で決めたほうが痛みが小さいと考えました。
結果として、崩れた箇所は 3 つでした。どれも「そのうち直す」で済ませられるものではなく、リリース前の実機で気づいていたら数時間は溶かしていたはずのものです。
猶予フラグは、外される日まで使うものではありません
Apple は WWDC25 の UI Frameworks Group Lab で、この互換オプションについて「一時的な措置であり、次のメジャーリリースで削除される予定」と明言しています。iOS 26 / Xcode 26 の段階で用意された逃げ道は、最初から期限つきでした。
現時点で公表・予測されている期日を並べると、残り時間の感覚がつかみやすくなります。
| 時期 | 内容 | 確度 |
|---|---|---|
| 2026年4月28日 | App Store 提出は iOS 26 SDK(Xcode 26)ビルドが必須 | 公式 |
| 2026年9月(見込み) | iOS 27 / Xcode 27 の正式リリース。互換フラグが無視される | Apple の明言+例年の周期からの予測 |
| 2027年4月中旬(予測) | App Store 提出は iOS 27 SDK ビルドが必須になる見込み | 過去の周期からの予測(未発表) |
2027年4月の期日は予測であって、執筆時点で Apple が公表したものではありません。ただし、9月に正式版が出た時点で「新 SDK でビルドし直したら見た目が変わる」状態には確実になります。手を付ける実質的な締切は、来年春ではなく今年の秋です。
外し方は Info.plist の 1 行を消すか、値を false にするだけです。
<!-- Info.plist -->
<!-- iOS 26 世代で見た目を据え置くための一時フラグ。Xcode 27 では無視される見込み -->
<key>UIDesignRequiresCompatibility</key>
<false/>これで Xcode 26 のままビルドすれば、標準コントロールは新デザインで描かれます。来年強制される状態を、今の SDK のまま予行演習できるというのがこのフラグの一番の使い道です。iOS 27 のベータ端末を用意する前に、まずここから始められます。検証機の選び方についてはiOS 27 パブリックベータをどの端末に入れるかにまとめてあります。
最初に崩れたのは、全画面ビューアの下端でした
私の壁紙アプリは、画像を全画面で表示して、下端に保存・共有・お気に入りのボタンを並べています。この下端の配置を、長いあいだタブバーの高さを前提にした固定値で組んでいました。
// これまで: バーの高さを決め打ちして下端から持ち上げていた
VStack {
WallpaperCanvas(item: item)
ActionBar(item: item)
.padding(.bottom, 49) // タブバーの高さぶん
}Liquid Glass のタブバーはコンテンツの上に浮く形になり、スクロールに応じて最小化します。つまり safeAreaInsets の値そのものが変わるため、49 という固定値は正しくなくなります。実機では、ボタン列がタブバーに半分潜り込みました。
直したあとはこうなりました。
// 修正後: 下端の余白はシステムに教えてもらう
VStack {
WallpaperCanvas(item: item)
}
.safeAreaInset(edge: .bottom) {
ActionBar(item: item) // 高さの決め打ちをやめる
}固定値を消しただけの小さな差分ですが、これは Liquid Glass に限った話ではありません。バーの高さを定数で持っている箇所は、次に何かが浮いたり縮んだりしたときに必ずもう一度壊れます。今回の移行は、その負債を洗い出す口実として使えました。
カスタム背景色は「効かなくなる」のではなく「濁ります」
もうひとつの崩れは、ナビゲーションバーの背景色でした。ブランドカラーに合わせて不透明の背景を指定していたのですが、これがガラスの質感と干渉して、意図しない濁った見た目になりました。
// これまで: 不透明の背景を自前で指定していた
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = .brandBackground
UINavigationBar.appearance().standardAppearance = appearance厄介なのは、これが「見えなくなる」わけではない点です。エラーも警告も出ず、ただ質感が悪くなります。ビルドが通ってしまうので、スクリーンショットを並べて比べるまで気づけません。
対処は、自前の背景を外してシステムの描画に任せることでした。ブランドカラーはバーの背景ではなく、コンテンツ側のアクセントとして残しています。加えて、システムが自動的に挿入する UIDropShadowView が既存のレイアウト計算を狂わせるケースも報告されているため、ビュー階層を数えて位置を決めている箇所があれば、そこも同時に見ておく価値があります。
私の場合、影響のあった箇所は次の 3 種類に集約されました。
| 種類 | 症状 | 対処 |
|---|---|---|
| バーの高さの決め打ち | ボタン列がタブバーに潜る | safeAreaInset に置き換える |
| バーの不透明背景 | ガラスと干渉して濁る | 自前の背景を外し、色はコンテンツ側へ |
| ビュー階層の添字参照 | システム挿入のビューでずれる | 添字ではなく型や識別子で引く |
エージェントに任せたのは修正ではなく、箇所の棚卸しでした
この点検で Antigravity に頼んだのは、直すことではなく、疑わしい箇所を全部並べることでした。
具体的には、バーの高さに相当する定数(44, 49, 83 など)を含むレイアウト指定、UINavigationBarAppearance と UITabBarAppearance への代入、subviews[0] のような添字参照、そして UIScreen.main の参照を、ファイルと行番号つきで一覧にしてもらいました。この種の「機械的に見つかるが、人間が見落とす」作業はエージェントの得意分野です。
一方で、直すかどうかの判断は自分で持ちました。上の 3 番目のような箇所は、一見同じパターンに見えても、意図的にそう書いてある場合があります。エージェントに一括修正させると、その意図ごと消えます。私はこの手の移行では、洗い出しは自動・判断は手動という分け方を好みます。
洗い出しの依頼文は、対象と出力形式を指定するだけで十分でした。
このリポジトリの Swift ファイルから、以下を含む行をファイル名と行番号つきで一覧にしてください。
修正はしないでください。
1. バーの高さと思われる数値定数(44 / 49 / 83 / 96)を含む padding・offset・frame の指定
2. UINavigationBarAppearance または UITabBarAppearance への代入
3. subviews への添字アクセス
4. UIScreen.main の参照
各項目に、なぜ Liquid Glass 移行で問題になりうるかの推測を 1 行添えてください。出てきたリストのうち、実際に手を入れたのは半分ほどです。残りは「読んで問題ないと確認した」という記録として残しました。移行作業でいちばん時間を食うのは、直す作業よりも「ここは大丈夫だと確信する」作業だと思います。
Liquid Glass より先に、UIScene ライフサイクルを見てください
見た目の話を先に書きましたが、優先順位としてはこちらが上です。
Apple のテクニカルノート TN3187 は、次のメジャーリリースで最新 SDK ビルド時に UIScene ライフサイクルが必須となり、採用していないアプリは起動しなくなると述べています。見た目が崩れるのと、起動しないのとでは、被害の桁が違います。
作業としては、SceneDelegate の作成、Info.plist への UIApplicationSceneManifest の追加、UIWindow(windowScene:) への置き換えが中心です。AppDelegate 側のライフサイクルメソッドは iOS 26 で非推奨になっており、対応先が決まっています。
| 非推奨(AppDelegate) | 移行先(SceneDelegate) |
|---|---|
applicationDidBecomeActive(_:) | sceneDidBecomeActive(_:) |
applicationDidEnterBackground(_:) | sceneDidEnterBackground(_:) |
application(_:open:options:) | scene(_:openURLContexts:) |
個人開発の規模であれば、まず UIApplicationSupportsMultipleScenes を false のまま単一ウィンドウ前提で移行を終わらせるのが現実的です。マルチウィンドウ対応は後回しにできますが、Scene ライフサイクルへの移行そのものは後回しにできません。
通知やカスタム URL スキームからの起動経路を持っているアプリほど、確認すべき組み合わせが増えます。App Store の審査に出す前に、起動経路を一覧にしておくと安心できます。
9月までに終わらせる順番
私が実際に進めた順番をそのまま書きます。
- UIDesignRequiresCompatibility を false に戻して、Xcode 26 のままビルドする(ここで初めて現実が見えます)
- 崩れた画面のスクリーンショットを、修正前の状態で残しておく
- バーの高さの決め打ちを
safeAreaInsetへ置き換える - バーの不透明背景を外し、ブランドカラーをコンテンツ側へ移す
UIScreen.mainをwindowScene.screen経由に置き換える- UIScene ライフサイクルへの移行に着手する(単一ウィンドウ前提で可)
1 から 4 までは、私の 2 本のアプリではそれぞれ半日ずつで終わりました。逆に言えば、Xcode 27 が出てから慌ててやると、その半日が「リリースを止めている半日」になります。
今日できることは、Info.plist の 1 行を書き換えてビルドすることだけです。それだけで、来年の自分が困る箇所が今日わかります。同じ移行の型として、Android 側のAndroid 16 のエッジツーエッジ強制対応も参考になるかもしれません。
最後までお読みいただき、ありがとうございました。移行の記録が、どなたかの半日を守ることにつながれば嬉しく思います。
参考: Meet Liquid Glass(WWDC25 Session 219) / TN3187: Migrating to the UIKit scene-based life cycle