JavaScript和Objective-c交互
- 现在的开发不再是纯原生的开发了,在很多APP中,很多活动页面、或者说专题页面,都采用了H5的页面
- 这种方式的好处就是这些页面可以很方便的修改,不用提交新的APP到AppStore去审核
- 那么js和oc的交互就分为:js调用oc方法、oc调用js方法 两种情况
OC调用JS
-
stringByEvaluatingJavaScriptFromString
方法执行js语句
// 执行JS语句
[webView stringByEvaluatingJavaScriptFromString:@"alert(100);"];
// 利用JS获得当前网页的标题
NSString *title = [webView stringByEvaluatingJavaScriptFromString:@"document.title;"];
// 执行JS函数
[webView stringByEvaluatingJavaScriptFromString:@"login();"];
JS调用OC
这种模式有点麻烦,就是传递参数的问题
不传递参数、一个或者两个参数,这些情况比较简单
但是想传递多个参数,就比较麻烦了
-
思路:
- 1、在网页中发送请求,如果是想调用OC方法,那么就需要自定义协议头
- 2、请求的地址需要自定义:协议头和方法名还有参数的拼接需要定义好规则
- 3、在UIWebView的代理方法中拦截请求,判断协议头
- 4、截取出方法名和参数
没有参数
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
// URL:YYHttp://方法名
NSString *url = request.URL.absoluteString;
// 自定义协议头
NSString *scheme = @"YYHttp://";
if ([url hasPrefix:scheme]) {
NSString *methodName = [url substringFromIndex:scheme.length];
[self performSelector:NSSelectorFromString(methodName) withObject:nil];
return NO;
}
return YES;
}
一个或者两个参数
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
// url == YYHttp://sendMessage_number2_?200&300
NSString *url = request.URL.absoluteString;
NSString *scheme = @"YYHttp://";
if ([url hasPrefix:scheme]) {
// 获得协议后面的路径 path == sendMessage_number2_?200&300
NSString *path = [url substringFromIndex:scheme.length];
// 利用?切割路径
NSArray *subpaths = [path componentsSeparatedByString:@"?"];
// 方法名 methodName == sendMessage:number2:
NSString *methodName = [[subpaths firstObject] stringByReplacingOccurrencesOfString:@"_" withString:@":"];
// 参数 200&300
NSString *param = [subpaths lastObject];
NSArray *subparams = nil;
if (subpaths.count == 2 || [param containsString:@"&"]) {
subparams = [param componentsSeparatedByString:@"&"];
}
// 取出前面的2个参数
NSString *firstParam = [subparams firstObject];
NSString *secondParam = subparams.count <= 1 ? nil : [subparams lastObject];
[self performSelector:NSSelectorFromString(methodName) withObject:firstParam withObject:secondParam];
return NO;
}
return YES;
}
三个或以上参数
- 这个时候就需要自定义方法去实现传递多个参数
- 需要用到
NSInvocation
- 只要下面这个方法定义好,那么直接传入数组即可
一个或者两个参数也可以使用下面这种方式
- (id)performSelector:(SEL)selector withObjects:(NSArray *)objects
{
// 方法签名(方法的描述)
NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector];
if (signature == nil) {
// 一般在这里面抛出异常
//@throw [NSException exceptionWithName:@"方法名错误" reason:@"方法找不到" userInfo:nil];
//[NSException raise:@"方法名错误" format:@"%@方法找不到", NSStringFromSelector(selector)];
}
// NSInvocation : 利用一个NSInvocation对象包装一次方法调用(方法调用者、方法名、方法参数、方法返回值)
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.target = self;
invocation.selector = selector;
// 设置参数
NSInteger paramsCount = signature.numberOfArguments - 2; // 除self、_cmd以外的参数个数
paramsCount = MIN(paramsCount, objects.count);
for (NSInteger i = 0; i < paramsCount; i++) {
id object = objects[i];
if ([object isKindOfClass:[NSNull class]]) continue;
[invocation setArgument:&object atIndex:i + 2];
}
// 调用方法
[invocation invoke];
// 获取返回值
id returnValue = nil;
if (signature.methodReturnLength) { // 有返回值类型,才去获得返回值
[invocation getReturnValue:&returnValue];
}
return returnValue;
}