|
1 | 1 |
|
2 | 2 | # Injection
|
3 | 3 |
|
4 |
| -支持OC、Swift以及Swift和OC混编项目的UI热重载工具,采取在**模拟器**(真机不支持)注入方式实现UI热重载,修改完UI直接com+s,不用重新编译运行就能看到UI效果,堪称神器。 |
5 |
| -[github](https://github.com/johnno1962/InjectionIII),而且[AppStore](https://apps.apple.com/cn/app/injectioniii/id1380446739)也有发布。 |
6 |
| -目前已经更新支持Xcode13和iOS15。 |
| 4 | +支持 OC、Swift 以及 Swift 和 OC 混编项目的 UI 热重载工具,采取在**模拟器**(真机不支持)注入方式实现 UI 热重载,修改完 UI 直接 `cmd + s`,不用重新编译运行就能看到 UI 效果。👉🏻 [Github](https://github.com/johnno1962/InjectionIII) 👈🏻 |
7 | 5 |
|
8 |
| -# 使用方法 |
9 |
| -## 1、Injection安装 |
10 |
| - 1、[github](https://github.com/johnno1962/InjectionIII)下载最新release版本,或者[AppStore](https://apps.apple.com/cn/app/injectioniii/id1380446739)下载安装即可,推荐[github](https://github.com/johnno1962/InjectionIII)下载安装,github更新比AppStore更新快。如果你的项目使用混编OC时,强烈建议使用github的[releases](https://github.com/johnno1962/InjectionIII/releases)版本 |
| 6 | +而且 [AppStore](https://apps.apple.com/cn/app/injectioniii/id1380446739) 也有发布。 |
| 7 | +目前已经更新支持 Xcode 13 和 iOS 15。 |
| 8 | + |
| 9 | +**最新消息:** 自从 4.4.0+ 版本开始,针对 iOS/tvOS 14+ 使用 InjectionIII 时,可以不用运行 InjectionIII 了,只需要在代码中集成加载 `injection bundles` 的代码就可以了。目前为止,这是最简单的使用 InjectionIII 的方式,而且不需要手动选择项目的文件夹目录。当 InjectionIII.app 没有运行时,bundle 将回退使用 HotReloading 的 `standalone` 的实现方式,监视主目录中的文件更改,并使用由 File Watcher 确定的上次构建项目的构建日志。跳转 [Standalone Injection](#standalone-injection) 查看更多。 |
| 10 | + |
| 11 | +## 使用方法 |
| 12 | + |
| 13 | +### 1、Injection 安装 |
| 14 | + |
| 15 | +1. [github](https://github.com/johnno1962/InjectionIII) 下载最新 release 版本,或者 [AppStore](https://apps.apple.com/cn/app/injectioniii/id1380446739) 下载安装即可,推荐 [github](https://github.com/johnno1962/InjectionIII) 下载安装,github 更新比 AppStore 更新快。如果你的项目使用混编 OC 时,强烈建议使用 github 的 [releases](https://github.com/johnno1962/InjectionIII/releases) 版本。 |
11 | 16 |
|
12 |
| - 2、安装后,打开InjectionIII,选择Open Project,选择你的项目目录 |
| 17 | +2. 安装后,打开 InjectionIII,选择 Open Project,选择你的项目目录。 |
13 | 18 |
|
14 | 19 | 
|
15 | 20 |
|
16 |
| - 3、选择的项目会在Open Recent中展示,同时保持File Watcher的选项勾选。 |
| 21 | +3. 选择的项目会在 Open Recent 中展示,同时保持 File Watcher 的选项勾选。 |
17 | 22 |
|
18 |
| - |
| 23 | + |
19 | 24 |
|
20 |
| -## 2、项目配置 |
21 |
| - 1、AppDelegate配置,在didFinishLaunchingWithOptions配置注入 |
22 |
| - 需要注意,先打开InjectionIII的Resources路径,确认bundle文件的正确路径 |
23 |
| - OC版本 |
24 |
| - #if DEBUG |
25 |
| - //iOS |
26 |
| - [[NSBundle bundleWithPath:@"/Applications/InjectionIII.app/Contents/Resources/iOSInjection.bundle"] load]; |
27 |
| - //同时还支持tvOS和MacOS,配置时只需要在/Applications/InjectionIII.app/Contents/Resources/目录下找到对应的bundle文件,替换路径即可 |
28 |
| - #endif |
29 |
| - |
30 |
| - Swift版本 |
31 |
| - #if DEBUG |
32 |
| - do{ |
33 |
| - let injectionBundle = Bundle.init(path: "/Applications/InjectionIII.app/Contents/Resources/iOSInjection.bundle") |
34 |
| - if let bundle = injectionBundle{ |
35 |
| - try bundle.loadAndReturnError() |
36 |
| - }else{ |
37 |
| - debugPrint("Injection注入失败,未能检测到Injection") |
38 |
| - } |
39 |
| - |
40 |
| - }catch{ |
41 |
| - debugPrint("Injection注入失败\(error)") |
42 |
| - } |
43 |
| - #endif |
| 25 | + |
| 26 | +### 2、项目配置 |
| 27 | + |
| 28 | + 1. AppDelegate 配置,在 `didFinishLaunchingWithOptions` 配置注入。 |
| 29 | +需要注意,先打开 InjectionIII 的 Resources 路径,确认 bundle 文件的正确路径 |
| 30 | + |
| 31 | +- OC 版本: |
| 32 | + |
| 33 | +```objective-c |
| 34 | +#if DEBUG |
| 35 | + // iOS |
| 36 | + [[NSBundle bundleWithPath:@"/Applications/InjectionIII.app/Contents/Resources/iOSInjection.bundle"] load]; |
| 37 | + |
| 38 | + // 同时还支持 tvOS 和 MacOS,配置时只需要在 /Applications/InjectionIII.app/Contents/Resources/ 目录下找到对应的 bundle 文件,替换路径即可 |
| 39 | +#endif |
| 40 | +``` |
44 | 41 |
|
45 |
| - 2、此时启动项目,在控制台可以看到,表示注入成功了 |
46 |
| - 如果有多个项目都在使用Injection,需要查看Injection链接路径是否正确,如果不正确,打开Injection菜单-OPen Recent-选择你需要注入的项目即可。 |
47 |
| - 💉 InjectionIII connected /Users/looha/Desktop/Project_lh/BVGenius/BVGenius.xcworkspace |
48 |
| - 💉 Watching files under /Users/looha/Desktop/Project_lh/BVGenius |
49 |
| - |
50 |
| - 3、注入页面文件配置 |
51 |
| - 在需要热重载的页面VC中,实现injected方法,把操作UI方法添加到injected中即可 |
52 |
| - 以Swift为例,比如UI操作都在vc的viewDidLoad中,那么就在injected添加viewDidLoad方法即可 |
53 |
| - 如果项目都想使用,直接添加到baseVC即可 |
54 |
| - Swift: |
55 |
| - @objc func injected() { |
56 |
| - #if DEBUG |
57 |
| - |
58 |
| - self.viewDidLoad() |
59 |
| - |
60 |
| - #endif |
61 |
| - } |
62 |
| - |
63 |
| - 4、在UI阶段,修改外UI,直接com+s就能看到效果,部分页面可能需要重新进入该页面才能看到效果。 |
64 |
| - ps:当你的项目使用unowned时,项目都配置完成并没有报错,但是修改完UI,按com+s并没有相应的效果,则删除injected方法,在需要热重载的界面或者(baseVC)添加通知INJECTION_BUNDLE_NOTIFICATION即可 |
65 |
| - NotificationCenter.default.addObserver(self, selector:#selector(hotReloadingUI), name: Notification.Name("INJECTION_BUNDLE_NOTIFICATION"), object: nil) |
66 |
| - |
67 |
| - |
68 |
| - |
69 |
| - |
70 |
| - # 更多设置 |
71 |
| - 1、Build Settings - Swift Compiler-Code Generation |
72 |
| - Compilation Mode - Debug模式改为 Incremental |
73 |
| - Optimization Level - Debug模式改为 No Optimization [-Onone] |
74 |
| - 2、不支持Swift的SWIFT_WHOLE_MODULE_OPTIMIZATION 模式,需要在关闭它 |
75 |
| - User-Defined - |
76 |
| - SWIFT_WHOLE_MODULE_OPTIMIZATION Debug模式改为NO |
77 |
| - |
78 |
| - 3、如果想对final方法和structs方法热重载,在Build Settings - Other Linker Flags中加入 -Xlinker,-interposable |
79 |
| - 项目编译报错:Can't find ordinal for imported symbol for architecture x86_64 |
80 |
| - 增加 -undefined,dynamic_lookup即可 |
| 42 | +- Swift 版本: |
| 43 | + |
| 44 | +```swift |
| 45 | +#if DEBUG |
| 46 | +do { |
| 47 | + let injectionBundle = Bundle.init(path: "/Applications/InjectionIII.app/Contents/Resources/iOSInjection.bundle") |
| 48 | + if let bundle = injectionBundle{ |
| 49 | + try bundle.loadAndReturnError() |
| 50 | + } else { |
| 51 | + debugPrint("Injection 注入失败,未能检测到 Injection") |
| 52 | + } |
| 53 | + |
| 54 | +} catch { |
| 55 | + debugPrint("Injection 注入失败 \(error)") |
| 56 | +} |
| 57 | +#endif |
| 58 | +``` |
| 59 | + |
| 60 | +2. 此时启动项目,在控制台可以看到,表示注入成功了 |
| 61 | + 如果有多个项目都在使用 Injection,需要查看 Injection 链接路径是否正确,如果不正确,打开 Injection 菜单 -OPen Recent- 选择你需要注入的项目即可。 |
| 62 | + |
| 63 | +``` |
| 64 | + 💉 InjectionIII connected /Users/looha/Desktop/Project_lh/BVGenius/BVGenius.xcworkspace |
| 65 | + 💉 Watching files under /Users/looha/Desktop/Project_lh/BVGenius |
| 66 | +``` |
| 67 | + |
| 68 | +3. 注入页面文件配置 |
| 69 | + |
| 70 | +在需要热重载的页面 VC 中,实现 injected 方法,把操作 UI 方法添加到 injected 中即可。以 Swift 为例,比如 UI 操作都在 VC 的 viewDidLoad 中,那么就在 injected 添加 viewDidLoad 方法即可。如果项目都想使用,直接添加到 baseVC 即可。 |
| 71 | + |
| 72 | + Swift: |
| 73 | + |
| 74 | + ```swift |
| 75 | + @objc func injected() { |
| 76 | + #if DEBUG |
81 | 77 |
|
82 |
| - |
83 |
| - |
| 78 | + self.viewDidLoad() |
84 | 79 |
|
85 |
| - |
| 80 | + #endif |
| 81 | + } |
| 82 | +``` |
86 | 83 |
|
87 |
| - 4、如果你的方法有默认参数,而报以下错误时,重新启动App即可 |
88 |
| - 💉 *** dlopen() error: dlopen(/var/folders/nh/gqmp6jxn4tn2tyhwqdcwcpkc0000gn/T/com.johnholdsworth.InjectionIII/eval101.dylib, 2): Symbol not found: _$s13TestInjection15QTNavigationRowC4text10detailText4icon6object13customization6action21accessoryButtonActionACyxGSS_AA08QTDetailG0OAA6QTIconOSgypSgySo15UITableViewCellC_AA5QTRow_AA0T5StyleptcSgyAaT_pcSgAWtcfcfA1_ |
89 |
| - Referenced from: /var/folders/nh/gqmp6jxn4tn2tyhwqdcwcpkc0000gn/T/com.johnholdsworth.InjectionIII/eval101.dylib |
90 |
| - Expected in: flat namespace |
91 |
| - in /var/folders/nh/gqmp6jxn4tn2tyhwqdcwcpkc0000gn/T/com.johnholdsworth.InjectionIII/eval101.dylib *** |
92 |
| - |
| 84 | +4. 在 UI 阶段,修改外 UI,直接 `cmd + s` 就能看到效果,部分页面可能需要重新进入该页面才能看到效果。 |
| 85 | +ps:当你的项目使用 unowned 时,项目都配置完成并没有报错,但是修改完 UI,按 `cmd + s` 并没有相应的效果,则删除 injected 方法,在需要热重载的界面(或者 baseVC)添加通知 `INJECTION_BUNDLE_NOTIFICATION` 即可。 |
93 | 86 |
|
94 |
| -# 更加详细的问题请多在项目README和issues查找 |
95 |
| - |
96 |
| - |
| 87 | +```swift |
| 88 | +NotificationCenter.default.addObserver(self, selector:#selector(hotReloadingUI), name: Notification.Name("INJECTION_BUNDLE_NOTIFICATION"), object: nil) |
| 89 | +``` |
97 | 90 |
|
| 91 | +## 使用 InjectionIII 的变化: |
98 | 92 |
|
| 93 | +### Standalone Injection |
99 | 94 |
|
100 |
| - |
101 |
| - |
| 95 | +自从 4.4.* 版本,这是推荐的使用方式,因为它需要更少的步骤就能“正常工作”。所有 Injection 需要的都会在模拟器内执行,它通过 `~/Library/Developer/Xcode/DerivedData` 目录中最近修改的“.wcactivitylog”文件(最近一次构建项目的构建日志的 gzip 压缩文件)自动确定使用哪个项目和构建日志。默认情况下,File Watcher 会监视 home 主目录中源文件的所有更改。 |
| 96 | + |
| 97 | +与之前一样,你需要在你项目 `target` 中的 `Other Linker Flags` 添加 `-Xlinker -interposable` 标识符,并且下载 [release 版 InjectionIII](https://github.com/johnno1962/InjectionIII/releases) app 来使得代码中的 `iOSInjection.bundle` 可访问,但是 **不需要单独运行** InjectionIII App(如果你运行了,也能像之前一样工作)。 |
| 98 | + |
| 99 | +## 更多设置 |
| 100 | + |
| 101 | +1. Build Settings - Swift Compiler-Code Generation |
| 102 | + |
| 103 | +``` |
| 104 | + Compilation Mode - Debug 模式改为 Incremental |
| 105 | + Optimization Level - Debug 模式改为 No Optimization [-Onone] |
| 106 | +``` |
| 107 | + |
| 108 | +2. 不支持 Swift 的 SWIFT_WHOLE_MODULE_OPTIMIZATION 模式,需要在关闭它 |
102 | 109 |
|
| 110 | +``` |
| 111 | + User-Defined - |
| 112 | + SWIFT_WHOLE_MODULE_OPTIMIZATION Debug模式改为NO |
| 113 | +``` |
| 114 | + |
| 115 | +3. 如果想对 final 方法和 structs 方法热重载,在 Build Settings - Other Linker Flags 中加入 -Xlinker,-interposable |
| 116 | + |
| 117 | +``` |
| 118 | + 项目编译报错:Can't find ordinal for imported symbol for architecture x86_64 |
| 119 | + 增加 -undefined,dynamic_lookup即可 |
| 120 | +``` |
| 121 | + |
| 122 | + |
| 123 | + |
| 124 | + |
103 | 125 |
|
104 | 126 |
|
| 127 | +4. 如果你的方法有默认参数,而报以下错误时,重新启动 App 即可 |
105 | 128 |
|
| 129 | +``` |
| 130 | + 💉 *** dlopen() error: dlopen(/var/folders/nh/gqmp6jxn4tn2tyhwqdcwcpkc0000gn/T/com.johnholdsworth.InjectionIII/eval101.dylib, 2): Symbol not found: _$s13TestInjection15QTNavigationRowC4text10detailText4icon6object13customization6action21accessoryButtonActionACyxGSS_AA08QTDetailG0OAA6QTIconOSgypSgySo15UITableViewCellC_AA5QTRow_AA0T5StyleptcSgyAaT_pcSgAWtcfcfA1_ |
| 131 | + Referenced from: /var/folders/nh/gqmp6jxn4tn2tyhwqdcwcpkc0000gn/T/com.johnholdsworth.InjectionIII/eval101.dylib |
| 132 | + Expected in: flat namespace |
| 133 | + in /var/folders/nh/gqmp6jxn4tn2tyhwqdcwcpkc0000gn/T/com.johnholdsworth.InjectionIII/eval101.dylib *** |
| 134 | +``` |
106 | 135 |
|
| 136 | +## 更加详细的问题请多在项目 README 和 issues 查找。 |
0 commit comments