WKWebView和JS交互

WKWebView和JS的那些事

最近公司需要將 某網站注入JS,從而實現對其中一些視頻添加下載按鈕的功能。當然我對JS不太懂,JS是由我們Web前端寫的,我要實現的就是打開網站的時候注入JS,並根據裏面點擊按鈕的操作作出響應,JS會給我傳一些參數。這裏記錄下我做的事情,給需要的朋友看下。
(本程序媛目前找工作中,有合適的可以推薦下。😂)
在這裏插入圖片描述
之後我們會用 http://www.test.com 代替你要注入的網站網址。之後自己寫的代碼做個替換就好。

注入JS (OC調用JS)

最重要的第一步,就是將JS注入。

  - (WKWebView *)myWebView {
      if (!_myWebView) {
          WKWebViewConfiguration *theConfiguration = [[WKWebViewConfiguration alloc] init];
          
          theConfiguration.userContentController = [[WKUserContentController alloc] init];
          [theConfiguration.userContentController addScriptMessageHandler:self name:@"downloader"];
          [theConfiguration.userContentController addScriptMessageHandler:self name:@"console"];
          if(IOSVersion >= 10.0){
              theConfiguration.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
          }
          
          theConfiguration.allowsPictureInPictureMediaPlayback = YES;
          theConfiguration.preferences.javaScriptEnabled = YES;

          theConfiguration.allowsInlineMediaPlayback = YES;

          _myWebView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:theConfiguration];
          _myWebView.contentScaleFactor = 3;
          _myWebView.backgroundColor = [UIColor whiteColor];
          _myWebView.opaque = NO;
          if (@available(iOS 11.0, *)) {
             _myWebView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
          }

          _myWebView.scrollView.bounces = YES;
          
          _myWebView.navigationDelegate = self;
          _myWebView.UIDelegate = self;
     }
      return _myWebView;
  }

以上代碼稍後講到,先講下注入時機,目前我們的是頁面加載成功後一次性注入,在WKWebView加載完成後注入。你也可以每次URL變化都注入一次。

  - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
    if ([urlstring isEqualToString:@"http://www.test.com"]) {
          [self injectConsoleJS];
      }
  }

  - (void)injectConsoleJS{
      NSString * js = [NSString stringWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"javascript-ios" withExtension:@"js"] encoding:NSUTF8StringEncoding error:nil] ;
      if (js) {
          [self.myWebView evaluateJavaScript:js completionHandler:^(id _Nullable data, NSError * _Nullable error) {
              SLLog(@"");
          }];
      }
  }

至於JS在OC代碼中存在的形式,如果比較少的JS,你可以直接把JS直接賦給一個字符串,但是要注意雙引號要用\做反義,最好對JS坐下壓縮後再這麼做,我是直接從包文件中讀取。當然你也可以搞個服務器接口下發JS代碼,這樣就不用每次更改JS都要打包重新提交審覈。

JS調用OC

調用方式,你可以攔截URL從而調用你的原生方法,還可以用WKWebView的新特性MessageHandler來調用原生方法。

所謂JS調用OC,就是OC對JS那邊的操作作出反饋。比如點擊按鈕事件,JS會告訴你用戶點擊了按鈕,趕快作出響應吧。當然他會告訴你對應的參數,也可以不傳參。

JS中要用的方法:

window.webkit.messageHandlers.<name>.postMessage(<messageBody>)
支持的格式:Allowed types are NSNumber, NSString, NSDate, NSArray, NSDictionary, and NSNull.

首先我們JS代碼中要在需要調用OC的位置加上如下代碼:(我這裏傳的是一個字典)

window.webkit.messageHandlers.downloader.postMessage({"link":link, "code":code})

解釋一下,上面是和安卓JS不太一樣的地方,這個很重要的地方:
上面我們創建WKWebView的時候,有一句代碼如下:

[theConfiguration.userContentController addScriptMessageHandler:self name:@"downloader"];

有了這句,我們就實現了對JS消息的監聽了。如果JS需要調用原生方法,就會通過以下方法監聽到。

(當然我們需要我們controller實現協議)

  #pragma mark WKScriptMessageHandler

  - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
      if ([message.name isEqualToString:@"downloader"]) {
          NSDictionary *dic = message.body;
          if (dic) {
              NSString *videoURL = dic[@"link"];
              NSString *code = dic[@"code"];
              /*
              有了參數,調用你的原生方法。
			 */
          }
      }else {
      }
  }

頁面消失之前記得移除這個監聽。不然強引用self就會無法釋放。內存泄漏的。😄

[self.myWebView.configuration.userContentController removeScriptMessageHandlerForName:@"downloader"];

至此,JS調用原生的過程結束。

小問題

最後說一個WKWebView的一個小問題。WKWebView 對於打開target="_blank"的頁面 不支持的,怎麼辦呢。😭,當時我被這個問題折騰的夠嗆,爲什麼點擊html裏的一個頁面圖片沒反應呢,原來是WKWebView根本不處理,我們要自己處理,幫助他完成,或者乾脆你用原生的打開一個新的頁面也行。
首先要實現協議UIDelegate,主要用到這個回調方法。

/*! @abstract Creates a new web view.
 @param webView The web view invoking the delegate method.
 @param configuration The configuration to use when creating the new web
 view. This configuration is a copy of webView.configuration.
 @param navigationAction The navigation action causing the new web view to
 be created.
 @param windowFeatures Window features requested by the webpage.
 @result A new web view or nil.
 @discussion The web view returned must be created with the specified configuration. WebKit will load the request in the returned web view.

 If you do not implement this method, the web view will cancel the navigation.
 */
- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
  if (!navigationAction.targetFrame.isMainFrame) {
      NSURL * url = navigationAction.request.URL;
	  [webView loadRequest:navigationAction.request];
	  /*
	  或者原生的打開新的Controller界面
	  */
  }
  return nil;
 }

在這裏插入圖片描述

發佈了11 篇原創文章 · 獲贊 3 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章