Chinesische Sprache Readme: 中文集成指南
Mit der Code -Injektion können Sie die Implementierung von Funktionen und eine beliebige Methode einer Klasse, Struktur oder enum schrittweise im iOS -Simulator aktualisieren, ohne eine vollständige Wiederherstellung ausführen oder Ihre Anwendung neu starten zu müssen. Dies spart dem Entwickler erheblich, um Code zu optimieren oder ein Design zu iterieren. Effektiv ändert es XCode von einem "Quelleditor" zu einem "Programmeditor", bei dem Quelländerungen nicht nur auf der Festplatte, sondern in Ihrem laufenden Programm direkt gespeichert werden.
Das Einrichten Ihrer Projekte zur Verwendung von Injektionen ist jetzt so einfach wie das Herunterladen eines der Github -Veröffentlichungen der App oder aus dem Mac App Store und dem Hinzufügen des unten stehenden Codes in Ihrer App, das beim Start ausgeführt werden soll (es ist nicht mehr erforderlich, die App selbst auszuführen).
#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 Es ist auch wichtig, die Optionen -Xlinker und -interposable (ohne doppelte Zitate und in separaten Zeilen) zu den "anderen Linker -Flags" von Zielen in Ihrem Projekt (nur für die Debug -Konfiguration) hinzuzufügen, um "Interposation" zu aktivieren (siehe Erklärung unten).

