1.在Mac的App Store上下载安装InjectionIII.
2.打开InjectionIII, Open Project, 选择你的项目目录.
3.选择的项目会在Open Recent中出现, 保持File Watcher的选项勾选.
4.在AppDelegate的DidFinishLaunchingWithOptions配置InjectionIII的路径
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
#ifdef DEBUG
//InjectionIII 注入
[[NSBundle bundleWithPath:@"/Applications/InjectionIII.app/Contents/Resources/iOSInjection.bundle"] load];
#else
#endif
return YES;
}
5.在需要动态调试的页面控制器中写上injected方法, 把需要操作的UI方法添加到injected中执行, 如果想让全部的控制器都能使用, 直接添加到BaseViewController.
// Objective-C:
- (void)injected {
#ifdef DEBUG
NSLog(@"I've been injected: %@", self);
[self viewDidLoad];
#endif
}
// Swift
@objc func injected() {
#if DEBUG
print("I've been injected: \(self)")
self.viewDidLoad()
#endif
}
6. 重新编译项目, 控制台可以看到
className UIViewController
InjectionIII connected /Users/hujintao/Desktop/lib/HKUtilities/HKUtilities.xcworkspace
Watching files under /Users/hujintao/Desktop/lib/HKUtilities
⚠️ Your project file seems to be in the Desktop or Documents folder and may prevent InjectionIII working as it has special permissions.
7.修改完UI, 直接Command + S就能看到效果, 部分页面可能耗时比较久或无法使用, 正常页面均能使用.
Flutter Hot Reload介绍
Flutter是Google开发的一个跨平台开发框架, 调试也是快速实时的.
在Flutter编辑器中修改文字代码后, 点击reload, App不用重启, 模拟器的内容就会立刻改变.
Flutter实现实时编译的原理
Flutter会在点击reload时取查看上次编译以后改动过的代码, 重新编译涉及到的代码库.
重新编译过的库会转换成内核文件发到Dart VM里, DartVM会重新加载新的内核文件,
加载后会让Flutter framework触发所有的Widgets和Render Objects进行重建、重布局、重绘.
Flutter为了能够支持跨平台开发, 使用了自研的Dart语言配合在App内集成Dart VM的方式运行Flutter程序.
iOS原生项目拥有Flutter热重载的原理
Injection for XCodeGitHub地址
Injection工具可以动态地将iOS代码在已运行的程序中执行, 不用重启.
Injection会监听源代码文件的变化, 如果文件被改动了,
Injection Server就会执行rebuildClass重新进行编译、打包成动态库.dylib文件,
编译、打包成动态库后, 使用writeString方法通过Socket通知运行的App.
- (BOOL)writeString:(NSString *)string {
const char *utf8 = string.UTF8String;
uint32_t length = (uint32_t)strlen(utf8);
if (write(clientSocket, &length, sizeof length) != sizeof length ||
write(clientSocket, utf8, length) != length)
return FALSE;
return TRUE;
}
Server会在后台发送和监听Socket消息, Client也会开启一个后台去发送和监听Socket消息.
Client接收到消息后会调用inject(tmpfile: String)方法, 运行时进行类的动态替换(新类动态替换旧类).
dlopen会把tmpfile动态库文件载入运行的App里, 返回指针dl.
接下来, dlsym会得到tmpfile动态库的符号地址, 然后就可以处理类的替换工作了.
当类的方法都被替换后, 我们就可以开始重新绘制界面了.
-
使用动态库方式极速调试, 整个过程无需重新编译和重启App.