1. 程式人生 > >JSPatch被拒之完美解決方案

JSPatch被拒之完美解決方案

  首先在裡這宣告,這篇文章主要是為了幫助使用過JSPatch被拒絕想要移除,或者沒有使用JSpatch被無辜牽連的小夥伴們。是為了如何在不違反蘋果規的則情況下,解決釋出被拒絕的問題,如果您是為了尋求JSPatch替代方案的,那麼您可以離開這個頁面了。

JSPatch被拒iOS開發者炸鍋

事件起因,今年3月8日大部分的開發者收到了這樣的一郵封件:

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

當時我這邊接到警告的時候,有點懵懵的,接近20個app同時收到了警告,第一時間去網上檢視各資種料,尋各找路大神的神蹟,很遺憾,各大路神,在這時個間點發聲的很少,標題黨倒是不少哦。直到最終看到兩篇部落格後,我才到找了方向。
http://www.jianshu.com/p/6803d660f67e
http://reactnative.cn/post/3551
根據這兩篇部落格自分己析,蘋果這次稽核JPSacth不是單純的憑藉某個點來判斷你是否使用了熱復修功能,而是根據以下幾點個形成證據鏈來判定你否是使用了熱修復的功能。
1. 網路/下載功能
2. 內建指令碼引擎 (JSPatch等指令碼引工擎具)
3. 動態訪問API
為了能夠保證app順利上架,那麼我們就需要破掉壞蘋果判我們違規的證據鏈。

網路/下載功能

  我們的app都具有網路連線,下載資文源件的功能,所以這一點我們無法下手去理處,但是我還是們刪了熱復修腳本下發的介面,以及相關的程式碼。

內建指令碼引擎 (JSPatch等指令碼引工擎具)

  這個通過上第面一篇部落格知道,個推,高德地圖,BugTags,Bugly 等SDK具有熱修復功能 ,我們需要在app中逐一排查,是否具有熱修復等功能,為了保險,我邊這把有所使用到的第方三sdk都一篇排查了幾遍,這裡我不就一一詳細說明了,當然了也排除不了我們的app中有自己實現的熱修復功能的程式碼片段。這個需要我們己自去查排了,自己的程式碼自己最清楚了。

動態訪問API

  所謂動態訪問API就是可以通過字串訪問相關的方法。
經過對第一步,第二步的處理,我這邊關閉掉了js熱修復指令碼下發介面;排查並替換刪除了所有第三方SDK;但是仍然被拒絕了四次。參考了http://www.wtoutiao.com/p/7cbSPhD.html
已經蘋果警告中提到的兩個方法respondsToSelector:, performSelector: 感覺蘋果對動態API的檢測應該是這兩個方法結合使用的時候,來現實判定的。根絕參考部落格上說的

比如這麼寫是沒問題的:

if([self.delegate respondsToSelector: @selector(myDelegateMethod)]) {
   [self.delegate performSelector: @selector(myDelegateMethod)];
}

這麼寫就可能被打回:

NSString *remotelyLoadedString = .... (download from your backend)
[self performSelector: NSSelectorFromString(remotelyLoadedString)];

我覺得有要必繞開respondsToSelector:, performSelector: 這兩個方法,使用具有同樣功能的方法來替換。我的們app中就有使用類似程式碼的地方

SEL selector = NSSelectorFromString(selectorStr);
        if ([weakSelf respondsToSelector:selector]) {

            SuppressPerformSelectorLeakWarning([weakSelf performSelector:selector withObject:parameter]);

        }

這的樣程式碼就容很易被蘋果認定具有熱復修功能。

我寫了兩個方法如下:

+ (BOOL)validateMehodCanRunWithTarget:(id)target selectorStr:(NSString *)selectorStr{
    unsigned int methodCount =0;
    Method* methodList = class_copyMethodList([target class],&methodCount);
    NSMutableArray *methodsArray = [NSMutableArray arrayWithCapacity:methodCount];

    for(int i=0;i<methodCount;i++)
    {
        Method temp = methodList[i];
        IMP imp = method_getImplementation(temp);
        SEL name_f = method_getName(temp);
        const char* name_s =sel_getName(method_getName(temp));
        int arguments = method_getNumberOfArguments(temp);
        const char* encoding =method_getTypeEncoding(temp);
        NSLog(@"方法名:%@,引數個數:%d,編碼方式:%@",[NSString stringWithUTF8String:name_s],
              arguments,
              [NSString stringWithUTF8String:encoding]);
        [methodsArray addObject:[NSString stringWithUTF8String:name_s]];
    }
    free(methodList);
    for (NSString *methodStr   in [methodsArray copy]) {
        if ([methodStr isEqualToString:selectorStr]) {

            return YES;
            break;
        }
    }

    return NO;

}

用上面的方法我替換了respondsToSelector但是有一點需要格外逐一,使用方法列表只能獲取例項方法,不獲能取類方法,所以我把app中原來要判定的是類方法的轉換成了例項方法來現實。

至於performSelector的替換,我這邊參考網上,寫了一個NSObject的category 添加了一個新的方法:

- (id)runSelector:(SEL)aSelector withObjects:(NSArray *)objects {
    NSMethodSignature *signature = [self methodSignatureForSelector:aSelector];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    [invocation setTarget:self];
    [invocation setSelector:aSelector];

    NSUInteger i = 1;

    for (id object in objects) {
        id tempObject = object;
        [invocation setArgument:&tempObject atIndex:++i];
    }
    [invocation invoke];

    if ([signature methodReturnLength]) {
        id data;
        [invocation getReturnValue:&data];
        return data;
    }
    return nil;
}

通過這兩個方法來破壞蘋認果認定我使用動態API的證據鏈。我們的app順利的上了架。特此把己自的心歷路程和大家分享,幫大家解決難題。

更多優質文章,可以微信掃碼關注:
這裡寫圖片描述