WKWebView替換WebView體會總結(jié)

一 先來看下UIWebView 基本用法 以及與JS交互過程

  1. 舉例:簡單的使用
//1.創(chuàng)建webview,并設(shè)置大小
_webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
 //2.創(chuàng)建請求
NSURL *url = [NSURL URLWithString:self.urlString];
NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30];
//3.加載網(wǎng)頁 將webView添加到界面
[_webView loadRequest:urlRequest];
[self.view addSubview:_webView]; 
  1. 一些實用函數(shù)
- (void)loadRequest:(NSURLRequest *)request;
- (void)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
- (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)textEncodingName baseURL:(NSURL *)baseURL;
  1. 網(wǎng)頁導(dǎo)航刷新有關(guān)函數(shù)
// 刷新
- (void)reload;
//停止加載
- (void)stopLoading;
//后退函數(shù)
- (void)goBack;
//前進函數(shù)
- (void)goForward;
//是否可以后退
@property (nonatomic,readonly, getter=canGoBack)BOOL canGoBack;
//是否可以向前
@property (nonatomic,readonly, getter=canGoForward)BOOL canGoForward;
//是否正在加載
@property (nonatomic,readonly, getter=isLoading)BOOL loading;
  1. 代理協(xié)議使用:UIWebViewDelegate
#pragma mark - UIWebViewDelegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
    // 攔截scheme為aaa時,是javascript要調(diào)用native代碼
    if ([[request.URL scheme] isEqualToString:@"aaa"]) {
        // Host
        NSString *host = [[request.URL host] trimBothEnd];
        // 取得參數(shù)
        NSDictionary *parameters = [request.URL.absoluteString urlQueryToDictionary];
        [self handleLinkTapWithUrl:request.URL.absoluteString withHost:host withParams:parameters];
    }
    return YES;
}

- (void)handleLinkTapWithUrl:(NSString *)url withHost:(NSString *)host withParams:(NSDictionary *)param{
    if(host && [[self getHostDictionary] objectForKey:host]){
        [self pushScheme:url];
    }
}

- (void)webViewDidFinishLoad:(UIWebView*)webView {
    
    // 在最后執(zhí)行一次,以保證標題正確設(shè)置,loading被正確隱藏
    self.title = [_webView stringByEvaluatingJavaScriptFromString:@"document.title"];
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
    [self hideLoading];
    [self registerJSContextFunction];
}

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
    [self hideLoading];
    if ([error code] != NSURLErrorCancelled){
        [self showWarning:@"加載失敗,請重試"];
    }
}
  1. 與js交互
