提示:文章只是用来记录本人自己在学习过程中所遇到的一些问题的解决方案,如果有什么意见可以留言提出来,不喜勿喷哦!
问题提出
问题产生于我所做的第一个项目,项目需要用到 WebView 也就是UIWebView,拦截JS请求的方法还是采用的在 delegate 的回调方法 shouldStartLoadWithRequest 里面拦截 http 请求来实现的。
但是要采用怎么的方式才能井然有序地通过 JS 代用原生方法呢?于是想到了采用反射的机制来实现这种交互。
方法构思
- 首先得和编写 JS 的人约定好 JS 请求原生方法的 Http 请求格式,例如:以 "cqutobjc://" 这种格式标志来进行方法和参数的提取。
- 编写一个 JS 调用原生方法的方法列表类,里面包含了所有 JS 要调用的原生方法和具体实现。
- 编写一个用于拦截 JS 请求的类,UIWebView 的实例化可以不用卸载里面,但是 delegate 必须给这个类。每次 JS 调用原生方法,都在回调方法里面调用反射类进行反射调用。
代码实现
这里我就只展示反射类的代码,其他类的实现可以参照以上描述(被调用的原生方法列表类为Operation类)。
#import <Foundation/Foundation.h>
@interface JudgmentRequest : NSObject
+ (JudgmentRequest *)shareinstance;
-(void)Judgment:(NSArray *)DataArr;
@end
#import "JudgmentRequest.h"
#import "Operation.h"
static Class tmp;
@implementation JudgmentRequest
+ (JudgmentRequest *)shareinstance{
static JudgmentRequest *tool = nil;
static dispatch_once_t oneToken;
dispatch_once(&oneToken, ^{
tool=[[JudgmentRequest alloc] init];
tmp = NSClassFromString(@"Operation");
});
return tool;
}
- (void)Judgment:(NSArray *)DataArr{
NSString *methodName = @"";
NSArray *temparr = [DataArr[0] componentsSeparatedByCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@"|"]];
if ([temparr count] > 1) {//判断是否有参数
int length = [DataArr count];
if(length >= 1)//有参函数(可以去掉)
{
NSMutableArray * paramValueArr = [[NSMutableArray alloc] init];
for (int i = 0;i < length ; i++) {
NSArray * dataArray = [DataArr[i] componentsSeparatedByCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@"|"]];
paramValueArr[i] =dataArray[1];
methodName = [methodName stringByAppendingString:dataArray[0]];
methodName = [methodName stringByAppendingString:@":"];
}
SEL sel = NSSelectorFromString(methodName);
//判断实例中是否包含这个方法,类似的还有是否属于某一个类等接口
if([tmp respondsToSelector:sel] == YES) {
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:
[tmp methodSignatureForSelector:sel]];
[inv setSelector:sel];
[inv setTarget:tmp];
int paramLength = [paramValueArr count];
for (int i = 0; i < paramLength; i++) {
NSString * paramTmp = @"";
paramTmp = [paramTmp stringByAppendingString:paramValueArr[i]];
[inv setArgument:¶mTmp atIndex:i+2];
[inv retainArguments];
}
[inv invoke];
}
}
}
else//无参函数
{
methodName = [methodName stringByAppendingString:DataArr[0]];
SEL sel = NSSelectorFromString(methodName);
if([tmp respondsToSelector:sel] == YES) {
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:
[tmp methodSignatureForSelector:sel]];
[inv setSelector:sel];
[inv setTarget:tmp];
[inv invoke];
}
}
}
注意:具体使用可能需要具体修改!