bundleid修改後ocr插件ExCardSDK不能使用的解決辦法

 

原理和上篇文章一樣 :  https://blog.csdn.net/qq_15509071/article/details/102688400

 

這裏直接貼代碼

 

#import "NSBundle+yyy.h"
#import <objc/runtime.h>
@implementation NSBundle (yyy)
+ (void)load{
    
//    NSString *bundleid = [[self mainBundle] bundleIdentifier];
    
      {
    
        Method originalMethod = class_getInstanceMethod([NSBundle class], @selector(bundleIdentifierS));
        Method swizzledMethod = class_getInstanceMethod([NSBundle class], @selector(bundleIdentifier));
        method_exchangeImplementations(originalMethod, swizzledMethod);
    
    }
    {
        Method originalMethod = class_getInstanceMethod([NSBundle class], @selector(infoDictionaryS));
        Method swizzledMethod = class_getInstanceMethod([NSBundle class], @selector(infoDictionary));
        method_exchangeImplementations(originalMethod, swizzledMethod);
        
    }
//    {
//        Method originalMethod = class_getInstanceMethod([NSBundle class], @selector(localizedInfoDictionaryS));
//        Method swizzledMethod = class_getInstanceMethod([NSBundle class], @selector(localizedInfoDictionary));
//        method_exchangeImplementations(originalMethod, swizzledMethod);
//
//    }
}
- (NSDictionary*)infoDictionaryS{
    NSMutableDictionary *dicc = [self infoDictionaryS].mutableCopy;
    if ([Global sharedData].useHookBundleid == YES) {
        [dicc setObject:@"需要的" forKey:@"CFBundleIdentifier"];
    }
    return dicc;
}
- (NSString *)bundleIdentifierS{
    if ([Global sharedData].useHookBundleid == YES) {
        return @"需要的";
    }else{
        return [self bundleIdentifierS];
    }
}

 

 

識別身份證的調用方法

    [EXOCRCardEngineManager initEngine];
    self.manager = [EXOCRQuadRecoManager sharedManager:、];
    [self.manager setDisplayLogo:NO];
    [self.manager setRecoTimeout:90];
    setCustomScanView
    [self.manager recoQuadCardFromStreamByCustomScanViewWithCardType:EXOCRCardTypeIDCARD];



協議方法
/**
 *  @brief   識別完成,獲取識別結果
 *  @param   info - 識別結果模型
 */
-(void)recoCompleted:(id)info;{
    //識別成功後的操作
    [self.manager dismissScanViewControllerAnimated:YES];
}

initEngine 裏面寫 useHookBundleid = YES;

由於協議方法是在實現的類裏實現的,所以useHookBundleid = No,不能按照之前的思路。

方法1:識別成功都調用了dismissScanViewControllerAnimated:YES,在這個方法里加上。但如果沒調用就會有問題

@implementation EXOCRQuadRecoManager (YYY)
+ (void)load{
//    {
//        Method originalMethod = class_getInstanceMethod([self class], @selector(dismissScanViewControllerAnimated:));
//        Method swizzledMethod = class_getInstanceMethod([self class], @selector(dismissScanViewControllerAnimatedS:));
//        method_exchangeImplementations(originalMethod, swizzledMethod);
//
//    }
}
//////掃描身份證結束
//-(void)dismissScanViewControllerAnimatedS:(BOOL)animated;{
//
//    [Global sharedData].useHookBundleid = NO;
//
//    [self dismissScanViewControllerAnimatedS:animated];
//}

方法2:參考:https://www.jianshu.com/p/2d9774c8b224 對代理方法hook。哪個類實現了代理給哪個類替換方法。

@interface EXOCRQuadRecoManager (YYY)
@end

@implementation EXOCRQuadRecoManager (YYY)
+ (void)load{
    {
//交換的是設置代理的方法
        Method originalMethod = class_getInstanceMethod([self class], @selector(setCustomScanView:));
        Method swizzledMethod = class_getInstanceMethod([self class], @selector(setCustomScanViewS:));
        method_exchangeImplementations(originalMethod, swizzledMethod);
        
    }

}

- (BOOL)setCustomScanViewS:(UIView *)customScanView{
    BOOL isSc =  [self setCustomScanViewS:customScanView];
    dz_exchangeMethod([customScanView class], @selector(recoCompleted:), [self class], @selector(recoCompletedS:),@selector(orirecoCompleted:));
    return isSc;
}