1 在viewDidLoad 中 初始化 給JS注冊方法
 // 初始化以做后來交互使用
    _jsContext = [_webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    //在js自己刷新頁面,不通過本地刷新的時候,需要重新綁定clint,寫成成員變量,避免多次實例化。
    _client = [ClientH5Object new];
    _client.delegate = self;
    
    // 給JS注冊方法
    [self registerJSContextFunction];
2 注冊方法
#pragma mark - JSContext
- (void)registerJSContextFunction {
    
    __weak __typeof(self)weakSelf = self;
    _jsContext[@"jsObjLoadDomFinished"] = ^() {
        dispatch_async(dispatch_get_main_queue(), ^{
            [weakSelf loadDomFinished];
        });
        
    };
    
    _jsContext[@"jsObjPageDataLoaded"] = ^() {
        dispatch_async(dispatch_get_main_queue(), ^{
            [weakSelf globalObjectLoaded];
        });
        
    };
    
    // 使用這種方式可以避免循環(huán)引用。
    // 注意:不能把self賦給_jsContext,即使是weakSelf也不行
    _jsContext[@"client"] = _Client;


    for (NSString *key in _jsCallers) {
        _jsContext[@"client"][key] = _jsCallers[key];
    }
}

- (void)addJSCall:(NSString *)jsFuncName implemention:(id)block {
    _jsCallers[jsFuncName] = block;
}

/**
 *  @brief  js調(diào)用該方法以hideLoading
 */
- (void)loadDomFinished{
    
    [self hideLoading];
    
    // 因為此時_jsGlobalObject還不能從H5中獲取,所以只先設(shè)置一個title,與數(shù)據(jù)相關(guān)的分享功能先不展示
    self.title = [_webView stringByEvaluatingJavaScriptFromString:@"document.title"];
}


- (void)globalObjectLoaded{
    
    // 從H5中取得全局變量
    @try {
        _jsGlobalObject = [[self.jsContext evaluateScript:@"window.GLOBAL.pagedata"] toDictionary];
    } @catch (NSException *exception) {                                                                                   
    }
    if (_jsGlobalObject == nil) {
        return;
    }

    //分享數(shù)據(jù)源
    _shareObject = [[WMShareObject alloc]initWithDictionary:_jsGlobalObject[@"share_data"] error:nil];

    //同時不為空的時候才顯示微信快照和朋友圈快照
    _isShowScreenshot = [_shareObject.wechatScreenshot.content isNonEmpty] && [_shareObject.wechatScreenshot.content isNonEmpty];
    if (![_jsGlobalObject[@"hide_share"] boolValue] && (_shareObject != nil)) {
        [self setNavigateTitle:[_webView stringByEvaluatingJavaScriptFromString:@"document.title"] rightButtonOption:OCBarButtonImageTypeShare];
    }
}

二 WKWebView使用說明

1 簡單使用

    與UIWebview一樣,僅需三步:記住導(dǎo)入
    // 1.創(chuàng)建webview,并設(shè)置大小
    WKWebView *webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
    // 2.創(chuàng)建請求
    NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.cnblogs.com/mddblog/"]];
    // 3.加載網(wǎng)頁
    [webView loadRequest:request];
    
    //最后將webView添加到界面
    [self.view addSubview:webView];

2 一些實用函數(shù)

//加載網(wǎng)頁函數(shù)
//相比UIWebview,WKWebView也支持各種文件格式,并新增了loadFileURL函數(shù),顧名思義加載本地文件。
///模擬器調(diào)試加載mac本地文件
- (void)loadLocalFile {
    // 1.創(chuàng)建webview,并設(shè)置大小,"20"為狀態(tài)欄高度
    WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0,20, self.view.frame.size.width,self.view.frame.size.height -20)];
    // 2.創(chuàng)建url  userName:電腦用戶名
    NSURL *url = [NSURL fileURLWithPath:@"/Users/userName/Desktop/bigIcon.png"];
    // 3.加載文件
    [webView loadFileURL:url allowingReadAccessToURL:url];
    //最后將webView添加到界面
    [self.view addSubview:webView];
}

/// 其它三個加載函數(shù)
- (WKNavigation *)loadRequest:(NSURLRequest *)request;
- (WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
- (WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL;


網(wǎng)頁導(dǎo)航刷新相關(guān)函數(shù)
    和UIWebview幾乎一樣,不同的是有返回值,WKNavigation(已更新),另外增加了函數(shù)reloadFromOrigin和goToBackForwardListItem。
reloadFromOrigin會比較網(wǎng)絡(luò)數(shù)據(jù)是否有變化,沒有變化則使用緩存,否則從新請求。
goToBackForwardListItem:比向前向后更強大,可以跳轉(zhuǎn)到某個指定歷史頁面
@property (nonatomic,readonly) BOOL canGoBack;
@property (nonatomic,readonly) BOOL canGoForward;
- (WKNavigation *)goBack;
- (WKNavigation *)goForward;
- (WKNavigation *)reload;
- (WKNavigation *)reloadFromOrigin; //增加的函數(shù)
- (WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item;// 增加的函數(shù)
- (void)stopLoading;

一些常用屬性
allowsBackForwardNavigationGestures:BOOL類型,是否允許左右劃手勢導(dǎo)航,默認不允許
estimatedProgress:加載進度,取值范圍0~1
title:頁面title
.scrollView.scrollEnabled:是否允許上下滾動,默認允許
backForwardList:WKBackForwardList類型,訪問歷史列表,可以通過前進后退按鈕訪問,或者通過goToBackForwardListItem函數(shù)跳到指定頁面

3 代理協(xié)議使用

一共有三個代理協(xié)議:
WKNavigationDelegate:最常用,和UIWebViewDelegate功能類似,追蹤加載過程,有是否允許加載、開始加載、加載完成、加載失敗。下面會對函數(shù)做簡單的說明,并用數(shù)字標出調(diào)用的先后次序:1-2-3-4-5

三個是否允許跳轉(zhuǎn)加載的函數(shù):
/// 接收到服務(wù)器跳轉(zhuǎn)請求之后調(diào)用 (服務(wù)器端redirect),不一定調(diào)用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;
/// 3 在收到服務(wù)器的響應(yīng)頭,根據(jù)response相關(guān)信息,決定是否跳轉(zhuǎn)。decisionHandler必須調(diào)用,來決定是否跳轉(zhuǎn),參數(shù)WKNavigationActionPolicyCancel取消跳轉(zhuǎn),WKNavigationActionPolicyAllow允許跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
/// 1 在發(fā)送請求之前,決定是否跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;

追蹤加載過程函數(shù):
/// 2 頁面開始加載
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;
/// 4 開始獲取到網(wǎng)頁內(nèi)容時返回
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;
/// 5 頁面加載完成之后調(diào)用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;
/// 頁面加載失敗時調(diào)用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;

WKScriptMessageHandler:必須實現(xiàn)的函數(shù),是APP與js交互,提供從網(wǎng)頁中收消息的回調(diào)方法
/// message: 收到的腳本信息.
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;


WKUIDelegate:UI界面相關(guān),原生控件支持,三種提示框:輸入、確認、警告。首先將web提示框攔截然后再做處理。
/// 創(chuàng)建一個新的WebView
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;
/// 輸入框
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *__nullable result))completionHandler {
    NSLog(@"%s",__FUNCTION__);
    
    NSLog(@"%@", prompt);
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"textinput" message:@"JS調(diào)用輸入框" preferredStyle:UIAlertControllerStyleAlert];
    [alert addTextFieldWithConfigurationHandler:^(UITextField *_Nonnull textField) {
        textField.textColor = [UIColor redColor];
    }];
    
    [alert addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler([[alert.textFields lastObject] text]);
    }]];
    
    [self presentViewController:alert animated:YES completion:NULL];
}
/// 確認框
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
    NSLog(@"%s", __FUNCTION__);
    
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"confirm" message:@"JS調(diào)用confirm"preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(YES);
    }]];
    [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(NO);
    }]];
    [self presentViewController:alert animated:YES completion:NULL];
    
    NSLog(@"%@", message);
}
/// 警告框
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    NSLog(@"%s", __FUNCTION__);
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"alert"message:@"JS調(diào)用alert" preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"確定"style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
    }]];
    
    [self presentViewController:alert animated:YES completion:NULL];
    NSLog(@"%@", message);
}

