Injection使用说明

1,522 阅读3分钟

Injection是支持OC和Swift的UI热重载工具,采取在模拟器(只支持模拟器)注入的方式实现UI热重载,修改完UI直接com+s,不用重新编译运行就能看到UI效果。

使用方法

  1. github下载最新release版本,目前已经支持Xcode13和iOS15系统。

  2. 安装后,打开InjectionIII,选择Open Project,选择你的项目目录。 Xnip2021-09-22_15-04-41.jpg

  3. 选择的项目会在OPen Recent中展示,同时保持File Watcher的选项勾选

    Xnip2021-09-22_15-06-55.jpg

  4. AppDelegate配置,在didFinishLaunchingWithOptions配置注入。

OC版本

 #if DEBUG
   // iOS
   [[NSBundle bundleWithPath:@"/Applications/InjectionIII.app/Contents/Resources/iOSInjection.bundle"] load];
 #endif

Swift版本

    #if DEBUG 
    do{
        let injectionBundle = Bundle.init(path: "/Applications/InjectionIII.app/Contents/Resources/iOSInjection.bundle")
        if let bundle = injectionBundle{
            try bundle.loadAndReturnError()
        }else{
             debugPrint("Injection注入失败,未能检测到Injection")
        }
        
     }catch{
         debugPrint("Injection注入失败(error)")
     }
     #endif

注意:先打开InjectionIII的Resources路径,确认 iOSInjection.bundle 文件的正确路径。

  1. 注入页面文件配置
  • 在需要热重载的控制器中(可以考虑BaseVC),实现injected方法,并将操作UI的方法添加到injected即可。修改完UI,直接cmd+s就能看到效果。
- (void)injected {
#if DEBUG
    DLog(@"I've been injected: %@", self);
    [self viewDidLoad];
#endif
}
  • 如果使用以上方式在页面注入没有效果,则可以删除injected方法,在需要热重载的控制器添加通知INJECTION_BUNDLE_NOTIFICATION即可。
- (instancetype)init {
    if (self = [super init]) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(hotReloadingUI) name:@"INJECTION_BUNDLE_NOTIFICATION" object:nil];
    }
    return self;
}

- (void)hotReloadingUI {
#if DEBUG
    DLog(@"I've been injected: %@", self);
    [self viewDidLoad];
#endif
}
  1. cmd+s,快速的开发吧!

  2. 更多项目设置,请参考作者维护的wiki:github.com/johnno1962/…

可能遇到的问题

  • 项目路径如果在Desktop或者Documents文件夹中,会报警告,目前不影响使用。

    Your project file seems to be in the Desktop or Documents folder and may prevent InjectionIII working as it has special permissions.
    
  • 热重载时,hotReloadingUI方法被调用多次

    监听INJECTION_BUNDLE_NOTIFICATION通知的方法不能放在viewDidLoad方法里。原因,在热重载时,viewDidLoad会被调用多次。

  • 视图被多次添加问题

     - (void)viewDidLoad {
         [super viewDidLoad];
         UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 100, 100, 100)];
         view.backgroundColor = UIColor.blueColor;
         [self.view addSubview:view];
     }
    

    由于viewDidLoad方法在热重载时会再次被调用,所以如果不是通过懒加载创建的视图,会导致视图被添加多次。

    解决方法(个人观点):如果是像首页这样的主页面,可以在添加视图之前做一次判断;如果是子页面,可以不用管,当视图层级过多时,可以返回让控制器出栈再重新push入栈。

注:“Every time the injected function runs, we’re going to remove all the subviews in the main view of the UIViewController. This should clear the screen in most cases.”,这是在文档中看到的作者写的原文,目前发现子视图并没有移除,正在向作者提问。

  • 在使用webView的页面闪退,无法复现
  • 会员产品发车页使用闪退

更多功能

  • Add Directory

    如果项目是跨多个目录的,或者项目文件不在源代码的根目录中,可以使用“添加目录”菜单项添加其他目录来监视文件更改。当选择一个新项目时,此列表将重置。

  • File Watcher

    • 启用,通过 cmd+s 进行热重载
    • 禁用,可以手动启用热重载,首先 cmd+s,然后 ctrl-=
  • Enable Vaccine

  • Prepare Project

    可以配合在SwiftUI中注入时使用

  • Method Tracing

    用来做方法跟踪的,会记录每一个方法的调用。具体实现在Injection.bundle -> Frameworks -> SwiftTrace.framework

  • Remote Control

    可以在开发过程中从 Mac 上的窗口控制 iPhone