UIWebView篇
- OC调用JS
1.在webView加载完成后调用:
//在oc中调用js的jsFun方法,并传入参数“hi,js”
[self.webView stringByEvaluatingJavaScriptFromString:@"jsFun('hi,js')"];
- 通过JavaScriptCore的方式(该方法需要导入JavaScriptCore框架)
在webView加载完成后调用:
//JSContext就为其提供着运行环境 H5上下文
JSContext *jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
self.jsContext = jsContext;
//给js传参
[self.jsContext evaluateScript:@"var arr = [3, 'Cooci', 'abc'];"];
也可以用这种方式:
// 将js方法转换成一个JSValue对象 然后调用并传参数
JSValue * value = self.jsContext[@"jsFun"];
dispatch_async(dispatch_get_main_queue(), ^{
[value callWithArguments:@[@"hi",@"js"]];
});
- JS调用OC
1.在webView的代理中拦截自定义的scheme
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSLog(@"%@",request.URL.scheme); // 标识 我们自己协议
NSLog(@"%@",request.URL.host); // 方法名
NSLog(@"%@",request.URL.pathComponents); // 参数
// JS 调用OC 的原理就是 拦截URL
NSString *scheme = request.URL.scheme;
if ([scheme isEqualToString:@"custom"]) {
NSLog(@"来了,我们自定义的协议");
NSArray *args = request.URL.pathComponents;
NSString *methodName = args[1];
// 方法1
// if ([methodName isEqualToString:@"getSum"]) {
// [self getSum];
// }
// 方法2
SEL methodSel = NSSelectorFromString(methodName);
if ([self respondsToSelector:methodSel]) {
#pragma clang diagnostic push
// 让编译器忽略错误
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
// 让编译器出栈,恢复状态,继续编译后续的代码!
[self performSelector:methodSel withObject:args[2]];
#pragma clang diagnostic pop
}
// 方法3
// objc_msgSend(self,methodSel,args[2],args[3]);
((void (*) (id, SEL, id))(objc_msgSend))(self, methodSel,args[2]);
// 定义kc_msgSend 函数指针 (void *) 替代了 (void (*)(id, SEL, id))
void (*kc_msgSend) (id, SEL, id) = (void *)objc_msgSend;
kc_msgSend(self,methodSel,args[2]);
return NO;
}
}
- 也可以采用JavaScriptCore的方式
//实现js里的jsFun方法 [JSContext currentContext]来避免循环引用
self.jsContext[@"jsFun"] = ^() {
NSArray *args = [JSContext currentArguments];
NSLog(@"args:%@",args); //获取js里调用该方法传的参数
NSDictionary *dict = @{@"name":@"cooci",@"age":@18};
//这里可以继续去调用js方法 如此反复
dispatch_async(dispatch_get_main_queue(), ^{
[[JSContext currentContext][@"jsFun"] callWithArguments:@[dict]];
});
}
JavaScriptCore的另外一些用法:
JS可以直接调用OC的对象方法:
OC中建立一个协议,并遵循JSExport协议,建立一个对象,遵循该协议
@protocol JSObjectProtocol <JSExport>
- (void)hello;
//相当于一个方法的简写。js中可以直接通过getSum来调用 getSumWithFirst 方法
JSExportAs(getSum, -(int)getSumWithFirst:(int)a second:(int)b third:(int)c);
@end
@interface JSObject : NSObject<JSObjectProtocol>
@end
@implementation JSObject
- (void)hello {
NSLog(@"hello");
}
- (int)getSumWithFirst:(int)a second:(int)b third:(int)c {
return a+b+c;
}
@end
使用:
//OC中绑定
JSObject * jsObject = [[JSObject alloc] init];
self.jsContext[@"jsObject"] = jsObject;
//js中调用
jsObject.hello()
jsObject.getSum(1,2,3)
JS异常处理:
self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception) {
context.exception = exception;
NSLog(@"exception == %@",exception);
NSLog(@"%@",context);
};
WKWebView篇
- OC调用JS
NSString *jsStr = [NSString stringWithFormat:@"showAlert('%@')",@"登陆成功"];
[self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
NSLog(@"%@----%@",result, error);
}];
- JS调用OC
1.跟UIWebView类似,通过拦截的方式
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
NSURL *URL = navigationAction.request.URL;
NSString *scheme = [URL scheme];
if ([scheme isEqualToString:@"custom"]) {
NSString *host = [URL host];
if ([host isEqualToString:@"jsCallOC"]) {
NSMutableDictionary *temDict = [self decoderUrl:URL];
NSString *username = [temDict objectForKey:@"username"];
NSString *password = [temDict objectForKey:@"password"];
NSLog(@"%@---%@",username,password);
具体使用同上 :uiwebview里
}else{
NSLog(@"不明地址 %@",host);
}
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
2.通过MessageHandle的方式
WKUserContentController *userContentController = [[WKUserContentController alloc] init];
[configuration.userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:@“jsFun”];
此处,messageHandle对self强引用了,所以需要在viewWillDisAppear里打破循环引用
[webView.configuration.userContentController removeScriptMessageHandlerForName:@"jsFun"];
写在文末
还有一些优秀的第三方的oc、js交互框架,例如:WebViewJavascriptBridge,使用起来非常的方便,就是需要前端配合一起开发才可以使用,感兴趣的可以去了解一下。WebViewJavaScriptBridge 基本使用
网友评论