mcpField
A
app-resizability

app-resizability

github.com/tartinerlabs開発843 回インストール今日更新
リポジトリ

app-resizability について

Swift と Objective-C の UIKit アプリを、シーンサイズの変更やマルチウィンドウ、現行の iOS ライフサイクルに対応させるコーディングスキルです。対象を絞った API 置換と、制御フローや変更範囲の維持を重視します。

主な機能

  1. 01旧式の共有状態 API の更新
  2. 02シーンライフサイクルへの移行
  3. 03サイズ変更可能なシーンとウィンドウへの対応
  4. 04Swift と Objective-C に対応
  5. 05安全で範囲を限定した編集の指針

活用シーン

  1. 01折りたたみ式 iPhone 向けのアプリ準備
  2. 02ウィンドウサイズ変更時のレイアウト修正
  3. 03画面分割や Stage Manager への対応

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/tartinerlabs/skills --skill app-resizability

インストール後、Claude Code で/app-resizabilityを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
idiom-task.md
orientation-task.md
safe-area-task.md
scene-lifecycle-task.md
uiscreen-task.md

詳細

アプリのサイズ変更対応スキル

使用するタイミング

API 名が指定されているかどうかにかかわらず、次のいずれかに関する依頼では、このスキルを使用してください。

  • 折りたたみ式 iPhone Duo に向けてアプリを準備または最適化する。
  • 実行中にウィンドウのサイズが変わったときに、適応する必要があるアプリ。
  • Split View でのマルチタスク、Stage Manager、またはサイズ変更可能なシーン。
  • 以下の「対象範囲」に記載されている非推奨 API。

依頼が技術的な内容である必要はありません。「アプリを iPhone Duo に向けて準備して」「このアプリを折りたたみ式 iPhone 向けに最適化して」「このアプリが適切にサイズ変更されるようにして」は、すべてこのスキルを有効にします。iPhone Duo は折りたたみ式 iPhone なので、iPhone Duo と折りたたみ式 iPhone に関する質問は、同じ依頼として扱ってください。画面サイズが変わるとすべてのタスクが一度に表面化するため、折りたたみ式 iPhone Duo に関する依頼は、「タスクレジストリ」のすべてのタスクを依頼されたものとして扱ってください。

目的

UIKit アプリを最新の iOS で正しく動作するようにモダナイズします。

  • レガシーな共有状態 API への参照を排除する
  • アプリケーションのライフサイクルからシーンのライフサイクルへ移行する
  • 動的なシーンサイズとマルチウィンドウ環境に対応する

対象範囲

このスキルでは、Swift と Objective-C のコードベースの両方を対象に、具体的かつ限定的なモダナイズを行います。

  • レガシーな共有状態 API を、状況に適した最新の API に置き換える
  • シーンベースのライフサイクルに移行する
  • 次の使用を取り除き、サイズ変更可能なユーザーインターフェイスに対応するようアプリを更新する:
    • メイン画面(UIScreen.mainScreen、UIScreen.main)
    • インターフェイスの向き(interfaceOrientation)
    • ユーザーインターフェイスのイディオム(userInterfaceIdiom、UI_USER_INTERFACE_IDIOM())
    • セーフエリアが左右対称であるという前提(safeAreaLayoutGuide、safeAreaInsets)
    • シーンのライフサイクルの代わりにアプリケーションのライフサイクルを使用すること(UIApplicationDelegate)

