记一次Runtime的巧用
背景
我们的视频直播是用的大华乐橙
的解决方案,而他们近期出来个新的SDK,并且对老版SDK不兼容,而这周,终于把大华乐橙
的新版SDK切换了,和这一周做的新的东西,一起提交审核了,并且今天也通过审核了。然后就和大华的技术支持联系,商讨数据的迁移。突然发现,我们用的是一个开发者帐号(该帐号下面创建了也只能创建一个应用,大华给了App ID
和App Secret
)来开发了两个App(用户版和商家版),而旧版的SDK这样是可行的,但是新版的不行。这是因为在大华新版SDK那边请求接口的时候会验证一个安全码
,这个安全码是由Bundle identifier
和 Project name
组合的,他们的SDK内部会获取当前的App的Bundle identifier
,heProject name
,和开发者帐号创建应用时提供的安全码做比较,如果不一致,那么就直接拒绝请求。
解决过程
互相了解了情况之后,双方都有点不知所措,就像后台隆哥说的:奇葩碰奇葩了
。一开始,我们这边是一直在等待大华那边出方案,看看能不能在数据库做个映射,把两个开发者帐号关联起来。但是大华那边好像不太好弄,毕竟涉及到线上数据库的操作,可以理解。但是我们这样坐以待毙下去也不行,只能想想自己这边能不能做一些事情。
首先,开始理清思路:
- 大华那边需要验证
安全码
,而这个安全码
又是Bundle identifier
和Project name
组合,我们不可能去改工程的Bundle identifier
和Project name
,所以,修改工程这个方法不行。 - 那么我们这边可不可以给他们返回固定的
Bundle identifier
和Project name
,来欺骗他们的验证,这个貌似是可以,但是这也有几个问题:- 他们的SDK是
.a
静态库,所以不能改他们的代码。 - 那就只能去猜测他们可能会获取当前
Bundle identifier
和Project name
的方法,http://www.90168.org/在iOS
中,获取Bundle identifier
和Project name
的方法,我知道的,也是最常用的就是:
- 他们的SDK是
1 2
|
NSString *identifier = [NSBundle mainBundle].bundleIdentifier; NSString *projectName = [[NSBundle mainBundle].infoDictionary objectForKey:(NSString *)kCFBundleNameKey];
|
所以,我猜测他们可能也是用的这个方法,那么能不能劫持他们调用这个方法,给他们返回固定的值,由于劫持函数这一方面实在是不懂,所以这个没搞头。
在谷歌上面转了一圈,突然,发现了一个词:method_exchangeImplementations
.哈,Bingo.
方案确定:method_exchangeImplementations
.
在SO
上面看到这个词,让我灵机一动,我可不可以去替换他们用来获取Bundle identifier
和 Project name
的方法,说搞就搞,我在AppDelegate.m
里面写了一下代码来测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
- (void)changeIdentifierAndName { method_exchangeImplementations(class_getInstanceMethod([NSBundle class], @selector(bundleIdentifier)), class_getInstanceMethod([self class], @selector(jly_bundleIdentifier))); method_exchangeImplementations(class_getInstanceMethod([NSBundle class], @selector(infoDictionary)), class_getInstanceMethod([self class], @selector(jly_bundleName))); } - (NSString *)jly_bundleIdentifier { return @"com.xiongqi.XXXXX"; } // 发现直接调用kCFBundleNameKey不行,然后就打印了这个Key,发现kCFBundleNameKey对应的是CFBundleName - (NSDictionary *)jly_bundleName { return @{@"CFBundleName":@"XXXXXXX"};// 这里简化了infoDictionary,仅仅是为了测试。 }
|
然后在didFinishLaunchingWithOptions:
里面调用了changeIdentifierAndName
.然后进入运行我们的App,打开店铺的直播,熟悉的画面出现在眼前,也就是我们通过Runtime
来绕过了大华
的所谓安全码
检测!
后续
但是,这又引起了另一个问题,我们这样去替换系统的方法,会不会被苹果拒绝审核?在家shadowsocks
不能用,明天去公司谷歌一下,或者就给经理说说去提交试试。然后来完善。
感想
从想法到确定方案到实现,20分钟,这件事也教会我,有些事还是要靠自己,依靠别人是行不通的!公司不缺干活的,但是需要解决问题的。