OC與JS互動 初體會
第一篇部落格,有點小緊張、小期待,會不會有人看?有也好,沒有也罷,權當自己圖個樂兒,記錄近來學到的知識。閒話少說,進入正題!
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