iOS 中UIWebView與WKWebView

猿來是你_發表於2019-04-26

1. UIWebView

UIWebView 適用於iOS8.0以下的系統版本 iOS原生沒有提供js直接呼叫OC的方式,只能通過UIWebView的UIWebViewDelegate協議方法來做攔截,並在這個方法中,根據url來呼叫OC方法;

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
複製程式碼
  • UIWebViewDelegate代理協議使用:
// 是否允許載入網頁,也可獲取js要開啟的url,通過擷取此url可與js互動
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    NSString *urlString = [[request URL] absoluteString];
    urlString = [urlString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    
    NSArray *urlComps = [urlString componentsSeparatedByString:@"://"];
    NSLog(@"urlString=%@---urlComps=%@",urlString,urlComps);
    return YES;
}
// 開始載入網頁
- (void)webViewDidStartLoad:(UIWebView *)webView {
    NSURLRequest *request = webView.request;
    NSLog(@"webViewDidStartLoad-url=%@--%@",[request URL],[request HTTPBody]);
}
// 網頁載入完成
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    NSURLRequest *request = webView.request;
    NSURL *url = [request URL];
    if ([url.path isEqualToString:@"/normal.html"]) {
        NSLog(@"isEqualToString");
    }
    NSLog(@"webViewDidFinishLoad-url=%@--%@",[request URL],[request HTTPBody]);
    NSLog(@"%@",[self.webView stringByEvaluatingJavaScriptFromString:@"document.title"]);
}
// 網頁載入錯誤
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
    NSURLRequest *request = webView.request;
    NSLog(@"didFailLoadWithError-url=%@--%@",[request URL],[request HTTPBody]);
}
複製程式碼

2. WKWebView

  • 引入WebKit庫 #import <WebKit/WebKit.h>
  • 在文件中可以看出,WKWebView的初始化方法有兩種:
- (instancetype)initWithFrame:(CGRect)frame
- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration
複製程式碼

我們大多使用第一種方式,這也是文件中預設的一種方式。

  • WKWebView 代理 協議方法如下:
//頁面開始載入時呼叫
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation
{
    NSLog(@"頁面開始載入時呼叫。   2");
}
//內容返回時呼叫,得到請求內容時呼叫(內容開始載入) -> view的過渡動畫可在此方法中載入
- (void)webView:(WKWebView *)webView didCommitNavigation:( WKNavigation *)navigation
{
    NSLog(@"內容返回時呼叫,得到請求內容時呼叫。 4");
}
//頁面載入完成時呼叫
- (void)webView:(WKWebView *)webView didFinishNavigation:( WKNavigation *)navigation
{
    NSLog(@"頁面載入完成時呼叫。 5");
}
//請求失敗時呼叫
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
{
    NSLog(@"error1:%@",error);
}
-(void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error
{
    NSLog(@"error2:%@",error);
}
//在請求傳送之前,決定是否跳轉 -> 該方法如果不實現,系統預設跳轉。如果實現該方法,則需要設定允許跳轉,不設定則報錯。
//該方法執行在載入介面之前
//Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Completion handler passed to -[ViewController webView:decidePolicyForNavigationAction:decisionHandler:] was not called'
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    //允許跳轉
    decisionHandler(WKNavigationActionPolicyAllow);
    
    //不允許跳轉
//    decisionHandler(WKNavigationActionPolicyCancel);
    NSLog(@"在請求傳送之前,決定是否跳轉。  1");
}
//在收到響應後,決定是否跳轉(同上)
//該方法執行在內容返回之前
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
{
    //允許跳轉
    decisionHandler(WKNavigationResponsePolicyAllow);
    //不允許跳轉
//    decisionHandler(WKNavigationResponsePolicyCancel);
    NSLog(@"在收到響應後,決定是否跳轉。 3");
    
}
//接收到伺服器跳轉請求之後呼叫
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation
{
    NSLog(@"接收到伺服器跳轉請求之後呼叫");
}
-(void)webViewWebContentProcessDidTerminate:(WKWebView *)webView
{
    NSLog(@"webViewWebContentProcessDidTerminate");
}
複製程式碼

3. OC呼叫JS傳遞引數

  • UIWebView方法
NSString *str = [self.webview stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"postStr('%@','%@');",str1,str2]];
複製程式碼
  • WKWebView方法
[self.wkWebView evaluateJavaScript:[NSString stringWithFormat:@"postStr('%@')", @"true"] completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        NSLog(@"==%@----%@", result, error);
    }];
複製程式碼

在需要接受引數值的js介面實現如下方法:

function postStr(str1, str2){
    alert(str1, str2);    //接收到的值”;
    //...code
}
複製程式碼

4. JS呼叫OC傳遞引數

js是不能執行oc程式碼的,但是可以變相的執行,js可以將要執行的操作封裝到網路請求裡面,然後oc攔截這個請求,獲取url裡面的字串解析即可。(攔截URL) 比如darkangel://。方法是在html或者js中,點選某個按鈕觸發事件時,跳轉到自定義URL Scheme構成的連結,而OC中捕獲該連結,從中解析必要的引數,實現JS到OC的一次互動。比如頁面中一個a標籤,連結如下: <a href="darkangel: smslogin?username="12323123&code=892845"">簡訊驗證登入</a href="darkangel:> 在該方法中,捕獲該連結,並且返回NO(阻止本次跳轉),從而執行對應的OC方法。

  • UIWebView方法
/*
 * 方法的返回值是BOOL值。
 * 返回YES:表示讓瀏覽器執行預設操作,比如某個a連結跳轉
 * 返回NO:表示不執行瀏覽器的預設操作,這裡因為通過url協議來判斷js執行native的操作,肯定不是瀏覽器預設操作,故返回NO
 */
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
    //標準的URL包含scheme、host、port、path、query、fragment等
    NSURL *URL = request.URL;    
    if ([URL.scheme isEqualToString:@"darkangel"]) {
        if ([URL.host isEqualToString:@"smsLogin"]) {
            NSLog(@"簡訊驗證碼登入,引數為 %@", URL.query);
            return NO;
        }
    }
    return YES;
}
複製程式碼
  • WKWebView方法
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    //可以通過navigationAction.navigationType獲取跳轉型別,如新連結、後退等
    NSURL *URL = navigationAction.request.URL;
    //判斷URL是否符合自定義的URL Scheme
    if ([URL.scheme isEqualToString:@"darkangel"]) {
        //根據不同的業務,來執行對應的操作,且獲取引數
        if ([URL.host isEqualToString:@"smsLogin"]) {
            NSString *param = URL.query;
            NSLog(@"簡訊驗證碼登入, 引數為%@", param);
            //不允許跳轉
            decisionHandler(WKNavigationActionPolicyCancel);
            return;
        }
    }
    //允許跳轉
    decisionHandler(WKNavigationActionPolicyAllow);
    NSLog(@"%@", NSStringFromSelector(_cmd));
}
複製程式碼

附:我的部落格地址

相關文章