IOS: WKWebView は JS と対話します

序文

モバイル インターネットの急速な発展に伴い、Web 開発とネイティブ アプリケーション開発の境界は徐々に曖昧になってきています。一方で、Web テクノロジーは常に進歩しており、オフライン ストレージやデバイス API アクセスなど、以前はネイティブ アプリケーションでしか実現できなかった多くの機能が Web テクノロジーを通じて実現できるようになりました。一方で、ネイティブアプリケーション開発においても、開発効率の向上やクロスプラットフォーム対応を実現するためにWeb技術の導入が始まっています。Web 開発とネイティブ開発を組み合わせるこの傾向は、モバイル アプリケーション開発に新たな可能性をもたらしました。

UIWebView と WKWebView の切り替え

元々、iOS プラットフォームに Web ページを読み込む方法は UIWebView を使用することでした。しかし、iOS プラットフォーム技術の発展に伴い、UIWebView の限界が徐々に現れてきました。まず、UIWebView のパフォーマンスの問題が顕著で、Web ページを読み込むときに大量のメモリと CPU リソースを消費するため、アプリケーションの効率が低くなります。次に、UIWebView は複数の Web ページの同時読み込みをサポートしていないため、マルチタスクのシナリオでは無力であると思われます。最後に、UIWebView の API 設計は比較的古く、新しい Web テクノロジ標準をサポートしていません。

これらの問題を解決するために、Apple は iOS 8 に新しいコンポーネントである WKWebView を導入しました。これは UIWebView を置き換えるために使用されます。WKWebView は、JavaScript の実行効率を大幅に向上させる効率的なエンジンである Nitro JavaScript エンジンを設計に使用しています。同時に、WKWebView は複数の Web ページの同時読み込みもサポートし、最新の Web テクノロジー標準を採用しているため、開発者は最新の Web テクノロジーを使用できます。

WKWebView と JavaScript 間の対話の原理

WKWebView と JavaScript の間の対話は、基本的に 2 つの方向に分けることができます。1 つは JavaScript が Swift コードを呼び出す方向で、もう 1 つは Swift コードが JavaScript コードを呼び出す方向です。

WKScriptMessageHandlerJavaScript が Swift コードを呼び出す場合、WKWebView はプロトコルを提供し、開発者はプロトコルのメソッドを実装することでuserContentController(_:didReceive:)、メソッドを通じて JavaScript コードpostMessageによって送信されたメッセージを受信できます。

JavaScript コードを呼び出す Swift コードの場合、WKWebView は、evaluateJavaScript(_:completionHandler:)開発者が JavaScript コードを実行し、completionHandler を通じて実行結果を取得できるメソッドを提供します。

次に、WKWebView を使用して JavaScript と対話する例を使用します。

1. WKWebView の作成と構成

ViewControllerまず、Swift プロジェクトを作成し、 WKWebView の使用をサポートするためにデフォルトのビルドに WebKit モジュールをインポートする必要があります。

import WebKit

ViewController に WKNavigationDelegate プロトコルと WKScriptMessageHandler プロトコルを実装させます。WKNavigationDelegate プロトコルは Web ページ ナビゲーション イベントの処理に使用され、WKScriptMessageHandler プロトコルは JavaScript によって送信されたメッセージの受信に使用されます。また、WKWebView 型の変数 webView を宣言します。

class ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler { 
     var webView: WKWebView!;
     ...
}

このメソッドではloadView、まずWKUserContentControllerインスタンスを作成し、add(self, name: "nativeCallback")メソッドを通じて「nativeCallback」というメッセージ ハンドラーを追加します。次に、WKWebViewConfigurationインスタンスを作成し、userContentControllerそのプロパティを作成したばかりのコンテンツ コントローラーに設定します。最後に、この構成オブジェクトを使用して WKWebView のインスタンスを作成し、それをビュー コントローラーの view プロパティに割り当てます。

override func loadView() {
    let contentController = WKUserContentController();
    contentController.add(self, name: "nativeCallback")
    
    let config = WKWebViewConfiguration();
    config.userContentController = contentController;
    webView = WKWebView(frame: .zero, configuration: config);
    webView.navigationDelegate = self;
    view = webView;
}

