本文只是介绍简单的OC与JS交互
一、OC调用JS
<html>
<header>
<meta http-equiv="Content-Type" content="text/html"; charset="UTF-8"/>
<title>zhaoName制作的网页</title>
</header>
<script Type = "text/javascript">
function login()
{
return 100;
}
</script>
<body>
电话:10086
<button style="background:red; width:120px; height:30px;">call</button>
</body>
</html>
调用webView的方法
// 获取网页的标题
self.title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
// 调用JS中的函数
NSLog(@"%@", [webView stringByEvaluatingJavaScriptFromString:@"login();"]);
该方法返回一个字符串,注意它是一个同步方法,若使用它执行非常耗时的操作会导致界面的卡顿。有两个解决方案:
1>使用官方推荐webView方法evaluateJavaScript:completionHandler:
2>自定义一个延迟执行方法来防止阻塞,或将方法放到setTimeout 中
二、JS调用OC
<html>
<header>
<meta http-equiv="Content-Type" content="text/html"; charset="UTF-8"/>
<title>zhaoName制作的网页</title>
</header>
<script Type = "text/javascript">
function login()
{
location.href = 'zhaoName://openLibrary';
}
</script>
<body>
电话:10086
<button style="background:red; width:120px; height:30px;" onclick="login();">call</button>
<br>
<a href="https://github.com/zhaoName">zhaoName的Git</a>
</body>
</html>
以下都是点击webView上的按钮”call”,调用OC中的方法
1、没有参数
/**
* 通过这个方法完成JS调OC
*/
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSString *url = @"zhaoname://";
if ([request.URL.absoluteString hasPrefix:url])
{
NSString *methodName = [request.URL.absoluteString substringFromIndex:url.length];
[self performSelector:NSSelectorFromString(methodName) withObject:nil];
return NO;
}
NSLog(@"想加载网络请求,不想做JS调用OC");
return YES;
}
- (void)openLibrary
{
NSLog(@"JS调用OC方法--%s", __func__);
}
2、一个参数
上面HTML中函数修改为
function login()
{
location.href = 'zhaoName://sendMessage_?How are you';
}
OC获取的路径path会自动删除’:’,所以此处用’_’代替。参数用?分割。(实际开发中需要你和写HTML的人共同制定JS调OC的规则)
/**
* 通过这个方法完成JS掉OC
*/
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSString *url = @"zhaoname://";
if ([request.URL.absoluteString hasPrefix:url])
{
// 路径
NSString *path = [request.URL.absoluteString substringFromIndex:url.length];
NSArray *subPaths = [path componentsSeparatedByString:@"?"];
// 获取方法名
NSString *methodName = [subPaths.firstObject stringByReplacingOccurrencesOfString:@"_" withString:@":"];
// 参数
NSString *para = subPaths.lastObject;
[self performSelector:NSSelectorFromString(methodName) withObject:para];
return NO;
}
NSLog(@"想加载网络请求,不想做JS调用OC");
return YES;
}
- (void)sendMessage:(NSString *)message
{
NSLog(@"JS调用OC方法--%s 参数:%@", __func__, message);
}
3、两个参数
上面HTML中函数修改为
function login()
{
location.href = 'zhaoName://sendMessage_sendName_?hehe&zhaoName';
}
‘:’用’_’代替,方法名和参数用’?’分割,参数之间用’&’分割
/**
* 通过这个方法完成JS掉OC
*/
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSString *url = @"zhaoname://";
if ([request.URL.absoluteString hasPrefix:url])
{
// 路径
NSString *path = [request.URL.absoluteString substringFromIndex:url.length];
NSArray *subPaths = [path componentsSeparatedByString:@"?"];
// 获取方法名
NSString *methodName = [subPaths.firstObject stringByReplacingOccurrencesOfString:@"_" withString:@":"];
// 参数
NSArray *paras = nil;
// 防止出现无参数的情况
if(subPaths.count == 2 || [subPaths.lastObject containsString:@"&"])
{
paras = [subPaths.lastObject componentsSeparatedByString:@"&"];
}
// 防止出现参数为空的情况
NSString *firstPara = paras.firstObject;
NSString *secondPara = paras.count <= 1 ? nil : paras.lastObject;
[self performSelector:NSSelectorFromString(methodName) withObject:firstPara withObject:secondPara];
return NO;
}
NSLog(@"想加载网络请求,不想做JS调用OC");
return YES;
}
- (void)sendMessage:(NSString *)message sendName:(NSString *)sendName
{
NSLog(@"JS调用OC方法--%s 参数:%@ %@", __func__, message, sendName);
}
4、三个及以上的参数
系统自带的方法performSelector最多只能传两个参数,所以有三个及以上的参数我们要借助NSInvocation类。
NSObject+Invocation.h文件
#import <Foundation/Foundation.h>
@interface NSObject (Invocation)
/**
* 基于NSObject封装一个可用于JS调用OC方法的分类,适用于参数可有可无,可有多个
@param selector 方法名
@param parameters 参数
@return 返回值
*/
- (id)performSelector:(SEL)selector withParameters:(NSArray *)parameters;
@end
NSObject+Invocation.m文件
#import "NSObject+Invocation.h"
@implementation NSObject (Invocation)
- (id)performSelector:(SEL)selector withParameters:(NSArray *)parameters
{
// 方法签名
NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector];
if(signature == nil) return nil;
// 利用NSIvocation可以包装一次方法调用(设置方法调用者、方法名、参数、返回值)
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
// 设置方法调用者
invocation.target = self;
// 设置方法名
invocation.selector = selector;
// 设置方法参数 注意参数下标从2开始,0、1被系统占用
for(int i=0; i<parameters.count; i++)
{
id object = parameters[i];
if([object isKindOfClass:[NSNull class]]) continue;
[invocation setArgument:&object atIndex:i+2];
}
// 执行
[invocation invoke];
// 设置返回值
id returnValue = nil;
// 兼顾没有返回值的方法
if(signature.methodReturnLength != 0)
{
[invocation getReturnValue:&returnValue];// 说明此方法有返回值
}
return returnValue;
}
@end
上面HTML中函数修改为
function login()
{
location.href = 'zhaoName://sendMessage_sendName_reviceName_?hehe&zhaoName&nicai';
}
/**
* 通过这个方法完成JS掉OC
*/
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSString *url = @"zhaoname://";
if ([request.URL.absoluteString hasPrefix:url])
{
// 路径
NSString *path = [request.URL.absoluteString substringFromIndex:url.length];
NSArray *subPaths = [path componentsSeparatedByString:@"?"];
// 获取方法名
NSString *methodName = [subPaths.firstObject stringByReplacingOccurrencesOfString:@"_" withString:@":"];
// 参数
NSArray *paras = [subPaths.lastObject componentsSeparatedByString:@"&"];
// 调用OC中的方法 并获取返回值
NSString *result = [self performSelector:NSSelectorFromString(methodName) withParameters:paras];
NSLog(@"%@", result);
return NO;
}
NSLog(@"想加载网络请求,不想做JS调用OC");
return YES;
}
- (NSString *)sendMessage:(NSString *)message sendName:(NSString *)sendName reviceName:(NSString *)reviceName
{
NSLog(@"JS调用OC方法--%s 参数:%@ %@ %@", __func__, message, sendName, reviceName);
return @"发信息";
}