中国語readme:中文集成指南
コードインジェクションを使用すると、完全な再構築を実行したり再起動したりすることなく、IOSシミュレーターで機能の実装とクラス、構造体、または列挙の任意の方法を更新できます。これにより、開発者にコードを調整するか、デザインを反復する時間を大幅に節約できます。事実上、Xcodeを「ソースエディター」から「プログラムエディター」にすることに変更します。ソースの変更は、ディスクだけでなく、実行中のプログラムに直接保存されます。
インジェクションを使用するようにプロジェクトを設定することは、アプリのGitHubリリースの1つまたはMac App Storeからダウンロードし、アプリのどこかにコードを追加してスタートアップで実行するのと同じくらい簡単です(実際にアプリ自体を実行する必要はなくなりました)。
#if DEBUG
Bundle ( path : " /Applications/InjectionIII.app/Contents/Resources/iOSInjection.bundle " ) ? . load ( )
//for tvOS:
Bundle ( path : " /Applications/InjectionIII.app/Contents/Resources/tvOSInjection.bundle " ) ? . load ( )
//Or for macOS:
Bundle ( path : " /Applications/InjectionIII.app/Contents/Resources/macOSInjection.bundle " ) ? . load ( )
#endifまた、プロジェクト内のターゲットの「他のリンカーフラグ」( Debug構成のみ)にオプション-Xlinkerと-interposable (二重引用符と別々の行に)を追加して、「インターポーズ」を有効にすることも重要です(以下の説明を参照)。