- (void)recoCompletedS:(UIWebView *)webView
{
    [Global sharedData].useHookBundleid = NO;
    [self recoCompletedS:webView];
}


static void dz_exchangeMethod(Class originalClass, SEL originalSel, Class replacedClass, SEL replacedSel, SEL orginReplaceSel){
    // 原方法
    Method originalMethod = class_getInstanceMethod(originalClass, originalSel);
    // 替換方法
    Method replacedMethod = class_getInstanceMethod(replacedClass, replacedSel);
    // 如果沒有實現 delegate 方法,則手動動態添加
    if (!originalMethod) {
        Method orginReplaceMethod = class_getInstanceMethod(replacedClass, orginReplaceSel);
        BOOL didAddOriginMethod = class_addMethod(originalClass, originalSel, method_getImplementation(orginReplaceMethod), method_getTypeEncoding(orginReplaceMethod));
        if (didAddOriginMethod) {
            NSLog(@"did Add Origin Replace Method");
        }
        return;
    }
    // 向實現 delegate 的類中添加新的方法
    // 這裏是向 originalClass 的 replaceSel(@selector(replace_webViewDidFinishLoad:)) 添加 replaceMethod
    BOOL didAddMethod = class_addMethod(originalClass, replacedSel, method_getImplementation(replacedMethod), method_getTypeEncoding(replacedMethod));
    if (didAddMethod) {
        // 添加成功
        NSLog(@"class_addMethod_success --> (%@)", NSStringFromSelector(replacedSel));
        // 重新拿到添加被添加的 method,這裏是關鍵(注意這裏 originalClass, 不 replacedClass), 因爲替換的方法已經添加到原類中了, 應該交換原類中的兩個方法
        Method newMethod = class_getInstanceMethod(originalClass, replacedSel);
        // 實現交換
        method_exchangeImplementations(originalMethod, newMethod);
    }else{
        // 添加失敗,則說明已經 hook 過該類的 delegate 方法,防止多次交換。
        NSLog(@"Already hook class --> (%@)",NSStringFromClass(originalClass));
    }
}
@end

 

 

 

 

 

 

 

 

 

 

 

 

 

下面是另一種使用方法

 

需要用到的地方:身份證識別     
    [Global sharedData].useHookBundleid = YES;
 
    [EXOCRCardEngineManager initEngine];

    self.manager = [EXOCRQuadRecoManager sharedManager:self.controller];
    
    [self.manager recoQuadCardParticularFromStreamWithCardType:EXOCRCardTypeIDCARD OnParticularCompleted:^(int statusCode, id cardInfo) {
        [Global sharedData].useHookBundleid = NO;
        //。。。
    } OnCanceled:^(int statusCode) {
        [Global sharedData].useHookBundleid = NO;
        
    } OnFailed:^(int statusCode, UIImage *recoImg) {
        [Global sharedData].useHookBundleid = NO;
        
    }];

這樣也是每一個地方都要寫。簡化一下

在上邊的類中添加如下代碼

        {
            Method originalMethod = class_getInstanceMethod([self class], @selector(recoQuadCardParticularFromStreamWithCardType:OnParticularCompleted:OnCanceled:OnFailed:));
            Method swizzledMethod = class_getInstanceMethod([self class], @selector(recoQuadCardParticularFromStreamWithCardType:OnParticularCompleted:OnCanceled:OnFailedS:));
            method_exchangeImplementations(originalMethod, swizzledMethod);
    
        }


-(void)recoQuadCardParticularFromStreamWithCardType:(EXOCRCardType)cardType

                              OnParticularCompleted:(EXOCRCompletedQuadCardParticularBlock)completedBlock

                                         OnCanceled:(EXOCRCanceledBlock)EXOCRCanceledBlock

                                           OnFailedS:(EXOCRFailedBlock)EXOCRFailedBlock;{
    [self recoQuadCardParticularFromStreamWithCardType:cardType OnParticularCompleted:^(int statusCode, id cardInfo) {
        [Global sharedData].useHookBundleid = NO;
        completedBlock(statusCode,cardInfo);

    } OnCanceled:^(int statusCode) {
        [Global sharedData].useHookBundleid = NO;

        EXOCRCanceledBlock(statusCode);

    } OnFailedS:^(int statusCode, UIImage *recoImg) {
        [Global sharedData].useHookBundleid = NO;

        EXOCRFailedBlock(statusCode,recoImg);

    }];
    
}

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章