避免因?yàn)閞espondsToSelector:, performSelector:上線被拒
記得前段時(shí)間iOS開發(fā)者很多都收到了使用JSPatch被拒的郵件,
Your app, extension, and/or linked framework appears to contain code designed explicitly with the capability to change your app’s behavior or functionality after App Review approval, which is not in compliance with section 3.3.2 of the Apple Developer Program License Agreement and App Store Review Guideline 2.5.2. This code, combined with a remote resource, can facilitate significant changes to your app’s behavior compared to when it was initially reviewed for the App Store. While you may not be using this functionality currently, it has the potential to load private frameworks, private methods, and enable future feature changes.
This includes any code which passes arbitrary parameters to dynamic methods such as dlopen(), dlsym(), respondsToSelector:, performSelector:, method_exchangeImplementations(), and running remote scripts in order to change app behavior or call SPI, based on the contents of the downloaded script. Even if the remote resource is not intentionally malicious, it could easily be hijacked via a Man In The Middle (MiTM) attack, which can pose a serious security vulnerability to users of your app.
Please perform an in-depth review of your app and remove any code, frameworks, or SDKs that fall in line with the functionality described above before submitting the next update for your app for review.
Best regards
App store Review
導(dǎo)致很多開發(fā)者炸鍋,大家都忙著去掉帶有JSPatch的框架或者更新新的框架,
那時(shí)候記得我也是有很多的三方框架有問題,比如高德,比如bugly...
去掉熱更新成為3月份的時(shí)候一大重要事件.
當(dāng)然現(xiàn)在又回歸了平靜,
當(dāng)然JSPatch等熱更新框架的移除我們肯定都會(huì)做,但是也會(huì)有部分開發(fā)者壓根就沒有使用JSPatch熱更新,但是應(yīng)用也會(huì)收到郵件,
原因可能就在這里
我們有注意到responseToSelector和performSelector,
回想一下,我們會(huì)經(jīng)常使用...
所以很多躺槍就在這里,我在JSPatch剛剛被限制的時(shí)候移除框架后仍然被拒,就是因?yàn)檫@兩個(gè)方法.
于是我想到了替代這兩個(gè)方法
#import <Foundation/Foundation.h>
@interface NSObject (Extension)
-(BOOL)canRunToSelector:(SEL)aSelector;
- (id)runSelector:(SEL)aSelector withObjects:(NSArray *)objects;
@end
#import "NSObject+Extension.h"
#import <objc/runtime.h>
@implementation NSObject (Extension)
-(BOOL)canRunToSelector:(SEL)aSelector{
unsigned int methodCount =0;
Method *methodList = class_copyMethodList([self class],&methodCount);
NSString *selectorStr = NSStringFromSelector(aSelector);
BOOL result = NO;
for (int i = 0; i < methodCount; i++) {
Method temp = methodList[i];
const char* selectorName =sel_getName(method_getName(temp));
NSString *tempSelectorString = [NSString stringWithUTF8String:selectorName];
NSLog(@"%@",tempSelectorString);
if ([tempSelectorString isEqualToString:selectorStr]) {
result = YES;
break;
}
}
free(methodList);
return result;
}
- (id)runSelector:(SEL)aSelector withObjects:(NSArray *)objects {
NSMethodSignature *methodSignature = [self methodSignatureForSelector:aSelector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
[invocation setTarget:self];
[invocation setSelector:aSelector];
NSUInteger i = 1;
if (objects.count) {
for (id object in objects) {
id tempObject = object;
[invocation setArgument:&tempObject atIndex:++i];
}
}
[invocation invoke];
if (methodSignature.methodReturnLength) {
id value;
[invocation getReturnValue:&value];
return value;
}
return nil;
}
@end
通過這兩個(gè)方法,我替換了郵件提到的兩個(gè)危險(xiǎn)的方法,雖然不是很完美,但是我們的應(yīng)用沒有問題了.順利上架
其實(shí)方法本身不是很復(fù)雜,還是使用runtime,第一個(gè)方法是獲取當(dāng)前類的所有的實(shí)例方法名,跟提供的方法名做比較
第二個(gè)方法則是采用OC的另一種調(diào)用方法的實(shí)現(xiàn)NSInvocation,把原先的方法和參數(shù)等轉(zhuǎn)換成采用NSInvocation調(diào)用而已.
兩個(gè)方法不復(fù)雜,很多人稍微想一想都會(huì)有這樣的類似的結(jié)果.
當(dāng)然,現(xiàn)在寫這個(gè)對(duì)于經(jīng)歷了JSPatch事件的開發(fā)者沒有什么作用,因?yàn)槭录呀?jīng)過去近兩個(gè)月了,但是我覺得我還是有必要把我的實(shí)現(xiàn)提供出來,方便剛剛參與到開發(fā)的小伙伴或者之前很碰巧沒有碰到熱更新的事件的開發(fā)者們.