Hybrid App: 對比UIWebView和WebKit實現JavaScript與Native交互

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>
View Code

[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>
View Code
//加載資源
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---------

 

相關文章
相關標籤/搜索