Interface Builder でビューのレイアウトを定義するために Storyboard または Xib ファイルが使用されていないことに注意してくださいloadView。このメソッドでは、UIView (またはそのサブクラス) のインスタンスを作成してビューに割り当てる必要があります。コントローラーのview属性。

viewDidLoad方法中,我们创建了一个URL请求,并通过webView.load(myRequest)方法加载这个请求,用于加载本地服务器上的index.html文件

override func viewDidLoad() {
    super.viewDidLoad()
    let myURL = URL(string: "http://127.0.0.1:8080")
    let myRequest = URLRequest(url: myURL!)
    webView.load(myRequest)
}

2. 处理JavaScript调用

userContentController(_:didReceive:)方法中,我们处理了JavaScript代码发送的消息。当JavaScript代码通过window.webkit.messageHandlers.nativeCallback.postMessage(message)调用"nativeCallback"的message handler时,这个方法就会被调用。我们在这个方法中检查消息的内容,并显示一个alert对话框。

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    if message.name == "nativeCallback" {
        if let msg = message.body as? String {
            showAlert(message: msg)
        }
    }
}

func showAlert(message: String) {
    let alertController = UIAlertController(title: "提示", message: message, preferredStyle: .alert)
    let okAction = UIAlertAction(title: "确定", style: .default, handler: nil)
    alertController.addAction(okAction)
    present(alertController, animated: true, completion: nil)
}

3. 调用JavaScript方法

在WKNavigationDelegate的webView(_:didFinish:)方法中,我们调用了JavaScript的displayDate()方法来显示当前的日期。

swiftCopy code
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    webView.evaluateJavaScript("displayDate()") { (any, error) in
        if (error != nil) {
            print(error ?? "err")
        }
    }
}

上述代码中在WKWebView加载完index.html页面后,swift会调用index.html的js方法displayDate()方法来显示当前的日期。

4. Web页面

在index.html页面中,我们定义了两个JavaScript函数:displayDate()nativeCallback()displayDate()函数会将当前的日期显示在id为"date"的p元素中。nativeCallback()函数会通过webkit.messageHandlers.nativeCallback.postMessage('js调用ios')发送一个消息到原生应用。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
    <title>wkwebview</title>
    <style type="text/css">
    	h1 {
	    	color: red;
	    	font-size: 1em;
		}
		body {
		    font-size: 2em;
		}
		button {
		    font-size: 0.5em;
		}
		p {
			font-size: 0.5em
		}
		#tip {
			color: blue;
		}
    </style>
</head>
<body>
    <h1>WKWebview和JS交互</h1>
    
    <div>
    	<p id="tip">ios调用js显示日期:</p>	
    	<p id="date">这是一个段落</p>	
    </div>
    <button type="button" onclick="nativeCallback()">js调用ios</button>
    <script type="text/javascript">
        function displayDate(){
            document.getElementById("date").innerHTML=Date();
        }

        function nativeCallback() {    
            try {
              //使用此方法,会报错,因此使用try-catch
              webkit.messageHandlers.nativeCallback.postMessage('js调用ios');
            } catch(error) {
              console.log('WKWebView post message error: ', error);
            }
        }
    </script>
</body>
</html>

通过上面4个步骤后,可以得到结果,当WKWebView加载页面成功后,对调用index.htmldisplayDate()·方法来显示时间,点击页面上的按钮会弹出提示弹窗

bsbqc-hjhul.gif

以上就是在IOS中使用WKWebViewJavaScript进行交互的基本步骤。这种交互方式为原生提供更大的灵活性,我们可以利用Web技术的便利性,同时保持原生应用的高性能和流畅性。

需要注意的是,虽然WKWebView提供了一套完整的API来和JavaScript进行交互,但我们仍然需要谨慎处理JavaScript发送的消息,防止潜在的安全问题。在实际开发中,我们应该尽量限制JavaScript能够调用的原生方法,并对传递的数据进行严格的验证和过滤。

同时,我们也需要注意WKWebView的性能问题。虽然WKWebView的性能大大优于UIWebView,但它仍然不如原生视图。因此,应该根据应用的具体要求和性能要求,合理选择使用WKWebView和原生视图。

おすすめ

転載: juejin.im/post/7232299098242105403