InjectionⅢ

工具简介

InjectionⅢ是作者John Holdsworth开源的一款iOS热重载工具,当APP在模拟器上编译运行后,使用它可以即时的执行项目中代码的改动,无需重新编译整个项目,从而极大的提高代码的调试效率。

InjectionⅢ大概的工作原理是:

  • 在APP启动时,以加载NSBundle的形式在APP中运行一个Client端;
  • InjectionⅢ作为Server端监视指定目录下文件的改动,当文件发生改动时将改动的文件重新编译为一个动态库;
  • 动态库编译完成后,通过socket通信通知Client端,让APP去加载这个动态库(dlopen);
  • 动态库加载完成后,再通过Runtime的class_replaceMethod将原来类中的方法都替换为动态库中新类的方法;
  • 最后再调用文件中的类及其对象的injected方法,以便在其中调用修改后的代码;
  • 最终完成了对当前文件中代码改动的动态调试;

工具教程

1.安装

InjectionⅢ可以在Mac的应用商店中下载,也可以通过源码安装:clone或者下载源码,构建源码中的InjectionⅢ.xcodeproj工程即可。如果通过源码安装,卸载时删除构建源码时生成的xcode插件即可,终端命令:

1
rm -rf ~/Library/Application\ Support/Developer/Shared/Xcode/Plug-ins/InjectionPlugin.xcplugin

2.使用

首先在InjectionⅢ中通过Open Project或Add Directory添加需要监视的文件目录,并勾选File Watcher。

然后在application:DidFinishLaunching:中加载Injection的动态库:

1
2
3
4
5
6
7
8
#if DEBUG
// iOS
[[NSBundle bundleWithPath:@"/Applications/InjectionIII.app/Contents/Resources/iOSInjection.bundle"] load];
// tvOS
// [[NSBundle bundleWithPath:@"/Applications/InjectionIII.app/Contents/Resources/tvOSInjection.bundle"] load];
// macOS
// [[NSBundle bundleWithPath:@"/Applications/InjectionIII.app/Contents/Resources/macOSInjection.bundle"] load];
#endif

再在需要被监视改动的代码文件中添加类重载后的代码执行入口:

1
2
3
4
5
6
7
8
9
+ (void)injected
{
// 代码改动或调用改动的代码
}

- (void)injected
{
// 代码改动或调用改动的代码
}

最后运行工程,当控制台输出“💉 Injection connected 👍”,即表示InjectionⅢ正常运行。

APP运行中,对代码文件做出修改并通过Command+s保存后,被修改文件中的所有类的+injected及其对象的-injected方法都会被调用,在方法中直接添加调试代码或调用发生改动的代码,即可对运行中的APP进行动态调试。

3.注意

在使用InjectionⅢ时需要注意以下几点:

  • InjectionⅢ只能在模拟器中使用,目前还不能进行真机调试;
  • InjectionⅢ动态调试时,新增的类/方法/属性/变量会生效,删除的类/方法/属性/变量仍然可以动态访问;
  • InjectionⅢ只监视当前文件的改动,如果要动态新增类,需要在当前文件中新增;

问题记录

Could not find file

记录日期:2020-04-03

错误提示:如下(目标、文件名等已省略)

1
2
3
4
5
💉 *** Compiling /xxx.m ***
💉 *** Re-compilation failed (... .../com.johnholdsworth.InjectionIII/Data/command.sh)
fatal error: malformed or corrupted AST file: 'could not find file '... .../Pods/BaiduMapKit/BaiduMapKit/BaiduMapAPI_Search.framework/Headers/BMKPOISearchResult.h' referenced by AST file '... .../PrefixHeader.pch.gch''
note: after modifying system headers, please delete the module cache at '/... ...'
1 error generated.

错误原因:PrefixHeader中引用了BaiduMapKit,而BaiduMapKit中对文件的引用(包括BMKPOISearchResult.h),有两处文件名的大小写不正确,导致InjectionⅢ对变动的文件重新编译时失败。

错误分析:XCode中import文件名大小写不正确时会报“Non-portable path”的警告,在InjectionⅢ这儿即导致了重编译的失败,同时信息中也说明InjectionⅢ重编译时使用了PrefixHeader.pch等system headers的编译缓存。

-------------This article is over, thank you for reading -------------