iOS让友盟分享SDK支持HTTPS -- 使用runtime hook 友盟分享SDK

先放两张效果图,是在同一个workspace中代码修改前修改后app网络请求的结果图。可以很明显看到通过修改自己的代码,改变了友盟分享SDK的网络请求协议。

iOS让友盟分享SDK支持HTTPS -- 使用runtime hook 友盟分享SDK_第1张图片
图1.修改前(不支持HTTPS)
iOS让友盟分享SDK支持HTTPS -- 使用runtime hook 友盟分享SDK_第2张图片
图2.修改后(支持HTTPS)

说明:项目ATS Settings设置了Allow Arbitrary Loads = YES,即允许HTTP请求。
本过程使用XCode 8.2.1运行appiPhone5s上,iPhone5s上设置代理到本机8888端口,Charles监听本机8888端口,可以拦截appHTTP/HTTPS网络请求。通过Charles拦截app的网络请求,可以观察到app的所有HTTP/HTTPS请求,是否符合AppleATS要求。以下两张图聚焦友盟分享SDK的网络请求。

最初,可以很轻松地观察拦截到的友盟SDK请求为HTTP协议(如图1),但是使用HTTPS协议也能访问,比如 https://api.share.mob.com 和 http://api.share.mob.com 都可以访问。
由此看来,友盟分享的网站是支持HTTPS的。这是改变友盟分享SDK的网络协议的基础

然后,寻找切入点。查看友盟SDK的头文件,发现MOBFoundation.frameworkMOBFApplication.h文件中有检测是否启用ATS的功能。可以从这点出发对它进行改造。

iOS让友盟分享SDK支持HTTPS -- 使用runtime hook 友盟分享SDK_第3张图片
MOBFApplication.h声明

替换方法很简单,使用runtime知识即可,这里使用Method Swizzling对原始方法进行替换。因为不需要原始方法的逻辑,只用自己的方法替换掉原始方法就好,不用管原始方法的逻辑。实现起来很简单:

-(void)exchangeMethodMobEnabledATS{
    Method originATS_enable = class_getClassMethod([MOBFApplication class], @selector(enabledATS));
    Method changeATS_enable = class_getClassMethod([HomeLifeAppDelegate class], @selector(app_enableATS));
    method_exchangeImplementations(originATS_enable, changeATS_enable);
}

+ (BOOL)app_enableATS{
    return true;
}

application:didFinishLaunchingWithOptions:方法中调用

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
      [self exchangeMethodMobEnabledATS];
}

运行工程,Charles中拦截的友盟SDK网络请求如下:

iOS让友盟分享SDK支持HTTPS -- 使用runtime hook 友盟分享SDK_第4张图片
Method Swizzling以后

效果非常明显,除了一个HTTP请求以外,其它请求都改用HTTPS了。这说明之前的思路是正确的。
剩下的这个HTTP请求估计是时机的问题,猜测很可能是exchangeMethodMobEnabledATS方法调用之前就已经确定好enableATS的值了。我们可以将exchangeMethodMobEnabledATS方法的执行时机提前,看是否有什么不同。

App能否在main()函数之前执行代码呢?它的入口在哪里呢?
我们一般考虑App的生命期是从main()函数开始的,main()函数执行以后会进入AppDelegate中的application:willFinishLaunchingWithOptions:等方法,这样看来,application:willFinishLaunchingWithOptions:方法已经是最早可以执行代码的时机了。

事实上,有某种方法可以让函数在main()函数之前或者之后执行。如下所示:

+ (BOOL)app_enableATS{
       return true;
}

static void __attribute__((constructor)) before_main_exchange_method() {
    Method originATS_enable = class_getClassMethod([MOBFApplication class], @selector(enabledATS));
    Method changeATS_enable = class_getClassMethod([HomeLifeAppDelegate class], @selector(app_enableATS));
    method_exchangeImplementations(originATS_enable, changeATS_enable);
}

可以放在工程的任何地方,都会在main()函数执行前被执行(某些SDK和库不用开发者调用都能自动执行,原来The Point在这里→_→)。
也就是之后执行enabledATS方法时都会调用自定义的app_enableATS方法,保证友盟SDK在判断环境的时候都会认为当前是ATS可用状态

这样做了以后,友盟SDK已经完全支持HTTPS了,无论工程设置了是否允许HTTP。其网络请求如下:

iOS让友盟分享SDK支持HTTPS -- 使用runtime hook 友盟分享SDK_第5张图片
screenshot5.png

PS:

main()函数或exit()函数之后执行代码的能力:

staticvoid__attribute__((destructor)) after_main_exchange_method() {   

}

可以用它干些有意思的事了(o)/

你可能感兴趣的:(iOS让友盟分享SDK支持HTTPS -- 使用runtime hook 友盟分享SDK)