その後、シミュレーターでアプリを実行すると、ファイルウォッチャーがホームディレクトリ用に開始したというメッセージが表示され、現在のプロジェクトにソースファイルを保存するたびに、注入されたと報告する必要があります。これは、以前は古い実装と呼ばれていたすべての場所が更新され、コードの最新バージョンを呼び出すことを意味します。
画面上で結果を見るほど簡単ではありません。すぐに新しいコードが実際に呼び出される必要があります。たとえば、ビューコントローラーを注入すると、再表示を強制する必要があります。この問題を解決するために、クラスは、ディスプレイの更新を実行するためにクラスが注入された後に呼び出される@objc func injected()メソッドを実装できます。使用できる手法の1つは、プログラムのどこかに次のコードを含めることです。
#if DEBUG
extension UIViewController {
@ objc func injected ( ) {
viewDidLoad ( )
}
}
#endifこの問題のもう1つの解決策は、このブログ投稿で導入されたInject Swiftパッケージを使用した「ホスティング」です。
メモリ内でデータがレイアウトされる方法に変更を挿入することはできません。つまり、ストレージでプロパティを追加、削除、または並べ替えることはできません。ファイナル以外のクラスの場合、これはメソッドの追加または削除にも適用されます。ディスパッチに使用されるvtableそれ自体が注入上で変化してはならないデータ構造です。また、上記のようにディスプレイを更新するために、どのコードを再実行する必要があるかを注入することはできません。また、アクセス制御に夢中にならないでください。 privateと方法は、特にglobal対話可能なシンボルではないため、拡張機能では直接注入することはできません。それらは、挿入されているファイル内でのみアクセスできるため、通常間接的に注入しますが、これは混乱を引き起こす可能性があります。最後に、注入中にソースファイルが追加/変更/削除されるため、注入はうまく対処しません。アプリをビルドして再起動するか、プロジェクトを閉じて再開して、古いXcodeビルドログをクリアする必要がある場合があります。
Swiftuiは、もしあれば、ディスプレイを更新するための特定のメカニズムがあるため、UIKITよりも注入に適していますが、注入する各View構造体にいくつかの変更を加える必要があります。強制的に最も簡単な方法は、注入が発生したときに観察するプロパティを追加することです。
@ ObserveInjection var forceRedrawこのプロパティラッパーは、hotswiftuiまたはswiftパッケージを挿入しています。基本的に@Published整数が含まれていますあなたのビューは、各注入でその増分を観察します。次のいずれかを使用して、プロジェクト全体でこれらのパッケージのいずれかを利用可能にすることができます。
@ _exported import HotSwiftUI
or
@ _exported import Inject信頼できるSwiftui注入に必要な2番目の変更は、これらのパッケージのViewを拡張する.enableInjection()メソッドを使用して、 AnyViewでwrappingをラッピングすることにより、身体の特性の「リターンタイプを消去」することです。これは、SwiftUI要素を追加または削除すると、crash落する可能性のあるメモリレイアウトの変更に相当するコンクリートリターンタイプの身体プロパティを変更できるためです。要約すると、各体のテールエンドは常に次のようになります。
var body : some View {
VStack or whatever {
// Your SwiftUI code...
}
. enableInjection ( )
}
@ ObserveInjection var redrawこれらの変更は、 Releaseビルドのためにノーオプに最適化するため、これらの変更を生産コードに残すことができます。
Xcode 16の新機能は、 SWIFT_ENABLE_OPAQUE_TYPE_ERASUREビルド設定です。この設定はデフォルトでオンになっており、ビューボディを明示的に消去する必要はありません。再描画を強制するために@ObserveInjectionする必要があります。
詳細については、Xcode16.2リリースノートを参照してください。
これは機能する可能性がありますが、インジェクションIII.AppのGitHub 4.8.0+リリースの1つを実際に実行する必要があります。ユーザーをデフォルトに設定して、アプリをオプトインして再起動します。
$ defaults write com.johnholdsworth.InjectionIII deviceUnlock any
次に、注入バンドルをロードする代わりに、このスクリプトを「ビルドフェーズ」で実行します:(プロジェクトビルド設定「ユーザースクリプトサンドボックス」をオフにする必要があります)
RESOURCES=/Applications/InjectionIII.app/Contents/Resources
if [ -f "$RESOURCES/copy_bundle.sh" ]; then
"$RESOURCES/copy_bundle.sh"
fi
そして、アプリケーションで起動時に次のコードを実行します。
#if DEBUG
if let path = Bundle . main . path ( forResource :
" iOSInjection " , ofType : " bundle " ) ??
Bundle . main . path ( forResource :
" macOSInjection " , ofType : " bundle " ) {
Bundle ( path : path ) ! . load ( )
}
#endifこの構成に切り替えると、シミュレータを使用するときにも機能します。 Wi-Fiを介してプログラムをInjectioniii.appに接続する方法の詳細については、HotReloadingプロジェクトのReadmeを参照してください。また、ポップダウンメニューからファイルウォッチャーのプロジェクトディレクトリを手動で選択する必要があります。
動作しますが、開発中に「硬化ランタイム」の下で「アプリサンドボックス」と「ライブラリの検証」を一時的にオフにする必要があります。そうすることで、コードを動的にロードできるようになります。コード設計の問題を回避するために、上記の実際のデバイスでの注入の指示に詳述されているように、新しいcopy_bundle.shスクリプトを使用してください。
注入は長年にわたってさまざまな方法で機能しており、Objective-Cの「スウィズリング」APIを使用し始めていますが、現在では、任意のタイプの迅速な方法または計算されたプロパティのソリューションを提供する「インターポーズ」と呼ばれるAppleのリンカーの特徴を中心に構築されています。
コードがSwiftで関数を呼び出すと、一般に「静的に発送されます」、つまり、呼び出される関数の「マングルされたシンボル」を使用してリンクされます。ただし、アプリケーションを「介入可能な」オプションにリンクするたびに、作成可能なメモリのセクションを通じて呼び出されているすべての関数のアドレスが見つかる場所に追加のレベルの間接が追加されます。実行可能なコードとFishhookライブラリをロードするオペレーティングシステムの機能を使用して、任意の機能の新しい実装を「干渉」し、実行時に残りのプログラムに効果的にステッチすることが可能です。その時点から、新しいコードがプログラムに組み込まれているかのように実行されます。
インジェクションでは、 FSEventSteam APIを使用して、ソースファイルが変更されたときに監視し、最後のXcodeビルドログを再コンパイルする方法をスキャンし、プログラムにロードできる動的ライブラリをリンクします。注入のランタイムサポートは、ダイナミックライブラリをロードし、それを含む関数定義をスキャンし、それがプログラムの残りの部分に「介入」します。これは、非ファイナルクラスのメソッドの派遣が「vtable」(C ++仮想メソッドを考えてください)を使用しているため、完全なストーリーではありません。これも更新する必要がありますが、プロジェクトはLegacy Objective-Cの「Swizzling」とともに面倒を見ます。
注入の仕組みについてもっと興味があるなら、最良のソースは私の本Swift SecretsまたはInjectionlite Swiftパッケージでの新しいスタートオーバーリファレンス実装のいずれかです。 「インターポーズ」の詳細については、このブログ投稿またはFishhookプロジェクトのReadmeを参照してください。アプリ自体の編成の詳細については、roadmap.mdに相談してください。
射出を機能させるには、3つのコンポーネントがあります。ファイルウォッチャー、変更されたファイルを再コンパイルし、ロードできる動的ライブラリを構築するためのコードと、実行中にコードの新しいバージョンを縫う注入コード自体を構築します。これらの3つのコンポーネントをどのように組み合わせるかにより、注入を使用する方法の数が生じます。
「Injection Classic」は、GitHubからバイナリリリースの1つをダウンロードし、InjectionIii.Appを実行する場所です。次に、上記のシミュレータに示すように、そのアプリ内のバンドルの1つをプログラムにロードします。この構成では、ファイルウォッチャーとソースの再コンパイルがアプリ内で実行され、バンドルはソケットを使用してアプリに接続して、新しいダイナミックライブラリのロードの準備ができていることを知ります。
「App Store Injection」このバージョンのアプリはサンドボックス化されており、ファイルウォッチャーはアプリ内でまだ実行されていますが、再コンパイルとロードはシミュレータ内で実行されるように委任されます。これにより、シミュレーターはケースに敏感なファイルシステムを使用して、実際のデバイスの忠実なシミュレーションになるため、Cヘッダーファイルに問題が発生する可能性があります。
「HotReloading Injection」は、デバイスでアプリを実行している場所であり、実際の電話にMacのファイルシステムからバンドルをロードできないため、通常は動的荷重を実行するためにバンドルにあるすべてのコードを含むすべてのコードを含むHotReLoading Swiftパッケージ(開発中!)に追加されます。これには、非サンドボックス化されたバイナリリリースの1つを使用する必要があります。また、上記のcopy_bundle.shスクリプトに置き換えられました。
「スタンドアロン注入」。これはプロジェクトの最新の進化であり、アプリ自体を実行しなくなりましたが、注入バンドルのいずれかを単純にロードし、ファイルウォッチャーをロードするだけで、再コンパイルとインジェクションはすべてシミュレータ内で実行されます。デフォルトでは、これはホームディレクトリ内のSwiftファイルの変更を監視していますが、環境変数INJECTION_DIRECTORIESを使用してこれを変更できます。
InjectionLiteは、参照用のスタンドアロン注入の最小限の最小限の実装です。この迅速なパッケージを追加するだけで、シミュレータに注入できるはずです。
InjectionNextは、現在、大規模なプロジェクトでより速く、より信頼性が高いはずのインジェクションの実験バージョンです。 Xcodeのデバッグフラグに統合して、ビルドログを解析しないようにファイルを再コンパイルする方法を見つけ、 InjectionLiteからのインジェクションのクライアントの実装を再利用します。 Cursorなどの外部エディターで使用するために、InjectionNextはファイルウォッチャーを使用して編集を検出し、フォールバックしてログ解析コードを構築することもできます。
これらのすべてのバリエーションでは、デバッグビルドに「-Xlinker -Interposble」リンカーフラグを追加する必要があります。そうしないと、クラスの非ファイナル方法のみを注入でき、すべてが高レベルの注入またはHotswiftuiのいずれかと組み合わせて使用できます。
カスタマイズに使用できるさまざまな環境変数を含む単に「あまりにも多くの情報」が含まれている場合は、古いReadmeを参照してください。いくつかの例:
| 環境var。 | 目的 |
|---|---|
| Injection_Detail | 実行されたすべてのアクションの冗長出力 |
| Injection_trace | 注入された関数へのログコール(v4.6.6+) |
| Injection_host | Device On-DeviceインジェクションのMACのIPアドレス |
Injection_Trace環境変数を使用すると、ファイルを挿入すると、ファイル内の関数とメソッドへのすべての呼び出しが、デバッグの援助としての引数値とともにログを追加します。
注入IIIのあまり知られていない機能は、個々のXCTestクラスを挿入してすぐに実行する場合にアプリのテストを実行した場合、変更するたびに失敗した場合に報告します。
このプロジェクトには、Rentzsch/Mach_Inject、Erwanb/Machinjectsample、Davedelong/Ddhotkey、ACJ/TimelapseBuilder-Swiftのそれぞれのライセンスのコードが含まれています。
アプリトレース機能では、MITライセンスの下でSwiftTraceプロジェクトを介してOliverletterer/IMP_IMPLEMENTATIONFORWARDINGTOSELECERTTOSELINEのトランポリン実装を使用します。
Swifttraceは非常に便利なhttps://github.com/facebook/fishhookを使用しています。ライセンスの詳細については、アプリバンドルに含まれるプロジェクトソースとヘッダーファイルを参照してください。
このリリースには、MITライセンスの対象となるHTMLキャンバスに「ドット」ファイルをレンダリングするための非常にわずかに変更されたバージョンの優れたCanvizライブラリが含まれています。変更は、ノードのIDを通過してノードラベルタグ(行212)に通過し、ノードとそれらをリンクするラインのレンダリング(行406)を逆転させ、「Canviz-0.1/canviz.js」で着色できるようにエッジパスを格納します(行66および303)。
また、MITライセンスの下での注入を使用してコードを評価するためのCodemirror JavaScriptエディターも含まれています。
素晴らしいアプリのアイコンは、pixel-mixer.comのKatyaのおかげです。