h5(WKWebView)和iOS之間的交互問題


       目前,大多數的應用中都嵌入了H5。那么在iOS應用中如何嵌入一個H5,並且和它進行交互就成了

一個勢必要掌握的技術了。本文我將結合我在項目中的一些需求整理出對應的技術點,僅供參考。

      在iOS開發中,H5的嵌入可以通過UIWebView或者WKWebView。這兩個都是繼承UIView,來加載web數據的類。

UIWebView是在iOS2的時候開始使用的。特點是加載速度慢,占用內存多,優化艱難。WKWebView是在iOS8蘋果

新推出的,加載速度快,占用內存較少,是一個不錯的選擇。如果想要比較兩者的區別,您可以選擇一個網頁進行

測試一下。鑒上所述,我們選擇WKWebView進行開發。

  • WKWebView的創建
- (void)createWebView{

       WKWebViewConfiguration
*config = [[WKWebViewConfiguration alloc] init];

      
// 根據需要去設置對應的屬性

       WKWebView
*webView = [[WKWebView alloc]initWithFrame:self.view.bounds configuration:config];

       webView.navigationDelegate
= self;

       [self.view addSubview:webView];

       NSURL
*url = [NSURL URLWithString:self.strURL];

       [self loadWebViewWithURL:url];
// JS調用OC 添加處理腳本

       [self.webView.configuration.userContentController addScriptMessageHandler:self name:
@"Share"];

    }

 

  • JS調用OC代碼
  [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"Share"];

 

  這是利用WKWebView的一個新特性MessageHandler來處理JS調用原生方法。要實現JS調用iOS原生方法,步驟見下。

  • 添加<WKScriptMessageHandler>協議。讓控制器成為MessageHandler的代理對象。

  • 對於監聽的方法名要和JS開發的人商量好。這里我們監聽的是Share方法,對於JS開發的人員必須要以以下方式寫。

 window.webkit.messageHandlers. Share.postMessage(null)
  • 實現協議方法。在這個方法里message參數有一個屬性body。message.body就是JS傳過來的參數,可以是字符串,可以是數組,也可以是字典。通過message.name判斷可以知道監聽的是JS的哪個方法。

 

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message

{

if ([message.name isEqualToString:@"Share"]) {

//TODO

}

}

    至此,JS調用OC代碼就已完結。是不是很簡單。另外,我在網上也看到了不一樣的處理方式。大家可以參考WebViewJavascriptBridge我覺得寫的比較清楚。

  • OC調用JS代碼

 

    [self.webView evaluateJavaScript:@"show()" completionHandler:^(id _Nullable response, NSError * _Nullable error) {

//TODO

}];

相信代碼已經看得很清楚啦。show()就是JS寫的方法,這個方法可傳可不傳參數,具體依實際情況而定。另外關於UIWebView和JS的交互,以下部分僅供參考。

    JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

context[
@"Share"] = ^() {

NSArray
*args = [JSContext currentArguments];

dispatch_async(dispatch_get_main_queue(),
^{

//TODO

});
  • 關於<WKNavigationDelegate>

     網頁加載開始,結束,失敗這幾個都特別簡單,我就不贅述了。說一下下面這個協議方法,這個方法發生在頁面跳轉中。WKNavigationActionPolicy是一個枚舉,

  WKNavigationActionPolicyAllow表示允許跳轉,WKNavigationActionPolicyCancel表示取消跳轉。對了,這里還有一個補充: scrollView嵌套網頁和原生view,原生view要根據網頁的高度來布局

我看到不少的電商應用都有這種布局,但在算高度上會有各種問題,不知道你們有遇見過?

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler

{

NSString
*url = navigationAction.request.URL.absoluteString;

if(![url isEqualToString:self.strURL]) {

// 頁面跳轉

}

decisionHandler(WKNavigationActionPolicyAllow);

}
  • 關於< WKUIDelegate >

   不知道您有沒有遇見過JS寫的alert()框在iOS上不彈出。那么您有沒有實現這些協議方法呢。

/// 創建一個新的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;

/// 確認框

- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;

/// 警告框

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;
  •  獲取網頁標題,網頁加載進度和加載狀態

     這是通過KVO的方式進行監聽的。您可以點擊進WKWebView的內部看一下,他們每個屬性上面都有很長的解釋,你不難發現這一段。舉一個獲取標題的例子。

  其他的類似。別忘了,KVO監聽在dealloc中移除監聽者哦。

    [self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context

{

if ([keyPath isEqualToString:@"title"]) {

if (object == self.webView) {

if(self.navigationController)

self.navigationItem.title
= self.webView.title;

}

}

else {

[super observeValueForKeyPath:keyPath ofObject:
object change:change context:context];

}

}

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com