中文讀數:中文集成指南
代碼注入允許您在iOS模擬器中逐步更新功能的實現以及類,結構或枚舉的任何方法,而無需執行完整的重建或重新啟動您的應用程序。這為開發人員節省了大量的時間調整代碼或在設計上迭代。有效地,它將XCode從“源編輯器”更改為“程序編輯器” ,其中源更改不僅將源更改保存到磁盤,而且直接將其直接放入您的運行程序中。
現在,將您的項目設置為使用注射,就像下載應用程序的GitHub版本之一或從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添加選項-Xlinker和-interposable (無需雙引號,在單獨的行上)將選項添加到項目中目標(僅用於Debug配置)的“其他鏈接器標誌”中,以啟用“插入”(請參見下面的說明)。

之後,當您在模擬器中運行應用程序時,您應該看到一條消息,說明觀察者已經為您的主目錄啟動了文件,並且每當您將源文件保存在當前項目中時,都應該報告它已被注入。這意味著所有以前稱為舊實施的地方都將被更新以調用您的代碼的最新版本。
不像立即在屏幕上看到結果的結果那樣簡單。新代碼需要實際調用。例如,如果您注入視圖控制器,則需要強制重新播放。為了解決此問題,類可以實現@objc func injected()方法,該方法將在全類註入以執行顯示的任何更新之後被調用。您可以使用的一種技術是在程序中的某個地方包括以下代碼:
#if DEBUG
extension UIViewController {
@ objc func injected ( ) {
viewDidLoad ( )
}
}
#endif解決此問題的另一個解決方案是使用此博客文章介紹的Intext Swift軟件包“託管”。
您無法注入更改對內存中數據列出的方式,即您無法使用存儲添加,刪除或重新排序屬性。對於非最終類別,這也適用於添加或刪除方法,因為用於調度的vtable本身就是一個數據結構,該數據結構一定不能改變注射。注射還無法弄清楚需要重新執行哪些代碼以更新上面討論的顯示。另外,不要被訪問控制所帶走。 private屬性和方法不能直接注入,尤其是在擴展中,因為它們不是global可插的符號。它們通常間接注射,因為它們只能在被注入的文件中添加,但這會引起混亂。最後,注射不能很好地應對注射過程中添加/重命名/刪除的源文件。您可能需要構建和重新啟動應用程序,甚至可以關閉並重新打開項目以清除舊的Xcode構建日誌。
SwiftUi(如果有的話)比Uikit更適合注射,因為它具有更新顯示屏的特定機制,但是您需要對要注入的每個View結構進行幾個更改。最簡單的方法是添加在註射時觀察的屬性:
@ ObserveInjection var forceRedraw此屬性包裝器可在Hotswiftui或Indext Swift軟件包中找到。它本質上包含一個@Published Integer您的觀點,觀察到每次注射都會增加。您可以使用以下一項在整個項目中提供這些軟件包之一:
@ _exported import HotSwiftUI
or
@ _exported import Inject您需要進行可靠的SwiftUI注入需要做出的第二個更改是通過使用.enableInjection()方法在這些軟件包中擴展View將其包裝在AnyView中“刪除返回類型”。這是因為,當您添加或刪除Swiftui元素時,它可以更改車身屬性的混凝土返回類型,該屬性構成可能崩潰的內存佈局更改。總而言之,每個身體的尾端應始終看起來像這樣:
var body : some View {
VStack or whatever {
// Your SwiftUI code...
}
. enableInjection ( )
}
@ ObserveInjection var redraw您可以將這些修改留在生產代碼中,因為對於Release構建,它們將優化為No-Op。
Xcode 16中的新是SWIFT_ENABLE_OPAQUE_TYPE_ERASURE構建設置。默認情況下,此設置將打開,您無需明確擦除視圖。您仍然需要@ObserveInjection才能迫使重新繪製。
有關更多信息,請參見Xcode 16.2發行說明。
這可以正常工作,但是您實際上需要運行IncectionIII.App的GitHub 4.8.0+版本之一,請設置一個用戶默認值以選擇加入並重新啟動應用程序。
$ 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切換到此配置後,使用模擬器時也可以工作。請諮詢HotreloDading項目的回教徒,以獲取有關如何調試程序將您的程序連接到wi-Fi的indectionii.app的詳細信息。您還需要從“流行菜單”菜單中手動選擇文件觀察器的項目目錄。
它有效,但您需要在開發過程中暫時關閉“硬化運行時”下的“應用沙盒”和“庫驗證”,以便可以動態加載代碼。為了避免代碼簽名問題,請使用上述真實設備上註入的說明中詳細介紹的新copy_bundle.sh腳本。
多年來,Indection一直使用各種方式,從Objective-C開始使用“ swizzling” API,但現在主要圍繞著Apple鏈接器的功能“ Interposing”構建,該功能為任何類型的任何SWIFT方法或計算屬性提供了解決方案。
當您的代碼在Swift中調用一個函數時,通常“靜態派遣”,即使用所調用的函數的“雜項符號”鏈接。但是,每當您將應用程序與“ - 可間接”選項鍊接起來時,都會添加附加級別的間接級別,以找到通過可寫入的一部分調用的所有函數的地址。因此,使用操作系統的能力加載可執行代碼和Fishhook庫來“重新啟用”呼叫,因此可以“插入”任何功能的新實現,並在運行時有效地將它們縫合到程序的其餘部分中。從那時起,它將像已在程序中內置新代碼一樣執行。
Indection使用FSEventSteam API查看何時更改源文件並掃描了最後的Xcode build Log,以進行重新編譯並鏈接可以加載到程序中的動態庫。然後,對注入的運行時支持加載動態庫,並將其掃描為其包含的功能定義,然後將其“插入”到程序的其餘部分中。這不是完整的故事,因為派遣非最終類方法使用了“ VTable”(想想C ++虛擬方法),該方法還必須進行更新,但是該項目將其與任何遺產Objective-C“ Swizzling”一起進行。
如果您有興趣了解注射方式的工作原理,那麼最佳來源是我的書Swift Secrets或IndectionLite Swift軟件包中的新的,啟動的參考實現。有關“插入”的更多信息,請諮詢此博客文章或Fishhook項目的讀書文件。有關應用程序本身組織的更多信息,請諮詢Roadmap.md。
上班注入有三個組成部分。文件觀察器,重新編譯任何更改的文件並構建可以加載的動態庫的代碼,並在運行時將代碼的新版本縫合到應用程序中。如何將這三個組件組合起來產生了可以使用注射的方式的數量。
“注入經典”是您從Github下載二進製版本之一併運行Indionctionii.App的地方。然後,您將該應用程序內部的一個捆綁包加載到您的程序中,如模擬器中所示。在此配置中,在應用程序內完成了文件觀察器和源重編譯,並且捆綁包使用套接字連接到應用程序,以了解何時準備加載新的動態庫。
“ App Store Indection”此版本的應用程序是沙盒,當文件觀察器仍在應用中運行時,重新編譯和加載是在模擬器內部執行的。由於模擬器使用案例敏感文件系統,這可能會引起C頭文件的問題,以作為對真實設備的忠實模擬。
“ HotRelodation Indection”是您在設備上運行應用程序的地方,因為您無法將Mac的文件系統從真實手機上加載,您將HotReloDaiding Swift軟件包添加到項目(僅在開發過程中!),其中包含通常在捆綁包中執行動態負載的所有代碼。這就要求您使用未包裝的二進製版本之一。它也已被上述copy_bundle.sh腳本替換。
“獨立注射”。這是該項目的最新演變,您不再運行應用程序本身,而只需加載一個注入束,並且文件觀察器,重新兼容和注入都在模擬器中進行。默認情況下,該手錶會更改主目錄內的任何SWIFT文件,儘管您可以使用環境變量INJECTION_DIRECTORIES更改此手錶。
注射液是獨立注入的最小啟動實施。只需添加此Swift軟件包,您就應該能夠注入模擬器。
IndectionNext是目前的注射劑,對於大型項目,應該更快,更可靠。它將其集成到XCode的調試標誌中,以了解如何重新編譯文件以避免解析構建日誌並重新使用客戶端從InjectionLite實現注入。要與外部編輯器(例如Cursor一起使用,IndectionNext還可以使用文件觀察者來檢測編輯並倒退以構建日誌解析代碼。
所有這些變化都要求您為調試構建添加“ -xlinker -interposble”鏈接標誌,否則您只能注入非最終類方法,所有這些都可以與更高級別的注入或HotSwSwiftUi結合使用。
請諮詢舊的讀書文件,如果有任何內容簡單地“信息過多”,包括可以用於自定義的各種環境變量。一些例子:
| 環境 | 目的 |
|---|---|
| indection_detail | 執行的所有動作的詳細輸出 |
| indection_trace | 注射功能的日誌調用(v4.6.6+) |
| indection_host | MAC的IP地址用於開發器注入 |
使用Indection_Trace環境變量,注入任何文件都會將所有調用的記錄添加到文件中的函數和方法以及其參數值以作為調試的幫助。
INDECTIONIII的一個鮮為人知的功能是,只要您在某個時候就可以為您的應用程序運行測試,您可以注入單個Xctest類,並且如果立即運行,則每次修改它是否都失敗了。
該項目包括Rentzsch/Mach_inject,Erwanb/Machinjectspample,Davedelong/Ddhotkey和ACJ/Timelapse-Builder-Swift的代碼。
應用程序跟踪功能使用oliverletterer/imp_implementationforwardingtoselector蹦床通過MIT許可通過SwiftTrace項目實現。
SwiftTrace使用非常方便的https://github.com/facebook/fishhook。有關許可詳細信息,請參見App Bundle中包含的項目源和標頭文件。
該版本包括出色的Canviz庫的一個非常略微修改的版本,以在HTML帆布中渲染“點”文件,該文件受到MIT許可證的約束。這些更改將通過節點的ID傳遞到節點標籤標籤(第212行),以逆轉節點的渲染和鏈接它們的線(第406行),並存儲邊緣路徑,以便可以在“ canviz-0.1/canviz.js”中塗色(66和303)。
它還包括CodeMirror JavaScript編輯器,以使用MIT許可下的注射來評估代碼。
神話般的應用圖標要歸功於Pixel-Mixer.com的Katya。