工作原理
injection
通过分析上次的build
日志来得出资源文件是如何被编译的。在这个分析结果的基础上进行再次编译,并将再次编译的结果包裹到一个bundle
中,然后使用动态加载器将这个bundle
注入到应用当中。至此应用中已经有了某个类的两个版本,一个原始版本一个来自bundle
中的已修改版本。接着,被修改的版本被swizzled
到原始的类中并发挥作用。这种特性适用于OS X
和iOS
的模拟器以及真机的应用中。
关于更深入的实现分析,请看这篇文章。
安装
点击http://injectionforxcode.johnholdsworth.com/InjectionPluginV6.4.pkg“>这里下载injection
的安装应用。你也可以在这里获取关于injection
的所有资源。
Xcode 7
的安装很简单,而Xcode 8
的安装就复杂一些了。苹果引入了官方的扩展API
,但目前只局限于资源编辑器扩展。苹果还将Xcode
签名来阻止未签名的代码的注入与执行。这些从安全方面来说是好的,但也阻止了一些类似于injection
的工具的安装。
网上提供的Xcode 8
安装插件的解决方案:
- update_xcode_plugins
- MakeXcodeGr8Again
-
需要强调一点,如果需要在真机上运行,插件的项目文件中需要包含你的
codesigning
,有两个工程需要更新codesigning
,这两个文件分别是: InjectionPluginLite/InjectionPlugin.xcodeproj
InjectionPluginLite/iOSBundleTemplate/InjectionBundle.xcodeproj
如果你有多个签名身份(例如一个个人身份和一个企业身份),那么你需要在
InjectionPlugin.xcodeproj
项目中的build phase
下的run script
中指明一个特定的身份你可以通过查看
produce
下拉菜单中的选项是否包含injection plugin
和inject source
选项来确定是否安装成功。
测试你的项目能否被正常注入
在任意一个viewController
中注入如下代码
- (void)injected {
NSLog(@"i've been injected");
}
这个方法在注入被触发的时候会被执行。
编译运行你的项目,选中product > inject source,或者按下快捷键^=。你会看到以下输出内容:
i've been injected
如果是这样那么你就成功了。
你可以打开 injection console
,这样就可以看到每次注入的结果以及一些错误信息。
可以基于以下三个回调来注入你的代码:
- (void)injected
一个实例方法,可以在这个方法里以新的上下文环境更新对象。+ (void)injected
一个类方法,可以在新的上下文中更新全局变量。监听
INJECTION_BUNDLE_NOTIFICATION
,允许其他的类来监听injection
的回调,这种方式使你能够在应用级别修改代码。在调试UI时,你可以随意改动相关类的代码,然后^=一下,
injection console
提示成功之后,将页面pop
或者dimiss
之后再次进入,你就可以看到修改的代码已经在发挥作用了。或者你也可以在injected
方法中调用viewcontroller
的viewDidLoad
方法。
遇到的问题
injection
的作者说目前暂不支持iOS 10
的真机设备的测试,看这里。所以就只能用iOS 9
的设备,然而我们iOS 9
的设备也不多。。。用模拟器吧。- 为了解决
xcode 8
签名的问题,我用上述方式安装了一个Xcode 8 - unsigned
,暂不确定用这种Xcode
开发会不会有别的问题。 - 一开始我以为^=之后修改的代码就能立即发挥作用,后来发现需要将页面
pop
之后再次进入,因为这个类是被修改了,但是页面还是需要重新渲染的。 injection
具有一些局限性,比如当新版本的类被加载到项目当中,它会引入自己的静态变量,例如shareInstance
和once token
。在注入发生之后,就会产生两个版本的单例实例。为了避免这种情况的发生,类方法中以shared
开头的将不会被swizzled
。