1、簡介javascript
在前面一篇文章中講到過實現JavaScript與Native交互的方式有一種就是使用原生內嵌webView。在iOS8以前,開發者只能使用蘋果提供的UIWebView類來加載URL或者HTML網頁視圖,而後經過設置代理,在回調函數中攔截並處理自定義交互事件,功能十分有限,一般只是做爲一個輔助視圖使用。在iOS8以後,蘋果對這方面的技術進行了重構和優化,推出了一個新的框架WebKit。WebKit提供了Native與JavaScript交互的方法,整個框架的結構很清晰,對外暴露的接口友好實用,極大地方便了開發者實現網頁視圖和的Native交互。而且,WebKit框架採用導航堆棧的模式來管理網頁視圖的跳轉,對於網頁視圖的管理和渲染,開發者更加容易管控。慢慢地,咱來比較這兩種webView的使用區別。css
2、UIWebViewhtml
一、UIWebView的詳細構成前端
UIWebView的類構成之:屬性java
//id類型,遵照UIWebViewDelegate協議 @property (nullable, nonatomic, assign) id <UIWebViewDelegate> delegate //只讀屬性,webView內部的滾動視圖 @property (nonatomic, readonly, strong) UIScrollView *scrollView //只讀屬性,是否能夠後退 @property (nonatomic, readonly, getter=canGoBack) BOOL canGoBack //只讀屬性,是否能夠前進 @property (nonatomic, readonly, getter=canGoForward) BOOL canGoForward //只讀屬性,是否正在加載 @property (nonatomic, readonly, getter=isLoading) BOOL loading //是否支持縮放頁面自適應 @property (nonatomic) BOOL scalesPageToFit //是否檢測電話號碼(連接形式) @property (nonatomic) BOOL detectsPhoneNumbers //枚舉類型,數據檢測類型。如電話、郵箱等 @property (nonatomic) UIDataDetectorTypes dataDetectorTypes //是否使用內聯播放器播放視頻 @property (nonatomic) BOOL allowsInlineMediaPlayback //視頻是否自動播放 @property (nonatomic) BOOL mediaPlaybackRequiresUserAction //是否支持air play功能 @property (nonatomic) BOOL mediaPlaybackAllowsAirPlay //是否將數據加載到內存後渲染界面 @property (nonatomic) BOOL suppressesIncrementalRendering //是否支持用戶打開鍵盤進行交互 @property (nonatomic) BOOL keyboardDisplayRequiresUserAction //是否支持視頻畫中畫 @property (nonatomic) BOOL allowsPictureInPictureMediaPlayback //是否支持連接預覽 @property (nonatomic) BOOL allowsLinkPreview //頁面長度 @property (nonatomic) CGFloat pageLength //頁面間距 @property (nonatomic) CGFloat gapBetweenPages //頁面數量 @property (nonatomic, readonly) NSUInteger pageCount //枚舉類型,分頁模式 @property (nonatomic) UIWebPaginationMode paginationMode //枚舉類型,決定加載頁面具備CSS屬性時是採用頁樣式仍是類樣式 @property (nonatomic) UIWebPaginationBreakingMode paginationBreakingMode
UIWebView的類構成之:方法web
//加載URL類型的webView - (void)loadRequest:(NSURLRequest *)request //加載HTML類型的webView - (void)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL //加載NSData類型的webView - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)textEncodingName baseURL:(NSURL *)baseURL //刷新webView - (void)reload //中止加載webView - (void)stopLoading //返回上一頁 - (void)goBack //前進下一頁 - (void)goForward //調用JavaScript代碼 - (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script
UIWebView的類構成之:協議數組
//即將對網頁URL發送請求,經過返回布爾值決定是否跳轉,根據scheme或者navigationType匹配來作攔截處理,以完成端上的交互行爲 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType //網頁已經開始加載時調用 - (void)webViewDidStartLoad:(UIWebView *)webView //網頁完成加載時調用 - (void)webViewDidFinishLoad:(UIWebView *)webView //網頁加載失敗時調用 - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
UIWebView的類構成之:枚舉cookie
//導航類型 UIWebViewNavigationType UIWebViewNavigationTypeLinkClicked //觸擊一個連接 UIWebViewNavigationTypeFormSubmitted //提交一個表單 UIWebViewNavigationTypeBackForward //觸擊前進或返回按鈕 UIWebViewNavigationTypeReload //觸擊從新加載的按鈕 UIWebViewNavigationTypeFormResubmitted //用戶重複提交表單 UIWebViewNavigationTypeOther //發生其它行爲 //翻頁模式 UIWebPaginationMode UIWebPaginationModeUnpaginated //無分頁 UIWebPaginationModeLeftToRight //從左往右翻頁 UIWebPaginationModeTopToBottom //從下往上翻頁 UIWebPaginationModeBottomToTop //從上往下翻頁 UIWebPaginationModeRightToLeft //從右往左翻頁 //CSS模式 UIWebPaginationBreakingMode UIWebPaginationBreakingModePage //頁樣式 UIWebPaginationBreakingModeColumn //列樣式
二、UIWebView的使用,混合開發
app
[2-1] 建立一個HTML文件框架
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .divcss{ border:1px solid #F00; width:300px; height:200px} </style> <script type="text/javascript"> function showAlert(){ alert("我被成功調起來了"); //<!-- JS通知WKWebView, methodInvoke就是和端上約定的方法名稱 --> var list = [1,2,3]; var dict = {"name":"XYQ", "qq":"1273843", "list":list}; window.webkit.messageHandlers.methodInvoke.postMessage(dict); } function disp_confirm() { var r=confirm("Press a button") if (r==true){ document.write("You pressed OK!") } else{ document.write("You pressed Cancel!") } } function disp_prompt() { var name=prompt("Please enter your name","") if (name!=null && name!=""){ document.write("Hello " + name + "!") } } </script> </head> <body> <div class="divcss"> <!-- 這是一個連接跳轉地址,點擊時,端上將會進行攔截,彈出日誌 --> <a href="http://www.w3school.com.cn/">Visit W3School</a> <br> <br> <a href="parent://www.parent.com.cn/">open parent</a> </div> <input type="button" onclick="disp_confirm()" value="Display a confirm box" /> <input type="button" onclick="disp_prompt()" value="Display a prompt box" /> </body> </html>
[2-2] 建立並加載webView
- (void)viewDidLoad { [super viewDidLoad]; //建立webView self.webView = [[UIWebView alloc] initWithFrame:self.view.bounds]; self.webView.delegate = self; //建立html NSString *file = [[NSBundle mainBundle] pathForResource:@"web" ofType:@"html"]; NSString *html = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil]; //加載webView [self.webView loadHTMLString:html baseURL:nil]; [self.view addSubview:self.webView]; }
[2-3] 設置代理,事件攔截
#pragma mark - UIWebViewDelegate -(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSLog(@"------------網頁即將開始加載------------"); //實際工做中,獲取scheme或者navigationType,經過匹配scheme或者navigationType來攔截頁面中的點擊行爲來完成端上交互 //這個scheme能夠自定義的,不過須要跟前端約定好。例如"http"、"https"、"iOS"等等 , 例子如:"iOS://baidu.com/con/"
//一、點擊連接 if (navigationType == UIWebViewNavigationTypeLinkClicked) { // <a href="http://www.w3school.com.cn/">Visit W3School</a> NSString *scheme = request.URL.scheme; if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]) { //H5調用原生方法,顯示iOS的彈框 NSString *href = request.URL.absoluteString; [self showAlertView:href]; } return NO; //取消網頁加載, 那麼該連接就不會進行跳轉了 } //二、點擊按鈕 if (navigationType == UIWebViewNavigationTypeFormSubmitted) { //H5調用原生方法,打開相冊 [self openPhotoLibrary]; //取消網頁加載, 那麼該提交事件就不會觸發了 return NO; } return YES; } -(void)webViewDidStartLoad:(UIWebView *)webView { NSLog(@"------------網頁已經開始加載------------"); } -(void)webViewDidFinishLoad:(UIWebView *)webView { NSLog(@"------------網頁已經完成加載------------"); //原生調用js方法,顯示window的alert內容 [self showWindowAlertString]; } -(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { NSLog(@"------------網頁已經加載失敗------------"); }
[2-4] 原生方法和JS事件
#pragma mark - h5 call native -(void)openPhotoLibrary { //打開Native系統相冊 UIImagePickerController *picker = [[UIImagePickerController alloc] init]; picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; picker.modalPresentationStyle = UIModalPresentationFullScreen; [self presentViewController:picker animated:YES completion:nil]; } -(void)showAlertView:(NSString *)message { //打開Native系統彈框 UIAlertController *aletVc = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *action = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]; [aletVc addAction:action]; [self presentViewController:aletVc animated:YES completion:nil]; } #pragma mark - native call js -(void)showWindowAlertString { //顯示H5頁面中的被調用的JS函數返回的彈框內容 NSString *result = [self.webView stringByEvaluatingJavaScriptFromString:@"alert()"]; [self showAlertView:result]; }
[2-5] 結果分析和顯示
經過html格式即將加載webView時,代理方法會依次調用123。除非加載失敗,纔會打印出4;
加載成功後,此時原生調用JS代碼,頁面會彈出調用js函數返回的內容;
點擊連接時,原本應該跳轉到新的頁面,可是端上在即將加載頁面作了攔截,返回值設置了NO,因此不會跳轉;
點擊按鈕時,原本HTML頁面的js事件會觸發,可是因爲端上在即將加載頁面作了攔截,返回值設置了NO,因此不會觸發js事件;
//首次加載HTM 2019-11-15 16:22:19.402276+0800 WebView[57408:2041607] ------------網頁即將開始加載------------ 2019-11-15 16:22:19.403887+0800 WebView[57408:2041607] ------------網頁已經開始加載------------ 2019-11-15 16:22:19.457337+0800 WebView[57408:2041607] ------------網頁已經完成加載------------ //點擊連接 2019-11-15 16:22:23.674148+0800 WebView[57408:2041607] ------------網頁即將開始加載------------ //點擊按鈕 2019-11-15 16:22:28.682868+0800 WebView[57408:2041607] ------------網頁即將開始加載------------
3、WebKit
一、能夠看到使用UIWebView雖然能夠實現Native與H5/JS的交互,可是功能過於簡單,並且在iOS系統快速升級以後,UIWebView已經被蘋果摒棄,再也不被推薦使用,取而代之的則是WebKit框架,就跟UserNotification框架取代UILocalNotification類同樣。WebKit框架用到的類不少,設計的思想更加面向對象化,模塊化,開發者使用起來很是方便,代碼結構清晰。WebKit框架圖大體以下:
二、看完上面的WebKit框架圖是否是感受很清晰,每個模塊有本身的對應的職責,WKWebView很具須要依賴這些模塊,基本能夠知足開發者想要的大多數需求。如今對一些重要的類概念瞭解一下。
三、WKWebView屬性和方法與UIWebView有不少相相似,具體的類的信息能夠看API。
3-1 WKWebView提供了進度progress屬性,可使用KVO監控頁面加載的進度,這個優化能提供用戶一個更好的使用體驗,而這個在UIWebView中是沒有的。
/*! @abstract An estimate of what fraction of the current navigation has been completed. @discussion This value ranges from 0.0 to 1.0 based on the total number of bytes expected to be received, including the main document and all of its potential subresources. After a navigation completes, the value remains at 1.0 until a new navigation starts, at which point it is reset to 0.0. @link WKWebView @/link is key-value observing (KVO) compliant for this property. */ @property (nonatomic, readonly) double estimatedProgress;
3-2 其次,WKWebView相比於UIWebView在導航管理上是更優秀的,採用堆棧管理的方式,可以任意進行不一樣視圖之間的跳轉。這個屬性就是WKBackForwardList,表示的是全部的網頁視圖堆棧,管理每個網頁視圖節點,能夠看看它的構成以下:
//去某一個網頁節點: WKWebView的方法,跳轉到某一個網頁節點 - (nullable WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item;
//這個WKBackForwardList類的構成 //當前網頁節點 @property (nullable, nonatomic, readonly, strong) WKBackForwardListItem *currentItem; //前進的一個網頁節點 @property (nullable, nonatomic, readonly, strong) WKBackForwardListItem *backItem; //回退的一個網頁節點 @property (nullable, nonatomic, readonly, strong) WKBackForwardListItem *forwardItem; //獲取某個index的網頁節點 - (nullable WKBackForwardListItem *)itemAtIndex:(NSInteger)index; //獲取回退的節點數組 @property (nonatomic, readonly, copy) NSArray<WKBackForwardListItem *> *backList; //獲取前進的節點數組 @property (nonatomic, readonly, copy) NSArray<WKBackForwardListItem *> *forwardList;
四、WKWebView中,Native與JavaScript交互以下幾種,這裏列一下基本實現方式,如何實現請看範例
// 第一種:JavaScript調用Native,採用WKUserContentController方式註冊,在WKScriptMessageHandler代理方法中實現 // 第二種:Native調用JavaScript,採用evaluteJavaScript:complementionHandler:方法直接調用JavaScript腳本中的函數來實現 // 第三種:將自定義的JavaScript代碼在端上採用addUserScript方式注入,而後再用evaluteJavaScript:complementionHandler:方法實現 // 第四種:經過WKUIDelegate來處理交互時來實現
五、如今來看一下在實例化WKWebView的過程當中,開發者能夠都設置哪些配置。
5-1 建立配置
//建立配置config WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]; config.suppressesIncrementalRendering = NO; config.applicationNameForUserAgent = @"Safari";
5-2 設置進程池
//設置進程池,擁有同一個pool進程池的多個webView能夠共享數據,如Cookie、用戶憑證等信息 WKProcessPool *pool = [[WKProcessPool alloc] init]; config.processPool = pool;
4-2 設置偏好
//設置偏好,能夠設置一些頁面信息,如字體、是否支持js交互、是否容許自動打開js窗體 WKPreferences *preference = [[WKPreferences alloc] init]; preference.minimumFontSize = 25; preference.javaScriptEnabled = YES; preference.javaScriptCanOpenWindowsAutomatically = YES; config.preferences = preference;
5-3 設置內容交互控制器,處理JavaScript與Native交互
//建立內容交互控制器,處理js與native的交互 //使用addScriptMessageHandler:name: 註冊JavaScript要調用的方法名稱,設置處理代理而且註冊要被JavaScript調用的方法名稱 name:方法名稱 //使用addUserScript:注入代碼,用window.webkit.messageHandlers.name.postMessage()向Native發送消息,支持OC中字典、數組、NSNumber等,設置Cookie //例如注入cookie代碼:NSString *cookieSource= @"document.cookie = 'token=12344';document.cookie = 'userName=xyq';"; //例如注入函數代碼:NSString *funcSource = @"function func(){}"; //注意:要想使用方式二,方式一這一步不可省略。方式一實現後,能夠根據狀況選擇是否須要使用方式二。 WKUserContentController *userContentController = [[WKUserContentController alloc] init]; //方式一:註冊函數,代理回調,這個在H5文件內使用了 "window.webkit.messageHandlers.methodInvoke.postMessage()" [userContentController addScriptMessageHandler:self name:methodInvoke]; //方式二:注入代碼,直接調用,手動注入代碼實現了"window.webkit.messageHandlers.methodInvoke.postMessage()" NSString *methodSource = @"function print(){ window.webkit.messageHandlers.methodInvoke.postMessage(\"hello js!\")}"; WKUserScript *userScript = [[WKUserScript alloc] initWithSource:methodSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES]; [userContentController addUserScript:userScript]; //設置內容交互控制器 config.userContentController = userContentController;
5-4 設置數據存儲
//設置數據存儲,單例 //defaultDataStore:默認的存儲器,會將數據寫入磁盤 //nonPersistentDataStore:臨時的存儲器 WKWebsiteDataStore *store = [WKWebsiteDataStore nonPersistentDataStore]; config.websiteDataStore = store;
5-5 設置代理
//建立WKWebView self.wkWebView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config]; //設置導航代理 self.wkWebView.navigationDelegate = self; //設置js彈出框代理 self.wkWebView.UIDelegate = self;
5-6 加載資源webkit.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .divcss{ border:1px solid #F00; width:300px; height:200px} </style> <script type="text/javascript"> function showAlert(){ alert("我被成功調起來了"); } function disp_confirm() { var r=confirm("Press a button") if (r==true){ document.write("You pressed OK!") } else{ document.write("You pressed Cancel!") } } function disp_prompt() { var name=prompt("Please enter your name","") if (name!=null && name!=""){ document.write("Hello " + name + "!") } } </script> </head> <body> <div class="divcss"> <!-- 這是一個連接跳轉地址,點擊時,端上將會進行攔截,彈出日誌 --> <a href="http://www.w3school.com.cn/">Visit W3School</a> <br> <br> <a href="parent://www.parent.com.cn/">open parent</a> </div> <input type="button" onclick="disp_confirm()" value="Display a confirm box" /> <input type="button" onclick="disp_prompt()" value="Display a prompt box" /> </body> </html>
//加載資源 NSString *file = [[NSBundle mainBundle] pathForResource:@"webkit" ofType:@"html"]; NSString *html = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil]; [self.wkWebView loadHTMLString:html baseURL:nil]; [self.view addSubview:self.wkWebView];
//釋放資源 -(void)dealloc { //必須移除注入的JS代碼 //不然wkWebView沒法被釋放 [self.wkWebView.configuration.userContentController removeScriptMessageHandlerForName:methodInvoke]; //[self.wkWebView.configuration.userContentController removeAllUserScripts]; }
六、WKWebView的代理方法
6-1 接收註冊JavaScript函數的代理回調<WKScriptMessageHandler>
#pragma mark - WKScriptMessageHandler // 獲取調用JavaScript代碼後傳遞過來的消息, 也即接收經過 window.webkit.messageHandlers.methodInvoke.postMessage()傳遞過來的數據 // WKScriptMessage:JavaScript傳遞過來的消息實體,包含:消息主體body、網頁視圖webView、網頁視圖頁面對象frameInfo、方法名稱name - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { NSLog(@"message.body:-------%@------",message.body); }
6-2 監聽網頁加載視圖導航和頁面渲染的代理回調<WKNavigationDelegate>
#pragma mark - WKNavigationDelegate //---------------------- 控制跳轉 注意:方法1和方法2根據本身的須要只重寫一個便可,系統只會調用一個 ----------------------- /* navigationType * WKNavigationTypeLinkActivated, * WKNavigationTypeFormSubmitted, * WKNavigationTypeBackForward, * WKNavigationTypeReload, * WKNavigationTypeFormResubmitted, * WKNavigationTypeOther = -1, */ // 在發送請求時,決定是否跳轉 // decisionHandler:決定是否響應網頁的某一個行爲,包括加載、回退、刷新等 // WKNavigationActionPolicyCancel:取消行動 // WKNavigationActionPolicyAllow: 執行行動 // 在此代理方法能夠設置攔截事件,實現Native與h5交互 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { NSString *scheme = navigationAction.request.URL.scheme; NSLog(@"1-scheme:-------%@-----",scheme); // 在這兒添加端上須要執行的代碼 if (navigationAction.navigationType == WKNavigationTypeLinkActivated) { if ([scheme isEqual:@"parent"]) { NSString *absoluteString = navigationAction.request.URL.absoluteString; UIAlertController *aletVc = [UIAlertController alertControllerWithTitle:@"請求時攔截" message:absoluteString preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *action = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]; [aletVc addAction:action]; [self presentViewController:aletVc animated:YES completion:nil]; decisionHandler(WKNavigationActionPolicyCancel); return; } } decisionHandler(WKNavigationActionPolicyAllow); } // 在發送請求時,決定是否跳轉 // decisionHandler:決定是否響應網頁的某一個行爲,包括加載、回退、刷新等 // WKNavigationActionPolicyCancel:取消行動 // WKNavigationActionPolicyAllow: 執行行動 // 在此代理方法也能夠設置攔截事件,實現Native與h5交互 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction preferences:(WKWebpagePreferences *)preferences decisionHandler:(void (^)(WKNavigationActionPolicy, WKWebpagePreferences *))decisionHandler { NSString *scheme = navigationAction.request.URL.scheme; NSLog(@"2-scheme:-------%@-----",scheme); // 在這兒添加端上須要執行的代碼 if (navigationAction.navigationType == WKNavigationTypeLinkActivated) { if ([scheme isEqual:@"parent"]) { NSString *absoluteString = navigationAction.request.URL.absoluteString; UIAlertController *aletVc = [UIAlertController alertControllerWithTitle:@"請求時攔截" message:absoluteString preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *action = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]; [aletVc addAction:action]; [self presentViewController:aletVc animated:YES completion:nil]; decisionHandler(WKNavigationActionPolicyCancel,preferences); return; } } decisionHandler(WKNavigationActionPolicyAllow,preferences); } // 在收到響應後,決定是否跳轉 // decisionHandler:決定是否響應網頁的某一個行爲,包括加載、回退、刷新等 // WKNavigationResponsePolicyCancel:取消響應 // WKNavigationResponsePolicyAllow:容許響應 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler { NSString *scheme = navigationResponse.response.URL.scheme; NSLog(@"3-scheme:-------%@-----",scheme); // 在這兒添加端上須要執行的代碼 if ([scheme isEqualToString:@"https"] || [scheme isEqualToString:@"htpps:"]) { NSString *absoluteString = navigationResponse.response.URL.absoluteString; UIAlertController *aletVc = [UIAlertController alertControllerWithTitle:@"響應後攔截" message:absoluteString preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *action = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]; [aletVc addAction:action]; [self presentViewController:aletVc animated:YES completion:nil]; } decisionHandler(WKNavigationResponsePolicyAllow); } //-------------------------------------------- 監聽流程 ------------------------------------------- // 當頁面加載啓動時調用 - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation { NSLog(@"1---------當頁面加載啓動時調用---------"); } // 當主機接收到的服務發生重定向時調用 - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation { NSLog(@"2---------當主機接收到的服務發生重定向時調用---------"); } // 當主頁數據加載發生錯誤時調用 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error { NSLog(@"3---------當主頁數據加載發生錯誤時調用---------"); } // 當內容到達主機時調用 - (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation { NSLog(@"4---------當內容到達主機時調用---------"); } // 當主頁加載完成時調用 - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation { NSLog(@"5---------當主頁加載完成時調用---------"); //Native調用JavaScript代碼 //調用H5頁面中定義的showAlert函數 [webView evaluateJavaScript:@"showAlert()" completionHandler:^(id _Nullable obj, NSError * _Nullable error) { if (error) { NSLog(@"call happend error----%@",error); } }]; //Native調用JavaScript代碼 //調用端上注入的js代碼中的print函數 [webView evaluateJavaScript:@"print()" completionHandler:^(id _Nullable obj, NSError * _Nullable error) { if (error) { NSLog(@"call happend error----%@",error); } }]; } // 當提交發生錯誤時調用 - (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error { NSLog(@"6---------當提交發生錯誤時調用---------"); } // 當須要驗證身份憑據時調用 - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler { //身份驗證憑據 NSURLCredential * credential = [[NSURLCredential alloc] initWithTrust:[challenge protectionSpace].serverTrust]; //爲challenge的發送方提供credential [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; completionHandler(NSURLSessionAuthChallengeUseCredential,credential); NSLog(@"7---------驗證身份憑據時調用---------"); } // 當進程被終止時調用 - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView { NSLog(@"8---------當進程被終止時調用---------"); }
6-3 監聽JavaScript的交互過程的回調,如alert等<WKUIDelegate>
#pragma mark - WKUIDelegate // 當建立新的webView時,會調用該代理方法 - (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures { NSLog(@"--------打開新的webView------"); return webView; } // 當調用關閉webView時,會調用該代理方法 - (void)webViewDidClose:(WKWebView *)webView { NSLog(@"--------關閉打開的webView------"); } // ----------------------------- 下面的這些方法是交互JavaScript的方法 -------------------------- // JavaScript調用alert方法後回調的方法,message中爲alert提示信息,必需要在其中調用completionHandler - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler { NSLog(@"---------alert message: %@---------",message);
//顯示alert信息 UIAlertController *aletVc = [UIAlertController alertControllerWithTitle:@"alert" message:message preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *action = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]; [aletVc addAction:action]; [self presentViewController:aletVc animated:YES completion:nil]; completionHandler(); } // JavaScript調用Confirm提交表單方法後的回調的方法,Confirm是JavaScript的肯定框,須要在block中把用戶選擇的狀況傳遞出去 - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler { NSLog(@"---------comfirm message: %@---------",message);
//顯示確認信息 UIAlertController *aletVc = [UIAlertController alertControllerWithTitle:@"comfirm" message:message preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *action = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]; [aletVc addAction:action]; [self presentViewController:aletVc animated:YES completion:nil]; completionHandler(YES); } // JavaScript調用Prompt方法後的回調的方法,Prompt是JavaScript的輸入框,須要在block中把用戶輸入的信息傳遞出去 - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler { NSLog(@"---------prompt message: %@---------",prompt);
//顯示輸入框信息 UIAlertController *aletVc = [UIAlertController alertControllerWithTitle:@"prompt" message:prompt preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *action = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]; [aletVc addAction:action]; [self presentViewController:aletVc animated:YES completion:nil]; completionHandler(prompt); }
6-4 測試打印信息
//啓動後 2019-11-16 17:29:52.885769+0800 Webkit[88133:2813082] 2-scheme:-------about----- 2019-11-16 17:29:52.901501+0800 Webkit[88133:2813082] 1---------當頁面加載啓動時調用--------- 2019-11-16 17:29:52.910799+0800 Webkit[88133:2813082] 4---------當內容到達主機時調用--------- 2019-11-16 17:29:52.913347+0800 Webkit[88133:2813082] 5---------當主頁加載完成時調用--------- 2019-11-16 17:29:52.916248+0800 Webkit[88133:2813082] ---------alert message: 我被成功調起來了--------- 2019-11-17 13:12:47.352925+0800 Webkit[1093:31197] message.body:-------{ list = ( 1, 2, 3 ); name = XYQ; qq = 1273843; }------ 2019-11-17 14:16:35.903852+0800 Webkit[1871:99459] message.body:-------hello js!------ //點擊第一個連接 2019-11-16 17:30:47.623126+0800 Webkit[88133:2813082] 2-scheme:-------http----- 2019-11-16 17:30:47.644042+0800 Webkit[88133:2813082] 1---------當頁面加載啓動時調用--------- 2019-11-16 17:30:47.754294+0800 Webkit[88133:2813082] 2-scheme:-------https----- 2019-11-16 17:30:47.757087+0800 Webkit[88133:2813082] 2---------當主機接收到的服務發生重定向時調用--------- 2019-11-16 17:30:47.853544+0800 Webkit[88133:2813082] 7---------驗證身份憑據時調用--------- 2019-11-16 17:30:47.949375+0800 Webkit[88133:2813082] 3-scheme:-------https----- 2019-11-16 17:30:47.990267+0800 Webkit[88133:2813082] 4---------當內容到達主機時調用--------- 2019-11-16 17:30:48.139897+0800 Webkit[88133:2813082] 7---------驗證身份憑據時調用--------- 2019-11-16 17:30:48.535383+0800 Webkit[88133:2813082] 7---------驗證身份憑據時調用--------- 2019-11-16 17:30:48.936130+0800 Webkit[88133:2813082] 7---------驗證身份憑據時調用--------- 2019-11-16 17:30:49.023373+0800 Webkit[88133:2813082] 5---------當主頁加載完成時調用--------- //點擊第二個連接 2019-11-16 17:31:31.248867+0800 Webkit[88152:2815204] 2-scheme:-------parent----- //點擊Confirm確認框 2019-11-16 17:32:09.871249+0800 Webkit[88152:2815204] ---------comfirm message: Press a button--------- //點擊Prompt輸入框 2019-11-16 17:32:35.748476+0800 Webkit[88164:2816717] ---------prompt message: Please enter your name---------