第一篇博客,有点小紧张、小期待,会不会有人看?有也好,没有也罢,权当自己图个乐儿,记录近来学到的知识。闲话少说,进入正题!
OC与JS交互的方式:1、使用UIWebView通过拦截Request完成JS调取OC,通过stringByEvaluatingJavaScriptFromString注入JS函数或者取数据完成OC调取JS
2、使用WKWebView通过- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler完成OC调取JS,通过- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name拦截完成JS调取OC,还可以通过- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name完成JS调用OC
3、苹果有提供JavaScriptCore库,可以完成交互
4、第三方库WebViewJavascriptBridge
一、使用UIWebView
拦截Request完成JS调取OC
1 #pragma mark - UIWebViewDelegate 2 3 /** 4 这些都是JS响应的样式 5 UIWebViewNavigationTypeLinkClicked, 点击 6 UIWebViewNavigationTypeFormSubmitted, 提交 7 UIWebViewNavigationTypeBackForward, 返回 8 UIWebViewNavigationTypeReload, 刷新 9 UIWebViewNavigationTypeFormResubmitted, 重复提交 10 UIWebViewNavigationTypeOther 其他 11 12 */ 13 // 加载所有请求数据,以及控制是否加载 14 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{ 15 16 NSLog(@"%@",request.URL.scheme); // 标识 我们自己协议 17 NSLog(@"%@",request.URL.host); // 方法名 18 NSLog(@"%@",request.URL.pathComponents); // 参数 19 20 // JS 调用OC 的原理就是 拦截URL 21 NSString *scheme = request.URL.scheme; 22 if ([scheme isEqualToString:@"custom"]) { 23 NSLog(@"来了,我们自定义的协议"); 24 25 NSArray *args = request.URL.pathComponents; 26 NSString *methodName = args[1]; 27 28 29 SEL methodSel = NSSelectorFromString(methodName); 30 if ([self respondsToSelector:methodSel]) { 31 32 [self performSelector:methodSel withObject:args[2]]; 33 34 } 35 36 return NO; 37 } 38 39 return YES; 40 }
通过stringByEvaluatingJavaScriptFromString注入JS函数或者取数据完成OC调取JS
// 加载完成 - (void)webViewDidFinishLoad:(UIWebView *)webView{ //获取title NSString *titlt = [webView stringByEvaluatingJavaScriptFromString:@"document.title"]; self.title = titlt; } //调用JS函数 NSString *result = [self.webView stringByEvaluatingJavaScriptFromString:@"showAlert('HELLO')"];
二、使用WKWebView
拦截Request
#pragma mark - WKNavigationDelegate - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { NSURL *URL = navigationAction.request.URL; NSString *scheme = [URL scheme]; if ([scheme isEqualToString:@"tzedu"]) { 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); }else{ NSLog(@"不明地址 %@",host); } decisionHandler(WKNavigationActionPolicyCancel); return; } decisionHandler(WKNavigationActionPolicyAllow); } - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{ self.title = webView.title; }
MessageHandler:
- (void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"messgaeOC"]; } - (void)viewWillDisappear:(BOOL)animated{ [super viewWillDisappear:animated]; //注意循环引用 [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"messgaeOC"]; } #pragma mark - WKScriptMessageHandler - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{ NSLog(@"message == %@ --- %@",message.name,message.body); }
OC调取JS:
NSString *jsStr2 = @"showAlert('messageHandle:OC-->JS')"; [self.webView evaluateJavaScript:jsStr2 completionHandler:^(id _Nullable result, NSError * _Nullable error) { NSLog(@"%@----%@",result, error); }];
三、JavaScriptCore
JSContext:给JavaScript提供运行的上下文环境
JSValue:JavaScript和Objective-C数据和方法的桥梁
JSManagedValue:管理数据和方法的类
JSVirtualMachine:处理线程相关,使用较少
JSExport:这是一个协议,如果采用协议的方法交互,自己定义的协议必须遵守此协议
- (void)webViewDidFinishLoad:(UIWebView *)webView{ NSString *titlt = [webView stringByEvaluatingJavaScriptFromString:@"document.title"]; self.title = titlt; //JSContext就为其提供着运行环境 H5上下文 JSContext *jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; self.jsContext = jsContext; __weak typeof(self) weakSelf = self; // 异常处理 self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception) { context.exception = exception; NSLog(@"exception == %@",exception); NSLog(@"%@",context); }; // 提供给JS全局变量 [self.jsContext evaluateScript:@"var arr = [3, 'Hello', 'abc'];"]; self.jsContext[@"showMessage"] = ^() { JSValue *thisValue = [JSContext currentThis]; NSLog(@"thisValue = %@",thisValue); JSValue *cValue = [JSContext currentCallee]; NSLog(@"cValue = %@",cValue); NSArray *args = [JSContext currentArguments]; NSLog(@"来了:%@",args); NSDictionary *dict = @{@"name":@"cooci",@"age":@18}; [[JSContext currentContext][@"ocCalljs"] callWithArguments:@[dict]]; }; // 因为是全局变量 可以直接获取 JSValue *arrValue = self.jsContext[@"arr"]; NSLog(@"arrValue == %@",arrValue); //纠正用法 // JSValue *value = [JSValue valueWithObject:@"test“ inContext:context]; // JSManagedValue *managedValue = [JSManagedValue managedValueWithValue:value andOwner:self]; self.jsContext[@"showDict"] = ^(JSValue *value) { //注意线程问题 NSArray *args = [JSContext currentArguments]; JSValue *dictValue = args[0]; NSDictionary *dict = dictValue.toDictionary; NSLog(@"%@",dict); // 模拟用 int num = [[arrValue.toArray objectAtIndex:0] intValue]; num += 10; NSLog(@"arrValue == %@ num == %d",arrValue.toArray,num); dispatch_async(dispatch_get_main_queue(), ^{ weakSelf.showLabel.text = dict[@"name"]; }); }; //异常收集 self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception) { weakSelf.jsContext.exception = exception; NSLog(@"exception == %@",exception); }; // JS 操作对象 KC_JSObject *kcObject = [[KC_JSObject alloc] init]; self.jsContext[@"kcObject"] = kcObject; // 打开相册 self.jsContext[@"getImage"] = ^() { weakSelf.imagePicker = [[UIImagePickerController alloc] init]; weakSelf.imagePicker.delegate = weakSelf; weakSelf.imagePicker.allowsEditing = YES; weakSelf.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; [weakSelf presentViewController:weakSelf.imagePicker animated:YES completion:nil]; }; } #import <Foundation/Foundation.h> #import <JavaScriptCore/JavaScriptCore.h> @protocol KCProtocol <JSExport> - (void)letShowImage; JSExportAs(getSum, -(int)getSum:(int)num1 num2:(int)num2); @end @interface KC_JSObject : NSObject<KCProtocol> @end #import "KC_JSObject.h" @implementation KC_JSObject - (void)letShowImage{ NSLog(@"打开相册,上传图片"); } - (int)getSum:(int)num1 num2:(int)num2{ return num1+num2; } @end
四、WebViewJavascriptBridge
https://github.com/marcuswestin/WebViewJavascriptBridge