基本原則

  1. 利用箇所に最も近い情報を使う — 使用箇所に最も近い情報を優先してください(例:ウィンドウの特性情報より、ビューの特性コレクションを使用する)。
  2. 対象 API がある場合は、必ず置き換えを適用する。 TODO だけでは不十分です。対象 API を含むファイルの差分が空であることも不十分です。 ファイルに対象となる非推奨 API が含まれており、現在のタスクのリファレンスファイルにあるいずれかのパターンで具体的な置き換えが可能な場合は、適用してください。対象 API がデッドコード(#if 0/#endif)内にのみある場合に限り、変更を省略できます。有効な置き換え方法が 2 つあり判断に迷う場合は、差分を空にするのではなく、ユーザーの依頼に最も適した方法を選んでください。ファイルを黙ってスキップしてはいけません。 変更を適用しない場合は、可能な選択肢についてユーザーに説明してください。ファイルに対して何も出力しないことは避けてください。単純なファイルで例外的なケースをいつまでも検討し続けてはいけません。置き換えが明白な場合は適用し、次に進んでください。
  3. TODO は実行可能な内容にする。 変更が必要な理由、置き換え後のコード例、ライフサイクルやスレッドに関する注意点を明記してください。TODO は変更していないコードの直前に、独立した行として配置し、コードと同じ行に書かないでください。「後で修正する」といった曖昧な TODO は、レビューの注意を消費するだけで誰の役にも立たないため、TODO がないよりも悪いものです。 挿入するコメントの各行は、そのコメントが先行する行と同じインデントにしてください。 インデントの異なる継続行があると、ブロックの配置がずれます。位置をそろえるために後続の行を再出力すると、変更を依頼されていない行を編集することになります。
  4. 既存の注釈で移行がすでにカバーされている場合、重複する TODO を追加しないでください。 呼び出し箇所に、バグ報告への参照と組み合わせた #pragma clang diagnostic ignored、既存の // TODO、または移行先を示す非推奨コメントがすでにある場合は、別の注釈を追加しないでください。既存の注釈にない移行ガイダンスを補足できる場合に限り、新しい TODO を追加します。
  5. リスクのあるコード変更を行う前にユーザーに確認してください。対話的な確認ができない場合に限り、TODO を追加してください。 置き換えによって呼び出し元が壊れたり、観察可能な動作が変わったりするおそれがある場合(たとえば、他のモジュールがインポートするヘッダーでメソッドのシグネチャを変更する場合や、左右の判定が重要なのに方向判定を width > height に置き換える場合)は、まずユーザーにどのように進めるか確認してください。スキルを非対話型で実行している場合、またはユーザーがガイダンスの提供を明示的に断った場合に限り、TODO を追加して先に進みます。これは、タスクの参照ファイルで指定されている標準的なドロップイン置換には適用されません。そのような置換はコア原則 2 に従って適用してください。
  6. 明示的なユーザー指示を尊重し、それ以外の場合はタスクの参照ファイルのデフォルトを適用してください。 ユーザーが特定の方法(特定の属性、パラメーター名、パラメーターの位置、トレイトの取得元、フォールバック動作など)を指定した場合は、その指示どおりにしてください。より新しい相当機能だと考えるものに黙って置き換えないでください。ユーザーの指示が一般的な場合(「このアプリをモダナイズして」「UIScreen.main の使用箇所を修正して」など)は、現在のタスクの参照ファイルにあるデフォルトを適用してください。
  7. 動的な値をリテラルに置き換えないでください。 置換後も常に動的な値を維持してください。
  8. 制御フローを維持してください。 元のコード構造を保つドロップイン置換を優先してください。直接置換できない場合に限り、ガードや早期リターンを追加してください。制御フロー(if/else、switch/case/default、do/catch)の周辺を編集するときは、編集後も分岐構造が保たれていることを確認してください。if/else を順次実行に変えないでください。そうすると両方の本体が無条件に実行され、重大なバグになります。条件が妥当な分岐はすべて維持し、その中の非推奨の値だけを置き換えてください。分岐を削除してよいのは、現在のタスクでその条件自体を問題として指定し、正しい動作は無条件に行うことだと明示されている場合に限ります。その場合は条件を削除し、正しい動作に該当する本体を残してください。また、レビュー担当者が確認できるよう、要約で削除した分岐を明記してください。
  9. 対象範囲を守ってください。ついでの整理はしないでください。 現在のタスクの対象となる非推奨 API を含む行だけを変更してください。近くにある別の非推奨 API も修正してはいけません。行末の空白を削除したり、空行を整えたり、周辺の書式を「整理」したりしないでください。隣接する行に明らかなモダナイズの機会があっても、そのままにしてください。各タスクは独立しており、対象範囲外の変更は、適切な変更を警告対象にしてしまいます。
  10. 繰り返し使われる式を抽出してください。 同じ置換後の値が同じスコープ内で複数回使われる場合は、名前付きのローカル変数に抽出してください。
  11. グローバルなシーン/ウィンドウ状態をたどらないでください。 置き換えに UIApplication.shared、UIDevice.current、UIScreen.main などの共有オブジェクトを使用しないでください。ローカルオブジェクトを利用できない場合は、メソッドが新しいパラメーターを受け取るように変更し、呼び出し元から渡してください。
  12. パターンはすべて適用してください。部分適用はできません。 現在のタスクで定義されている複数要素からなるパターンは、すべてまとめて一つの変更として適用する必要があります。現在のタスクで API の置換とリアクティブな更新(たとえばトレイト変更の監視)の両方が必要な場合、これらは不可分な一つの変更です。片方だけを適用してはいけません。 タスクで指定されたすべての要素を適用できない場合は、部分的な変更を加えないでください。パターンをすべて適用するか、明示的な理由を示して見送ってください。
  13. 無関係なガードやフォールバックを維持してください。 対象 API への参照を削除するときは、その参照だけを変更してください。呼び出し箇所を囲む respondsToSelector: チェック、nil ガード、if (x != nil) による防御、バージョンチェック(#available、@available)、その他の防御的なロジックを同時に削除してはいけません。ユーザーから明示的な指示がある場合を除きます。各ガードには、SDK バージョン間のセレクターの可用性、nil のウィンドウへの安全性、機能フラグなど、独立した理由があります。モダナイズで置き換えるのは対象の値だけであり、周囲の制御フローではありません。
  14. 対象外への置換を防止してください。 行を編集する前に、次の 2 点を確認してください。(a)その行に、現在のタスクの対象となる非推奨 API が含まれていること。(b)ユーザーが求めている非推奨 API を編集しており、「似ている」だけの近くの行を編集していないこと。

前提条件

Phase 1 の前に、プロジェクトごとに 3 つのチェックをすべて一度実行します。これらのチェックは読み取り専用です。Info.plist またはビルド設定で、キーを追加したり、値を変更したり、キーを削除したりしないでください。読み取った内容を報告してから、ワークフローを続けます。チェックに不合格のアプリは、ソースコードの内容にかかわらずサイズ変更できません。

対象の Info.plist とビルド設定で、各キーを確認します。ビルド設定はプロジェクトファイルとすべての .xcconfig にあります。ビルド時にすべての設定元が統合されるため、報告する前にすべて確認してください。ある設定元にキーがないからといって、何かが証明されるわけではありません。2 つの設定元で同じキーが設定されている場合は、プロジェクトファイルが優先されます。

依頼でプロジェクトではなくファイルが指定されている場合は、3 つのチェックすべてを省略してください。チェックについては何も言わないでください。ファイルシステムを検索してプロジェクトを探さないでください。

チェックすでに満たしている条件それ以外の場合に報告する内容
起動画面ターゲットで UILaunchScreen、UILaunchScreens、UILaunchStoryboardName、UILaunchStoryboards、または INFOPLIST_KEY_UILaunchScreen_Generation が設定されているアプリで起動画面が宣言されていません。iOS 27 では App Store へのアップロードが ITMS-90870 で拒否されます。TN3208 を参照してください。キーは 1 つで十分なので、既存のストーリーボードはそのままにしてください
iPad の向きiPad の宣言ですべての 4 方向が列挙されているか、ターゲットで何も宣言されていない。UISupportedInterfaceOrientations~ipad が iPad の宣言であり、このキーがない場合は通常の UISupportedInterfaceOrientations が使われます宣言から漏れている向きを示してください。supportedInterfaceOrientations のオーバーライドによってシーンがロックされる可能性があること、そのオーバーライドは確認していないことも伝えてください。iPad のみを確認してください。iPhone の宣言が縦向きのみであることは通常です
フルスクリーンのオプトアウトUIRequiresFullScreen が存在しないか、UIRequiresFullScreenIgnoredStartingWithVersion がすでに設定されているターゲットで UIRequiresFullScreen が設定されています。iOS 27 ではこれが無視され、シーンはサイズ変更されます。TN3192 を参照してください

最後の行にある両方のキーは、確認したとおりの状態を維持してください。UIRequiresFullScreen は絶対に削除しないでください。削除するとアプリはすぐにサイズ変更可能になり、レイアウトが対応できていない可能性があります。UIRequiresFullScreenIgnoredStartingWithVersion は絶対に追加しないでください。その値によって、どのリリースで従来の動作を維持するかが決まるため、これは開発者が判断することです。値が 27 以下の場合、iOS 27 でアプリは完全にサイズ変更可能になり、安全な手順とは正反対です。アプリがサイズ変更に対応したら、このキーを削除します。対応を確認するには、アプリを実行してサイズ変更する必要があります。他の部分が正しくても、1 つのビューコントローラーが問題を起こすことがあります。


ワークフロー

フェーズ 0:単純なケースの高速パス

判断ツリーに進む前に、該当箇所が単純なケースに当てはまるか確認してください。 UIScreen.main/UIScreen.mainScreen の該当箇所の多くは、値がその場で使われる UIView/UIViewController のインスタンスメソッド内での単純な置換です。こうしたケースでは分析は不要です。置き換えて先に進んでください。

元のコード置換後
UIView/UIViewController のインスタンスメソッド内の UIScreen.main.scale(Swift)。その場で使用(保存しない)self.traitCollection.displayScale
UIView/UIViewController のインスタンスメソッド内の [UIScreen mainScreen].scale(ObjC)。その場で使用(保存しない)self.traitCollection.displayScale
layoutSubviews、drawRect:、updateConstraints、または viewIsAppearing: 内の UIScreen.main.scaleself.traitCollection.displayScale(登録不要。UIKit が特性の変更時にこれらを自動的に呼び出します)

単純な置換を深く考えすぎないでください。 そのクラスが UIView/UIViewController で、値が ivar、レイヤープロパティ、制約、または保存する画像に代入されていないなら、そのまま置き換えてください。単純なファイルで差分が空のままになるのは、最もよくある間違いです。置換して先に進んでください。 判断ツリーを使うのは、単純なケースに当てはまらない場合(非ビュークラス、キャッシュされた値、クラス/静的メソッド、特別なユーザー指示)のみにしてください。

フェーズ 1:検出

該当するタスクファイルの検出パターンを使って、モダナイズするパターンを特定してください。適用対象のコードベースについて、該当するタスクを 1 つだけでなく、タスクレジストリにあるすべてについて検出を実行してください。下記のタスクレジストリを参照してください。

フェーズ 2:分析

各該当箇所について、周囲のコンテキストを読み、以下を理解してください。

  • クラス階層(UIView/UIViewController のサブクラスか、通常の NSObject か、非ビュークラスか)
  • メソッドの種類(インスタンス、静的、自由関数、キャッシュされた dispatch_once ヘルパー)
  • ライフサイクルの段階(init、viewDidLoad、viewWillAppear、layoutSubviews)
  • コードの意図(コードが確認しようとしていたこと:利用可能な空間、レイアウトの種類、レンダリング、デバイスクラス、ライフサイクル)

有効なタスクの参照ファイルで、このリストにタスク固有の項目が追加される場合があります。

コンテキストウィンドウを小さく保つため、サブエージェントを使って更新が必要なコードを特定してください。

フェーズ 3:判断と検証
条件対応
安全な 1 対 1 の置換が可能適用してください。 コメントを追加しないでください(// TODO: FIXME、// TODO、// FIXME は追加せず、置換のみ行います)。有効なタスクの参照ファイルで指定された置換を使用してください。
複数の有効な方法がある、またはコードの移動が 10 行を超えるユーザーに確認してください。
安全な置換が不可能(極めてまれ)ユーザー向けに明示的なタスクを記載した todo を追加してください。 差分がないまま何も出力してはいけません。適用対象がないと結論付ける前に、各パターンをサブエージェントで再確認してください。

コードを変更する前に、サブエージェントを使って有効なタスクの「ファイル作成後のチェックリスト」に照らして検証してください。

フェーズ 3b:ファイル処理の完全性

対象の非推奨 API が含まれるすべてのファイルを処理してください。 早々に作業を終えたり、ファイルをスキップしたり、作業キューから黙ってファイルを外したりしないでください。フェーズ 1 で特定されたファイルに差分もスキップ理由の説明もない場合、処理の失敗です。

ファイルの明示的な追跡: 処理の開始時に、利用可能なタスク/TODO ツールまたは Markdown ファイルを使って、変更対象のファイルの完全なリストを書き出してください。各ファイルを処理するごとに、完了としてマークしてください。終了前にこのリストと出力を照合してください。差分も明示的なスキップ理由もないファイルがあれば、完了前に必ず対応してください。

コンテキストサイズ: コンテキストサイズが気になる場合は、個々のファイルまたはタスクの処理にサブエージェントを利用してください。

ファイルの黙った脱落の防止: 終了前に、サブエージェントを使って、指定されたファイルのリストと出力を作成したファイルのリストを比較してください。出力に含まれていないファイルがあれば、戻って処理してください。ファイルが黙って脱落する主な原因は次のとおりです。

  • ファイルサイズ: 大きなファイル(1000 行以上)も例外ではありません。同じ方法で処理してください。
  • 複雑さ: プリプロセッサマクロ、複雑なクラス階層、または特殊なコードパターンを含むファイルも変更が必要です。
  • プロジェクトのまとまり: 特定のプロジェクトやディレクトリに属するファイルをすべてスキップしないでください。同じプロジェクトの複数のファイルを脱落させたことに気付いた場合は、体系的な問題を示しているため、調査して修正してください。
  • 曖昧さ: ファイルの修正方法が不明な場合は、ユーザーに確認してください。差分がない状態を黙って出力しないでください。

大規模または複雑なファイル: プリプロセッサの使用頻度が高いファイル(#if/#ifdef のネスト)、1000 行以上のファイル、またはあまり一般的でないパターン(C++ の相互運用、dispatch_once によるキャッシュ、深くネストしたマクロ)も処理対象です。そのようなファイルに対象 API が含まれている場合は、同じ判断フローを適用してください。ファイルを一度に編集するには大きすぎる場合は、非推奨 API の使用箇所を一つずつ処理してください。必要に応じてサブエージェントを利用してください。マクロ展開やプリプロセッサの複雑さのために安全な置き換えを本当に判断できない場合は、ユーザーに確認してください。黙ってスキップしてはいけません。

バッチ処理の徹底: ファイルのリストを処理する際、最初にすべてのファイルを分析してから、差分をまとめて出力しないでください。代わりに、ファイルを一つずつ、または少数(3~5 ファイル)ずつ処理してください。コンテキストを読み、判断し、差分を作成してから、次のバッチに進んでください。これにより、出力制限やコンテキストの枯渇によってリストの後半が黙って脱落するのを防げます。指定されたファイル数より出力したファイル数が少ないことに気付いた場合は、そこで止め、終了前に残りを処理してください。

単純な置き換えで済むはずのファイルに空の差分がある場合は、戻って処理してください。単純なファイルはすぐに処理できるため、決して脱落させてはいけません。

フェーズ 4:実装

有効なタスクの参照ファイルにある実装のゲート、ルール、およびファイル処理後のチェックリストを適用してください。パターン固有の判断フロー、ゲートの質問、検証ルールは、それらが適用される各タスクファイル内に記載されています。検証にはサブエージェントを利用してください。

フェーズ 5:最終検証

ファイル網羅性の監査: サブエージェントを使って、指定された(またはフェーズ 1 で検出した)ファイルのリストと、実際に差分を作成したファイルを比較してください。入力ファイルごとに、空でない差分が必要です。変更がないファイルがあれば、戻って今すぐ処理してください。

有効なタスクの参照ファイルに、タスク固有の検証手順が追加されている場合があります。

タスクレジストリ

開発者のリクエストで対象が明示的に絞られていない限り、このレジストリにあるすべてのタスクをコードベースに適用してください。各タスクは独立しており、それぞれの参照ファイルに独自の検出パターン、判断ツリー、検証ルールがあります。上から順に実行してください。

タスクファイル説明
UIScreen.main の最新化uiscreen-task.mdUIScreen.main を状況に応じた API に置き換えます
userInterfaceOrientation の最新化orientation-task.mdレイアウト関連の向きチェックをサイズクラスまたはウィンドウの境界に置き換え、非推奨のシーンジオメトリコールバックを移行します
シーンのライフサイクル移行scene-lifecycle-task.mdAppDelegate を SceneDelegate に移行します
セーフエリアのインセットsafe-area-task.mdtopLayoutGuide と bottomLayoutGuide を置き換え、インセットの固定値をセーフエリア参照に置き換え、既存の参照が非対称なセーフエリアやアプリの実行中に変化するインセットでも機能するようにします
userInterfaceIdiom の最新化idiom-task.mdレイアウト関連の idiom チェックをサイズクラスに置き換え、本当に必要な idiom はローカルのトレイトコレクションから読み取ります

コメント