Wenn Sie Ihre App im Simulator ausführen, sollten Sie eine Nachricht sehen, die besagt, dass ein Dateibeobachter für Ihr Heimverzeichnis gestartet wurde. Wenn Sie im aktuellen Projekt eine Quelldatei speichern, sollte sie angegeben werden. Dies bedeutet, dass alle Orte, die früher als alte Implementierung bezeichnet wurden, aktualisiert wurde, um die neueste Version Ihres Codes aufzurufen.
Es ist nicht ganz so einfach, dass die Ergebnisse auf dem Bildschirm sofort angezeigt werden. Der neue Code muss tatsächlich aufgerufen worden sein. Wenn Sie beispielsweise einen View -Controller injizieren, muss er ein Redisplay erzwingen. Um dieses Problem zu beheben, können Klassen eine @objc func injected() -Methode implementieren, die aufgerufen wird, nachdem die Klasse injiziert wurde, um ein Update für die Anzeige durchzuführen. Eine Technik, die Sie verwenden können, besteht darin, den folgenden Code irgendwo in Ihr Programm aufzunehmen:
#if DEBUG
extension UIViewController {
@ objc func injected ( ) {
viewDidLoad ( )
}
}
#endifEine weitere Lösung für dieses Problem ist das "Hosting" mit dem von diesem Blog -Beitrag eingeführten Inject Swift -Paket.
Sie können keine Änderungen in die Art und Weise injizieren, wie Daten im Speicher festgelegt werden, dh Sie können Eigenschaften mit Speicher nicht hinzufügen, entfernen oder neu ordnen. Für Nicht-Finalklassen gilt dies auch für das Hinzufügen oder Entfernen von Methoden, da die für den Versand verwendete vtable selbst eine Datenstruktur ist, die sich nicht über die Injektion ändern darf. Die Injektion kann auch nicht herausfinden, welche Codestücke wieder ausgeführt werden müssen, um die Anzeige wie oben erläutert zu aktualisieren. Lassen Sie sich auch nicht mit Zugangskontrolle mitnehmen. private Eigenschaften und Methoden können nicht direkt injiziert werden, insbesondere in Erweiterungen, da es sich nicht um ein global Interpositionssymbol handelt. Sie injizieren im Allgemeinen indirekt, da sie nur innerhalb der in die Injektion der Datei injizierten Datei akustiert werden können, dies kann jedoch Verwirrung verursachen. Schließlich ist die Injektion nicht gut mit Quelldateien zu tun, die während der Injektion hinzugefügt/umbenannt/gelöscht werden. Möglicherweise müssen Sie Ihre App erstellen, neu starten oder sogar Ihr Projekt schließen und wieder eröffnen, um alte Xcode -Build -Protokolle zu beseitigen.
Swiftui ist, wenn überhaupt, besser für die Injektion als UIKIT geeignet, da es spezifische Mechanismen zur Aktualisierung des Displays enthält. Sie müssen jedoch ein paar Änderungen an jeder View vornehmen, die Sie injizieren möchten. Um die einfachste Art und Weise zu erzwingen, ist das Hinzufügen einer Eigenschaft, die beobachtet, wann eine Injektion aufgetreten ist:
@ ObserveInjection var forceRedraw Diese Immobilienverpackung ist entweder im HotSwiftui oder in der Injize Swift -Paket erhältlich. Es enthält im Wesentlichen eine @Published -Ganzzahl, die Ihre Ansichten mit jeder Injektion beobachten. Sie können eines der folgenden Informationen verwenden, um eines dieser Pakete während Ihres gesamten Projekts verfügbar zu machen:
@ _exported import HotSwiftUI
or
@ _exported import Inject Die zweite Änderung, die Sie für eine zuverlässige Swiftui -Injektion vornehmen müssen, besteht darin, den Rückgabetyp der Körpereigenschaft zu "löschen", indem Sie sie in AnyView mit der Methode für die .enableInjection() -Methode in diesen Paketen View . Dies liegt daran, dass, wenn Sie Swiftui -Elemente hinzufügen oder entfernen, den Betonrückgabetyp der Körpereigenschaft ändern kann, der zu einer Speicher -Layout -Änderung führt, die möglicherweise zum Absturz ist. Zusammenfassend lässt sich sagen, dass das Ende jedes Körpers immer so aussehen sollte:
var body : some View {
VStack or whatever {
// Your SwiftUI code...
}
. enableInjection ( )
}
@ ObserveInjection var redraw Sie können diese Modifikationen in Ihrem Produktionscode als Release Build auf ein No-Op-OP-optimaler Release-Build belassen.
Neu in Xcode 16 ist SWIFT_ENABLE_OPAQUE_TYPE_ERASURE -Build -Einstellung. Diese Einstellung wird standardmäßig aktiviert und Sie müssen den Körper nicht explizit ansehen. Sie müssen immer noch @ObserveInjection melden, um Wiederholungen zu erzwingen.
Weitere Informationen finden Sie in Xcode 16.2 Versionshinweise.
Dies kann funktionieren, aber Sie müssen tatsächlich eines der GitHub 4.8.0+ -Reenschaften der Injektioniii.app ausführen und die App für die Option einstellen, um die App zu deaktivieren und neu zu starten.
$ defaults write com.johnholdsworth.InjectionIII deviceUnlock any
Anstatt die Injektionsbündel zu laden, führen Sie dieses Skript in einer "Build -Phase" aus: (Sie müssen auch die Projekt -Build -Einstellung "Benutzerskript -Sandboxing" deaktivieren))
RESOURCES=/Applications/InjectionIII.app/Contents/Resources
if [ -f "$RESOURCES/copy_bundle.sh" ]; then
"$RESOURCES/copy_bundle.sh"
fi
Führen Sie in Ihrer Anwendung den folgenden Code beim Start aus:
#if DEBUG
if let path = Bundle . main . path ( forResource :
" iOSInjection " , ofType : " bundle " ) ??
Bundle . main . path ( forResource :
" macOSInjection " , ofType : " bundle " ) {
Bundle ( path : path ) ! . load ( )
}
#endifSobald Sie zu dieser Konfiguration gewechselt sind, funktioniert sie auch bei der Verwendung des Simulators. Wenden Sie sich an die Readme des Hotreloading-Projekts, um Details zum Debuggen zu erhalten, wie Ihr Programm über Wi-Fi mit dem Injektioniii.app verbunden ist. Sie müssen auch das Projektverzeichnis für den Dateibeobachter aus dem Pop-Down-Menü manuell auswählen.
Es funktioniert, aber Sie müssen die "App Sandbox" und "Bibliotheksvalidierung" unter der "gehärteten Laufzeit" während der Entwicklung vorübergehend ausschalten, damit es dynamisch Code laden kann. Um Probleme mit dem Codessigning zu vermeiden, verwenden Sie das Skript copy_bundle.sh , wie in den Anweisungen für die Injektion auf realen Geräten oben beschrieben.
Die Injektion hat im Laufe der Jahre auf verschiedene Weise gearbeitet und begonnen, die "Swizzling" -APIs für Objective-C zu verwenden, basiert jedoch hauptsächlich um eine Funktion von Apple's Linker, die als "Interpossion" bezeichnet wird und eine Lösung für jede Swift-Methode oder eine berechnete Eigenschaft eines beliebigen Typs bietet.
Wenn Ihr Code eine Funktion in Swift aufruft, wird er im Allgemeinen "statisch versandt", dh mit dem "verstümmelten Symbol" der aufgerufenen Funktion verknüpft. Immer wenn Sie Ihre Anwendung mit der Option "-interpositionierbar" verknüpfen, wird jedoch eine zusätzliche Indirektion hinzugefügt, bei der die Adresse aller Funktionen über einen Abschnitt mit beschreibbarem Speicher aufgerufen wird. Verwenden der Fähigkeit des Betriebssystems, ausführbarer Code und die Fishhook -Bibliothek zu laden, um den Aufruf zu "wiederherstellen", ist daher möglich, neue Implementierungen jeder Funktion zu "einstellen" und sie zur Laufzeit effektiv in den Rest Ihres Programms zu nähen. Ab diesem Zeitpunkt wird es so ausgeführt, als wäre der neue Code in das Programm integriert worden.
Injection verwendet die FSEventSteam -API, um zu beobachten, ob eine Quelldatei geändert wurde, und scannt das letzte Xcode Build -Protokoll, um sie neu kompilieren und eine dynamische Bibliothek verknüpft, die in Ihr Programm geladen werden kann. Die Laufzeitunterstützung für die Injektion lädt dann die dynamische Bibliothek und scannt sie auf die Funktionsdefinitionen, die sie dann in den Rest des Programms "einmischt". Dies ist nicht die vollständige Geschichte, da der Versand von Nicht-Final-Klassenmethoden eine "vtable" (denken Sie an virtuelle C ++-Methoden), die ebenfalls aktualisiert werden muss, das Projekt jedoch zusammen mit jedem Legacy-Objektiv-C "Swizzling" betraf.
Wenn Sie mehr darüber wissen, wie die Injektion funktioniert, ist die beste Quelle entweder mein Buch Swift Secrets oder die neue Implementierung von Start-Over-Referenz im Injectionlite Swift-Paket. Weitere Informationen zum "Interposieren" an diesen Blog -Beitrag oder den Readme des Fishhook -Projekts. Weitere Informationen zur Organisation der App selbst finden Sie in Roadmap.md.
Die Injektion zur Arbeit hat drei Komponenten. Ein Dateiwächter, der Code, um geänderte Dateien neu zu kompilieren und eine dynamische Bibliothek zu erstellen, die geladen werden kann, und der Injektionscode selbst, der die neuen Versionen Ihres Codes in die App nähert, während sie ausgeführt wird. Wie diese drei Komponenten kombiniert werden, entsteht die Anzahl der Möglichkeiten, wie die Injektion verwendet werden kann.
In der "Injection Classic" laden Sie eine der Binärveröffentlichungen von Github herunter und leiten die Injektioniii.App. Anschließend laden Sie einen der Bündel in diese App in Ihr Programm, wie oben im Simulator gezeigt. In dieser Konfiguration erfolgt der Dateiwächter und die Quell -Neukompilierung in der App und das Bundle stellt eine Verbindung zur App mit einem Socket her, um zu wissen, wann eine neue dynamische Bibliothek geladen werden kann.
"App Store Injection" Diese Version der App ist sandboxiert, und während der Dateibeobachter weiterhin in der App ausgeführt wird, wird die Neukompilierung und das Laden im Simulator delegiert. Dies kann Probleme mit C -Header -Dateien erzeugen, da der Simulator ein fälschliches sensitives Dateisystem verwendet, um eine treue Simulation eines realen Geräts zu sein.
In der "Hotreloading Injection" werden Ihre App auf einem Gerät ausgeführt. Da Sie ein Bündel nicht vom Dateisystem Ihres Mac auf einem echten Telefon laden können, fügen Sie das Hotreloading -Swift -Paket zu Ihrem Projekt hinzu (nur während der Entwicklung!), Das den Codes, das normalerweise im Bündel, die dynamische Belastung ausführt. Dies erfordert, dass Sie eine der nicht sandboxierten Binärveröffentlichungen verwenden. Es wurde auch durch das oben beschriebene copy_bundle.sh -Skript ersetzt.
"Eigenständige Injektion". Dies war die jüngste Entwicklung des Projekts, bei dem Sie die App nicht mehr selbst ausführen, sondern einfach eines der Injektionsbündel laden, und der Dateibeobachter, eine Wiedereinsparung und die Injektion werden im Simulator durchgeführt. Standardmäßig beobachtet diese Änderungen an einer Swift -Datei in Ihrem Home -Verzeichnis, können Sie diese mithilfe der Umgebungsvariablen INJECTION_DIRECTORIES ändern.
Injectionlit ist eine minimale Einführung der eigenständigen Injektion als Referenz. Fügen Sie einfach dieses schnelle Paket hinzu und Sie sollten in der Lage sein, den Simulator zu injizieren.
InjectionNext ist eine derzeit experimentelle Version der Injektion, die für große Projekte schneller und zuverlässiger sein sollte. Es ist in ein Debugging-Flag von Xcode integriert, um herauszufinden, wie Sie Dateien neu kompilieren können, um die Analyse von Build-Protokollen zu vermeiden, und die Client-Implementierung der Injektion aus InjectionLite wiederverwendet. Um mit externen Redakteuren wie Cursor zu verwenden, kann InjectionNext auch einen Dateibeobachter verwenden, um Änderungen zu erkennen und zurückzufallen, um Protokoll -Parsing -Code zu erstellen.
Bei all diesen Variationen müssen Sie die Linker-Flags "-xlinker -interposble" für einen Debug-Build hinzufügen, oder Sie können nur Nicht-Finale-Methoden von Klassen injizieren, und alle können in Verbindung mit einer der höheren Injektion oder Hotwiftui verwendet werden.
Wenden Sie sich an die alte Readme, die, wenn etwas einfach "zu viele Informationen" enthält, einschließlich der verschiedenen Umgebungsvariablen, die Sie zur Anpassung verwenden können. Ein paar Beispiele:
| Umwelt var. | Zweck |
|---|---|
| Injektion_Detail | Ausführliche Ausgabe aller durchgeführten Aktionen |
| Injektion_Trace | Protokollaufrufe zu injizierten Funktionen (v4.6.6+) |
| Injektion_Host | Die IP-Adresse von MAC für die Injektion von On-Geräten |
Mit einer Variablen zur Umgebungsvariablen in Injection_Trace wird die Protokollierung aller Aufrufe zu Funktionen und Methoden in der Datei zusammen mit ihren Argumentwerten als Hilfe zum Debuggen hinzugefügt.
Ein wenig bekanntes Merkmal von Injectioniii ist, dass Sie die Tests für Ihre App irgendwann ausgeführt haben, dass Sie eine einzelne XCTest -Klasse injizieren können, und wenn Sie sofort ausgeführt werden - melden Sie, ob sie bei jedem Ändern nicht fehlgeschlagen ist.
Dieses Projekt enthält Code von Rentzsch/Mach_inject, Erwanb/MachinjectSample, Davedelong/Ddhotkey und ACJ/Timelapsebuilder-Swift unter ihren jeweiligen Lizenzen.
Die App -Tracing -Funktionalität verwendet die Implementierung von Oliverletterer/Imp_ImplementationforwardingToSelector über das Swifttrace -Projekt unter einer MIT -Lizenz.
SwiftTrace verwendet die sehr praktische https://github.com/facebook/fishhook. Die im App -Bundle enthaltene Projektquelle und Header -Datei finden Sie in Lizenzdetails.
Diese Version enthält eine leicht modifizierte Version der exzellenten Leinwandbibliothek, um "Punktdateien" in einer HTML -Leinwand zu rendern, die einer MIT -Lizenz unterliegt. Die Änderungen bestehen darin, die ID des Knotens an das Knoten-Etikett-Tag (Zeile 212) zu übergeben, das Rendering von Knoten und die Linien zu umkehren, die sie verknüpfen (Zeile 406), und um Kantenpfade zu speichern, damit sie in "Canviz-0.1/canviz.js" gefärbt werden können (Zeile 66 und 303).
Es enthält auch den Codemirror JavaScript -Editor für den Code, der unter Verwendung einer Injektion im Rahmen einer MIT -Lizenz bewertet wird.
Das fabelhafte App-Symbol ist Katya von Pixel-mixer.com zu verdanken.