原理和上篇文章一样 : 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);
}];
}