capacitor-ios-resizability について
iPad などのリサイズ可能なウィンドウに対応する Capacitor iOS アプリの準備を支援するスキルです。Web レイアウト、ネイティブコード、プラグイン、アプリ設定を監査し、修正と検証を案内します。
主な機能
- 01Web レイアウトの前提を監査
- 02ネイティブ API とプラグインをスキャン
- 03Info.plist とシーン設定を確認
- 04承認を得た各層の修正を案内
- 05シミュレーターでリサイズを検証
活用シーン
- 01iPad マルチタスクへのアプリ対応
- 02リサイズ後に崩れるレイアウトの調査
- 03Split View でのプラグインオーバーレイ確認
- 04起動画面や向きに関する警告への対応
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ cap-go/ capgo-skills --skill capacitor-ios-resizabilityインストール後、Claude Code で/capacitor-ios-resizabilityを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
metadata.jsonreferences/info-plist-and-scenes.mdnative-replacements.mdplugin-audit.mdswiftui-in-plugins.mdweb-layer.mdscripts/scan-legacy-apis.sh詳細
Capacitor iOS アプリのサイズ変更可能なウィンドウ
Capacitor アプリは、CAPBridgeViewController 内のウィンドウ全体を占める WKWebView です。Web ビューはウィンドウに追従します。必要なのは、幅の変更に応じて Web レイアウトを更新し、1 つのフルスクリーンウィンドウを前提とするネイティブコード(アプリ、カスタムコード、プラグイン)を取り除くことです。
使用する場面
次の場合に使用します。
- iPad のマルチタスク、ステージマネージャ、ウィンドウ表示の iPad アプリ、折りたたみ式 iPhone、または外部ディスプレイに向けてアプリを準備する場合
- ウィンドウのサイズ変更時にレイアウトが崩れる、または更新されない場合
- プラグインのネイティブオーバーレイ(スキャナー、カメラプレビュー、カスタムシート)のサイズや位置が、画面分割表示で合わない場合
- Xcode または App Store Connect が
UIRequiresFullScreen、iPad の向きの不足、または起動画面の要件について警告する場合 - ユーザーが
UIScreen.main、userInterfaceIdiom、interfaceOrientation、または AppDelegate のライフサイクルの使用を取り除くよう求める場合
次の場合は使用しないでください。
- CSS の
env(safe-area-inset-*)設定やノッチのパディングのみの場合:safe-area-handling - AppDelegate から SceneDelegate への移行の場合:
capacitor-uiscene-migration(Xcode 27 の前提条件) - キーボードとの重なりの場合:
capacitor-keyboard - Tailwind のブレークポイントのみの場合:
tailwind-capacitor
計画に影響する事実
- iOS 27 は
UIRequiresFullScreenを無視し、いずれにせよシーンのサイズを変更します(TN3192)。このキーを黙って削除しないでください。削除すると、現行の iOS ですぐにアプリのサイズを変更できるようになります。独断でUIRequiresFullScreenIgnoredStartingWithVersionを追加しないでください。その値によって、どのリリースで従来の動作を維持するかが決まります。どちらも、テスト後にユーザーが判断します。 - **iOS 27 SDK では起動画面の宣言が必須です。**宣言がないと、アップロードは
ITMS-90870で拒否されます。Capacitor のテンプレートではUILaunchStoryboardNameが設定されています。維持してください。 - **Xcode 27 ではシーンライフサイクルが必須です。**Capacitor 8.5 のテンプレートには
SceneDelegate.swiftが含まれています。これがない場合、AppDelegate のライフサイクルメソッドだけが通知手段となり、マルチウィンドウでは適切ではありません。UIApplicationSceneManifestがない場合は、先にcapacitor-uiscene-migrationを実行してください。 - **
UIApplicationSupportsMultipleScenes = falseを維持してください。**各シーンで独自のCAPBridgeViewControllerが作成され、2 つ目の WebView とプラグイン一式が生成されます。Capacitor 8.5 では、プラグインが準備できるようシーン単位の通知が追加されましたが、テンプレートではマルチウィンドウはサポートされていません。単一シーンであればサイズ変更できます。 CAPBridgeViewControllerは iPhone 用のキーUISupportedInterfaceOrientationsのみからsupportedInterfaceOrientationsを構築し、UISupportedInterfaceOrientations~ipadは参照しません(Capacitor 8.5 のソース)。iPad ですべての向きを宣言していても、ブリッジのマスクによってロックされることがあります。この点を報告してください。ユーザーが iPad で異なる動作を望む場合に限り、ブリッジのサブクラスでsupportedInterfaceOrientationsをオーバーライドしてください。- Web レイヤーはサイズ変更イベントを自動的に受け取ります。
WKWebViewはウィンドウに合わせてサイズが変わり、resizeを発火します。問題の原因は、ビューポートではなくデバイス情報を読み取るレイアウトコードです。 - プラグインはサードパーティコードです。
node_modulesの編集内容は、インストール時に失われます。プラグインの調査結果を報告し、プラグインをアップグレードするか、上流に課題を提出するか、ユーザーの承認を得たうえで暫定策としてのみpatch-packageを使用してください。
参考資料
トピックが関係する場合にのみ、参考資料を読み込んでください。
| ファイル | 読み込むタイミング |
|---|---|
| references/info-plist-and-scenes.md | Info.plist のキー、向きのマスク、シーンのライフサイクル、および呼び出されなくなる AppDelegate のメソッドを確認するとき |
| references/web-layer.md | CSS/JS のレイアウト(ビューポート、単位、デバイス判定、安全領域の実行時の変化)を監査・修正するとき |
| references/native-replacements.md | Swift/ObjC の UIScreen.main、向き、デバイス種別、キーウィンドウ、ライフサイクル、ハードコードされたインセットを置き換えるとき |
| references/plugin-audit.md | node_modules 内のプラグインのスキャン、優先度の判断、プラグイン作成者が変更すべき内容を確認するとき |
| references/swiftui-in-plugins.md | サイズ変更が必要なネイティブ SwiftUI 画面をプラグインまたはアプリが表示するとき、および iOS 27 SDK の SwiftUI の変更を確認するとき |
スクリプト:scripts/scan-legacy-apis.sh は ios/App/App とすべての node_modules/**/ios フォルダーをスキャンし、サイズ変更に関連する Info.plist のキーを出力します。読み取り専用です。
ワークフロー
1. 前提条件(読み取り専用)
ios/App/App/Info.plist、AppDelegate.swift、SceneDelegate.swift、@capacitor/ios のバージョン、および TARGETED_DEVICE_FAMILY のビルド設定(1,2 = iPhone と iPad)を確認します。次の内容を報告してください。
| 確認項目 | OK の条件 | それ以外の場合 |
|---|---|---|
| 起動画面 | UILaunchStoryboardName または UILaunchScreen が存在する | ITMS-90870 のリスクを報告します |
| シーンのライフサイクル | UIApplicationSceneManifest が存在し、SceneDelegate.swift がターゲットに含まれている | まず capacitor-uiscene-migration に進みます |
| iPad の向き | UISupportedInterfaceOrientations~ipad に4方向すべてが記載されているか、iPad 用のキーがない | 不足している向きを列挙します。上記のブリッジのマスクに関する事実にも触れます |
| 全画面表示のオプトアウト | UIRequiresFullScreen が存在しない | iOS 27 では無視されることを報告します。変更前にユーザーに確認してください |
2. スキャン
bash <skill>/scripts/scan-legacy-apis.sh .
Web コードもスキャンします(references/web-layer.md)。
grep -rnE 'screen\.(width|height|availWidth)|window\.orientation|orientationchange|\b100vh\b|navigator\.userAgent.*(iPad|iPhone)|isPlatform\(.(ipad|tablet|iphone)|innerWidth' src --include='*.{ts,tsx,js,jsx,vue,svelte,css,scss}'
ファイルごとに1項目を記載した TODO リストを作成します。大規模なプロジェクトでは、ファイルを3〜5個ずつ処理します。リスト内の各ファイルに変更を加えるか、変更しない理由を記録してください。
3. 報告してから確認する
調査結果をアプリの Web コード、アプリのネイティブコード、プラグイン(パッケージ別)、Info.plist に分類します。それぞれについて修正内容を示します。次の変更を行う前にユーザーに確認してください。
UIRequiresFullScreen、向きのキー、または向きのマスクを変更する- 共有ネイティブコードの公開メソッドのシグネチャを変更する
node_modules内のプラグインにパッチを適用する
4. 修正する
- まず Web レイヤーを修正します。通常、修正の大部分はこれで完了します:references/web-layer.md。
- アプリのネイティブコード:references/native-replacements.md。対象 API を含む行だけを編集します。すべての
if/else分岐と#availableガードを維持してください。動的な値をリテラルに置き換えてはいけません。また、あるグローバル(UIScreen.main)を別のグローバル(UIApplication.shared、UITraitCollection.current、UIDevice.current)に置き換えてはいけません。 - 空のテンプレートスタブ(
applicationDidBecomeActiveなど、コメントしかないもの)は問題ありません。コードが含まれている場合にのみ移動してください。 - プラグイン:references/plugin-audit.md。
5. 検証する
npx cap sync ios
xcrun simctl list devices available | grep -i ipad
npx cap run ios --target <iPad-simulator-UDID>
- iPad シミュレーター(iPadOS 26 以降)でアプリをウィンドウ表示に切り替え、ウィンドウの隅をドラッグします。狭い、中程度、広い各サイズを確認してください。別のアプリとの Split View も試してください。
- 各サイズで回転させます。狭いウィンドウでキーボードを開閉します。
- 狭い幅で、プラグインのネイティブオーバーレイ(スキャナー、カメラプレビュー、ピッカー)を確認します。
- アプリをバックグラウンドとフォアグラウンドに切り替えます。JS の
pause/resumeが発火する必要があります。 - Xcode に折りたたみ式 iPhone シミュレーターがある場合は、同様に折りたたみと展開をテストします。
- スキャンを再実行します。残ったヒットには、それぞれ理由を記録する必要があります(カメラ撮影時の向きや分析など、レイアウト以外の用途)。
エラー処理
| 症状 | 原因 | 対処法 |
|---|---|---|
| サイズ変更後もレイアウトが古いサイズのままになる | JS が起動時の window.innerWidth / screen.width をキャッシュしているか、CSS で 100vh を使用している | resize 時にサイズを読み取るか、CSS を使用します。100vh を 100dvh に置き換えます |
| 一部のウィンドウサイズでのみ、ステータスバーやホームインジケーターの下にコンテンツが表示される | セーフエリアのインセットを一度だけ読み取っているか、片側のインセットを両側に適用している | CSS で各辺に env(safe-area-inset-*) を使用します。JS では決してキャッシュしないでください |
| 分割表示でプラグインのオーバーレイが誤った領域を覆う | プラグインが UIScreen.main.bounds を使ってビューのサイズを決定している | プラグインを更新するか、スキャン行を添えて上流に報告します |
| アプリは起動するが、iOS 26 でサイズ変更できない | UIRequiresFullScreen = true | テスト後にユーザーが削除するまでは想定された動作です |
ITMS-90870 でアップロードが拒否される | 起動画面のキーがない | LaunchScreen.storyboard を指定した UILaunchStoryboardName を復元します |
SceneDelegate の追加後に pause / resume が呼び出されなくなる | AppDelegate のライフサイクルメソッドにカスタムコードがある | シーンメソッドに移すか、通知を監視します(参考情報) |
関連スキル
safe-area-handling:CSS の env() 変数とステータスバーのオーバーレイcapacitor-uiscene-migration:SceneDelegate の導入。シーン対応の修正に必要ですtailwind-capacitor:Tailwind のレスポンシブブレークポイントcapacitor-testing:シミュレーターとデバイスでの検証サイクルcapacitor-plugin-upgrade-v8-to-v9:プラグインの修正に新しいメジャーバージョンが必要な場合