1. 程式人生 > >iOS常用方法——WKWebView與h5互動的實現

iOS常用方法——WKWebView與h5互動的實現

隨著前端開發的強大,原生與h5的互動用的也越來越多。
為什麼選用WKWebView,我們可以做一個對比,同一個web頁面,用UIWebView載入和用WKWebView來載入,記憶體佔用情況很容易看出來,回到原生頁面之後,UIWebView對應的記憶體也不會降下來。從效能而言,個人覺得能用WKWebView就不要用UIWebView。
UIWebView與h5的互動方式和WKWebView與h5的互動方式不太一樣,對h5那邊的實現方式要求也不一樣。下面給一個WKWebView與h5實現互動的主要程式碼。

  • 需要的成員變數的初始化:
//初始化webView
-(WKWebView *)webView{
    if
(!_webView) { _webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - self.mNavigationbarHeight) configuration:self.configuration]; _webView.navigationDelegate = self; _webView.UIDelegate = self; } return _webView; } //初始化配置 -(WKWebViewConfiguration *)configuration{ if
(!_configuration) { _configuration = [[WKWebViewConfiguration alloc] init]; WKPreferences *preferences = [WKPreferences new]; preferences.javaScriptCanOpenWindowsAutomatically = YES; _configuration.preferences = preferences; _configuration.userContentController = self
.userContentController; } return _configuration; } -(WKUserContentController *)userContentController{ if (!_userContentController) { _userContentController = [[WKUserContentController alloc] init]; //互動關鍵程式碼 [_userContentController addScriptMessageHandler:self name:@"webViewApp"]; } return _userContentController; }
  • WKWebView相關代理及互動的實現
#pragma mark - WKUIDelegate
// 在JS端呼叫alert函式時,會觸發此代理方法。
// JS端呼叫alert時所傳的資料可以通過message拿到
// 在原生得到結果後,需要回調JS,是通過completionHandler回撥
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    NSLog(@"%s", __FUNCTION__);
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
    }]];

    [self presentViewController:alert animated:YES completion:NULL];
    NSLog(@"%@", message);
}

// JS端呼叫confirm函式時,會觸發此方法
// 通過message可以拿到JS端所傳的資料
// 在iOS端顯示原生alert得到YES/NO後
// 通過completionHandler回撥給JS端
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
    NSLog(@"%s", __FUNCTION__);

    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:message 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);
}

// JS端呼叫prompt函式時,會觸發此方法
// 要求輸入一段文字
// 在原生輸入得到文字內容後,通過completionHandler回撥給JS
- (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:@"請輸入" message:@"JS呼叫輸入框" 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];
}
#pragma mark - WKNavigationDelegate
-(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
    //頁面開始載入

}

-(void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{
    //內容開始到達時
}

-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
    //頁面載入完成

}

-(void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error{
    //頁面載入失敗

}

-(void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{
    //收到伺服器重定向請求後呼叫
}

-(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
    // 在請求開始載入之前呼叫,決定是否跳轉
    decisionHandler(WKNavigationActionPolicyAllow);
}

-(void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
    // 在收到響應開始載入後,決定是否跳轉
    decisionHandler(WKNavigationResponsePolicyAllow);
}

#pragma mark - WKScriptMessageHandler
//實現互動的代理
-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
    //message.body為h5向原生互動時所傳的引數,這個為客戶端與h5端協商,端需要什麼就讓h5端給什麼
    NSDictionary * messageDic = message.body;
    //以下為協商後處理的一個例項,根據方法名判斷原生需要做什麼處理
    if ([messageDic[@"method"] isEqualToString:@"h5share"]) {
        //調起原生分享頁面
        [BZJSInteractiveManager h5shareInteractive:messageDic];
    }else if ([messageDic[@"method"] isEqualToString:@"mall_wxpay"]){
        //微信支付
        [BZJSInteractiveManager h5WeiXinPayInteractive:messageDic[@"result"][@"payuri"]];
    }else if ([messageDic[@"method"] isEqualToString:@"h5tologin"]){
        //token失效
        [BZJSInteractiveManager h5ToLogin];
    }
}

需要注意的一點是WKUIDelegate需要按上面的程式碼處理,否則h5中的一些彈框無法彈出。
如果專案中用到的web比較多,可以寫一個基類,基類中基本可以實現大部分功能,互動的處理也可以在基類中統一分發處理,這樣的話互動不必在意是哪個介面,只要確定互動方法,在任何頁面有互動都可以實現。
h5實現互動程式碼示例:

  • 按鈕:
<p align="center"> <input type="button" value="測試WKWebView中..." onClick="functest1()"></p>
  • 點選方法:
function functest1(){
    var message = {
    'method' : 'hello',
    'param1' : 'liuyanwei',
    };
    //這句為關鍵程式碼,沒有這句,客戶端無法再代理方法中獲取到該點選事件
    window.webkit.messageHandlers.webViewApp.postMessage(message);
}