# 背景

项目中遇到一个问题,需要引入两个 SDK,我们暂且命名为 A 和 B,由于业务需要这两个 SDK 都需要对一个系统函数 C 进行 hook, 但是有一个前提,由于 B 所做的是一个统计相关的 SDK,所以 B 要监控 App 内的所有代码这其中也包括了 SDK A 所做的一些操作,所以我们必须确保 B 在 hook C 函数时候 A 已经对 C 函数 hook 完毕,其实这就涉及到 hook 顺序的问题。

# 研究

先看下代码,我用 hookMethod 来模仿系统方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (void) TEST_HOOK_TWICE {
[self changeOrginalSelectorName:@"hookedMethod" inClass:@"RootViewController" withCustomSelectorName:@"swizzle_hookedMethod1" isClassMethod:NO];

[self changeOrginalSelectorName:@"hookedMethod" inClass:@"RootViewController" withCustomSelectorName:@"swizzle_hookedMethod2" isClassMethod:NO];

[self hookedMethod];

}

- (void)hookedMethod {
NSLog(@"原始方法");
}

- (void)swizzle_hookedMethod1 {
NSLog(@"1");
[self swizzle_hookedMethod1];
}

- (void)swizzle_hookedMethod2 {
NSLog(@"2");
[self swizzle_hookedMethod2];
}

然后看下没有 hook 之前的样子

原本的样子

然后我们执行代码

1
2
3
4
5
6
//第一步:交换A中的方法和系统方法
[self changeOrginalSelectorName:@"hookedMethod" inClass:@"RootViewController" withCustomSelectorName:@"swizzle_hookedMethod1" isClassMethod:NO];
//第二步:交换B中的方法和系统方法
[self changeOrginalSelectorName:@"hookedMethod" inClass:@"RootViewController" withCustomSelectorName:@"swizzle_hookedMethod2" isClassMethod:NO];
//第三步:调用系统方法
[self hookedMethod];

然后我们一步一步来看,先看调用第一步之后是什么样子的 (红色箭头为第一步之后的样子)

第一步之后

然后看第二步调用完之后的样子 (绿色是第二步调用)

第二部之后的样子

接下来我们调用系统方法也就是第三步,然后我们看下流程是怎样的 (每个方法实现里面都会递归调用下自身,为了是 hook 时候不改变原有逻辑)

调用顺序

这样一来就很明显 如果想想监控住所有的代码那就需要在 A IMP 这步,因为之前的 Hook 顺序是先 A -> B -> System 这样一来只要我们改一下顺序改为 B -> A -> System 就可以让 B SDK 监控到所有的代码。

调用顺序