4 與js交互

/// 5 頁面加載完成之后調(diào)用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;
{
    
    // 直接調(diào)用js
    [self.webViewevaluateJavaScript:@"document.documentElement.style.webkitUserSelect='none';"completionHandler:nil];
    // 調(diào)用js參數(shù)
    [self.webViewevaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none';"completionHandler:nil];
    [self.showViewremoveFromSuperview];
    NSString *jsToGetHTMLSource =@"document.getElementsByTagName('html')[0].innerHTML";
    [self.activityViewstopAnimating];
    // 調(diào)用js獲取返回值
    [self.webViewevaluateJavaScript:jsToGetHTMLSourcecompletionHandler:^(id_Nullable HTMLSource, NSError * _Nullable error) {
        NSRange range = [HTMLSourcerangeOfString:@"Bad Gateway"];//判斷字符串是否包含
        bool urlIsTrue = (range.location ==NSNotFound);
        if (urlIsTrue ==true ) {
            range = [HTMLSource rangeOfString:@"Network is unreachable"];
            urlIsTrue = (range.location ==NSNotFound);
        }
        
        if (urlIsTrue ==true ) {
            range = [HTMLSource rangeOfString:@"頁面不存在"];
            urlIsTrue = (range.location ==NSNotFound);
        }
        if (urlIsTrue ==true) {
            range = [HTMLSource rangeOfString:@"網(wǎng)頁無法訪問"];
            urlIsTrue = (range.location ==NSNotFound);
        }
        if (urlIsTrue ==true) {
            range = [HTMLSource rangeOfString:@"Not Found"];
            urlIsTrue = (range.location ==NSNotFound);
        }
        //網(wǎng)頁可訪問隱藏我們自己的返回按鈕
        if (urlIsTrue==true)
        {
            self.topView.hidden =YES;
        }
        else
        {
            [webView stopLoading];
            [selfaddShowView];
        }
    }];
    [webView stopLoading];

}
如果想在加載的頁面中繼續(xù)操作 
UIWebView打開一個頁面之后,點擊里面的內(nèi)容就直接能跳轉(zhuǎn)。而WKWebView一開始點里面的東西沒反應(yīng),只要加了這個方法就好了。
//在發(fā)送請求之前,決定是否跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    if (navigationAction.targetFrame ==nil) {
        [webView loadRequest:navigationAction.request];
    }
   // 沒有這一句頁面就不會顯示
    decisionHandler(WKNavigationActionPolicyAllow); 
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容