steipete/Aspects
的设计,挺高深莫测的
- 一般我们 hook, hook 一个类的所有实例的方法
这里 hook 的粒度,到了对象级别
- 而且不需要建立,大量的 IMP
利用到了固有的方法转发的流程
本文主要参考 woshiccm/Aspect
分析下 Aspects 的 swift 源代码实现
Aspects 的大概设计
1, 方法换一个时机执行
1.1, 方法转发的流程
方法执行的时候,将 hook 的 selector 的实现 IMP 替换为 _objc_msgForward 或者_objc_msgForward_stret,
此时调用 selector, 就会进行消息转发
1.2,实际做事情的函数
将 forwardInvocation 的实现, 替换为自定义的函数
__ASPECTS_ARE_BEING_CALLED__
并添加 __aspects_forwardInvocation 的实现为 forwardInvocation 原来的实现。
我们 hook 的方法 selector ,需要进行消息转发
我们 hook 的方法 selector, 都会执行自定义的函数
__ASPECTS_ARE_BEING_CALLED__
1.3, 自定义的函数中
执行了原来的方法,和 hook 的 block
这样,原来的方法,还是跑了,但是在一个不同的时机
方便我们处理
2, 需要执行的 hook 方法
得到了有利的时机
把 hook 在前面,在后面,用来替换的方法,给执行了
2.1, 执行对应的 block
Aspects 中,把 hook 的 block 的描述信息中,捞出 NSMethodSignature
使用 NSMethodSignature,执行 hook 的 block
2.2,执行原来的方法
NSInvocation 的实例, invoke 下
Swift Aspect 中的具体实现
3.1 调用
有这么个实例方法
@objc dynamic func test(id: Int, name: String) {
print("come on")
}
hook 上面那个方法
_ = try? hook(selector: #selector(ViewController.test(id:name:)), strategy: .before) { (_, id: Int, name: String) in
print("done")
}
开始 hook
@discardableResult
func hook<Arg1, Arg2>(
selector: Selector,
strategy: AspectStrategy = .before,
block: @escaping(AspectInfo, Arg1, Arg2) -> Void) throws -> AspectToken
{
// 拿到需要插入执行的 block
let wrappedBlock: @convention(block) (AspectInfo) -> Void = { aspectInfo in
guard aspectInfo.arguments.count == 2,
let arg1 = aspectInfo.arguments[0] as? Arg1,
let arg2 = aspectInfo.arguments[1] as? Arg2 else { return }
block(aspectInfo, arg1, arg2)
}
let wrappedObject: AnyObje

本文深入分析了 Swift Aspects 库的源代码实现,探讨了方法在不同时机执行的原理,包括利用方法转发流程、自定义函数执行以及如何执行 hook 的 block。同时,介绍了 Swift Aspects 的主要流程,如动态创建子类、方法交换等,并指出了其在 Swift 中的局限性和与 Objective-C 版本的差异。
最低0.47元/天 解锁文章
798

被折叠的 条评论
为什么被折叠?



