foreword
With the rapid development of the mobile Internet, the boundaries between Web development and native application development are gradually blurring. On the one hand, web technology is constantly improving, and many functions that could only be realized in native applications before, such as offline storage, device API access, etc., can now be realized through web technology. On the other hand, native application development has also begun to adopt Web technology to improve development efficiency and achieve cross-platform capabilities. This trend of combining web development with native development has brought new possibilities for mobile application development.
Alternation between UIWebView and WKWebView
Originally, the way to load web pages on the iOS platform was through the use of UIWebView. However, with the development of iOS platform technology, the limitations of UIWebView gradually emerged. First of all, the performance problem of UIWebView is prominent. It needs to consume a lot of memory and CPU resources when loading web pages, resulting in low application efficiency. Secondly, UIWebView does not support concurrent loading of multiple web pages, which seems powerless in multitasking scenarios. Finally, the API design of UIWebView is relatively old and does not support new Web technology standards.
In order to solve these problems, Apple introduced a new component in iOS 8 - WKWebView, which is used to replace UIWebView. WKWebView uses the Nitro JavaScript engine in its design, which is an efficient engine that can greatly improve the execution efficiency of JavaScript. At the same time, WKWebView also supports concurrent loading of multiple web pages, and adopts the latest web technology standards, enabling developers to use the latest web technologies.
The principle of interaction between WKWebView and JavaScript
The interaction between WKWebView and JavaScript can basically be divided into two directions: one is that JavaScript calls Swift code, and the other is that Swift code calls JavaScript code.
For JavaScript calling Swift code, WKWebView provides WKScriptMessageHandler
a protocol, and developers can receive messages sent by userContentController(_:didReceive:)
JavaScript code through methods by implementing the method of the protocol.postMessage
For Swift code calling JavaScript code, WKWebView provides evaluateJavaScript(_:completionHandler:)
a method through which developers can execute JavaScript code and obtain the execution result through completionHandler.
Next, use an example to use WKWebView to interact with JavaScript
1. Create and configure WKWebView
First, we need to create a Swift project and ViewController
import the WebKit module in the default build to support the use of WKWebView.
import WebKit
Let ViewController implement the WKNavigationDelegate and WKScriptMessageHandler protocols. The WKNavigationDelegate protocol is used to handle web page navigation events, and the WKScriptMessageHandler protocol is used to receive messages sent by JavaScript. Also, declare a variable webView of type WKWebView.
class ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler {
var webView: WKWebView!;
...
}
In loadView
the method, we first create an WKUserContentController
instance and add(self, name: "nativeCallback")
add a message handler called "nativeCallback" through the method. Then, we create an WKWebViewConfiguration
instance and userContentController
set its properties to the content controller we just created. Finally, we use this configuration object to create an instance of WKWebView and assign it to the view controller's view property.
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;
}
Note that since no Storyboard or Xib file is used to define the layout of the view in Interface Builder, the loadView
method needs to be rewritten. In this method, an instance of UIView (or its subclass) needs to be created and assigned to the view controller's view
Attributes.
在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.html
的displayDate()·
方法来显示时间,点击页面上的按钮会弹出提示弹窗
以上就是在IOS中使用WKWebView
与JavaScript
进行交互的基本步骤。这种交互方式为原生提供更大的灵活性,我们可以利用Web技术的便利性,同时保持原生应用的高性能和流畅性。
需要注意的是,虽然WKWebView
提供了一套完整的API来和JavaScript进行交互,但我们仍然需要谨慎处理JavaScript发送的消息,防止潜在的安全问题。在实际开发中,我们应该尽量限制JavaScript能够调用的原生方法,并对传递的数据进行严格的验证和过滤。
同时,我们也需要注意WKWebView
的性能问题。虽然WKWebView
的性能大大优于UIWebView
,但它仍然不如原生视图。因此,应该根据应用的具体要求和性能要求,合理选择使用WKWebView
和原生视图。