使用WebKit从Swift调用WKWebView JavaScript和从JavaScript调用Swift
许多移动应用程序都将远程网页合并为被动(静态)内容,或者在这种情况下作为UI的组成部分。 使用此处介绍的WebKit / WKWebView技术,您的本机应用程序可以更好地与Web内容集成,并为最终用户提供卓越的体验。
Swift和JavaScript之间的双向集成
在本文中,我们将构建一个完整的混合本机/ Web应用程序示例,该应用程序在本机iOS应用程序(用Swift编写)和移动网页(用HTML / JavaScript编写)之间使用双向函数调用。
通过利用这两个功能,我们可以构建一个高度健壮的混合应用程序,其中本机和Web组件作为平等的合作伙伴协作,以提供有价值的客户解决方案。
解决方案概述
最终的解决方案包含两个组件:
- 在Swift中开发的本机iOS应用程序
- 托管在远程Web服务器上的静态HTML / JavaScript网页(在本例中为Microsoft Azure托管)。
完成学习的应用程序实现了三个主要功能:
#1-从远程加载网页。 如果您使用过WKWebView,那么您将了解所有有关此功能的信息。 加载UIViewController时,会将网页URL设置为WKWebView,该WebKView使用HTTP GET方法获取HTML内容。
#2 —从Swift操纵WebView的外观。 接下来,我们通过向WKWebView内容页面发送命令以根据本机Segment控件中的用户选择来更改页面背景颜色,来轻而易举地进入互操作性领域。
#3-从HTML / JavaScript回调到Swift。 最后,通过将本机iOS应用程序中的地理位置功能公开到网页,我们使解决方案更加复杂和有趣。 当用户输入地址时,在Web视图页面上按一个按钮,将完成以下操作:
- 网页(使用JavaScript)调用Swift函数,将用户输入的地址作为JSON对象传入。
- Swift本机应用程序使用CLLocation异步调用Apple,以确定用户输入地址的纬度和经度。
- 从Apple返回纬度/经度时,Swift本机应用程序将调用网页中的JavaScript函数,以使用输入地址的纬度/经度来更新网页。
解决方案演示
在遍历代码之前,让我们演示完整的应用程序的外观(动画GIF)。
UI故事板设计
学习应用程序包含一个名为ViewController的 UIViewController。 ViewController在Storyboard中只有两个UI控件:
- 一个UISegmentedControl,允许用户将WebView背景颜色更改为五种颜色之一。
- UIView,放置在情节提要中,用作WKWebView控件的容器视图。
更改网页颜色
为了深入研究混合解决方案,让我们实现一个从 Swift 到 WKWebView的简单调用。
ViewController具有与本机视图顶部的Segment控件中的颜色选择相对应的颜色成员数组。
让颜色= [“黑色”,“红色”,“蓝色”,“绿色”,“紫色”]
当用户在Segment控件中点击新的细分时,事件处理程序将调用JavaScript函数changeBackgroundColor ,并传递与用户选择相对应的字符串:
@IBAction func colorChoiceChanged(_发送者:UISegmentedControl){
webView.evaluateJavaScript
(“ changeBackgroundColor('(colors [sender.selectedSegmentIndex])')'”,
completeHandler:无)
}
Swift代码并不真正知道网页上有一个名为changeBackgroundColor的JavaScript例程。 要做的工作是格式化将在WebView中成功运行的JavaScript片段。
WKWebView中的HTML内容具有匹配的JavaScript例程,该例程仅将页面的背景色设置为从Swift传递给它的字符串:
函数changeBackgroundColor(colorText){
document.body.style.background = colorText;
}
设置消息处理程序
下一个功能是将用户输入的地址从HTML页面发送到本地Swift应用程序进行地理编码。 要实现此功能,分三个步骤:
- 将消息处理程序添加到WKWebView的WKUserContentController。 这建立了一个约定,该约定保证Swift代码可以通过JavaScript从HTML页面调用时,可以响应命名的消息处理程序。
- 实现WKScriptMessageHandler委托方法didReceive消息以接收来自JavaScript的调用。
- 从Web内容JavaScript调用消息处理程序。
创建一个消息处理程序(1)
// 一种
让contentController = WKUserContentController();
contentController.add(自己,名称:“ geocodeAddress”)
// B
让config = WKWebViewConfiguration()
config.userContentController = contentController
// C
webView = WKWebView(框架:webViewContainer.bounds,配置:配置)
在(A)创建一个WKUserContentController。 contentController保存geocodeAddress消息处理程序的注册。
WKUserContentController已添加到(B)处的新WKWebViewConfiguration中。
最后,在实例化WKWebView的(C)中 ,将在(B)中创建的已配置WKWebViewConfiguration传递给初始化程序。
实现WKScriptMessageHandler委托(2)
现在,将geocodeAddress处理程序定义为WKWebView,我们需要实现一个委托方法,该方法在调用WKWebView事件处理程序时触发。
在此解决方案中,定义了扩展以在ViewController类上实现WKScriptMessageHandler协议。
扩展ViewController:WKScriptMessageHandler {
func userContentController(
_ userContentController:
WKUserContentController,
didReceive消息:WKScriptMessage){
如果message.name ==“ geocodeAddress”,
让dict = message.body为? NSDictionary {
geocodeAddress(dict:dict)
}
}
}
didReceive处理程序将检查消息名称是否符合预期( geocodeAddress ),如果是,则从消息正文中提取JSON对象(作为NSDictionary),然后调用ViewController实例方法geocodeAddress 。
请注意,消息处理程序是字符串类型的 ,因此请注意, didReceive中的字符串比较正确匹配使用WKUserContentController进行的原始消息处理程序注册。
从HTML / JavaScript页面调用geocodeAddress(3)
在HTML中,表单的INPUT按钮调用一个称为geocodeAddress的JavaScript函数:
JavaScript geocodeAddress函数的主体通过调用同名的Swift消息处理程序进行响应,并将地址详细信息作为JSON对象传递。
函数geocodeAddress(){
尝试{
webkit.messageHandlers.geocodeAddress.postMessage(
{
街道:document.getElementById(“街道”).value,
城市:document.getElementById(“ city”)。value,
状态:document.getElementById(“状态”).value,
国家/地区:document.getElementById(“ country”)。value
});
document.querySelector('h1')。style.color =“绿色”;
} catch(err){
document.querySelector('h1')。style.color =“红色”;
}
}
注意:在JavaScript geocodeAddress()函数中,此处的H1样式更改仅出于测试目的,而不是实际解决方案的一部分。
将纬度/经度传递回HTML页面
到目前为止,HTML页面已经在一系列INPUT字段中接受了来自用户的地址输入,并将其发送到本机Swift应用程序。 现在,让我们完成最后的要求-对地址进行地理编码并将其返回到网页UI。
回想一下,Swift消息处理程序调用了一个名为geocodeAddress(dict 🙂的Swift函数来对地址进行地理编码。
func geocodeAddress(dict:NSDictionary){
让geocoder = CLGeocoder()
让street = dict [“ street”]如? 字符串?? “”
让city = dict [“ city”]为? 字符串?? “”
让状态= dict [“状态”]为? 字符串?? “”
让国家= dict [“国家”]为? 字符串?? “”
让addressString =“ \(街道),\(城市),\(州),\(国家)”
geocoder.geocodeAddressString(
addressString,
completeHandler:geocodeComplete)
}
解决方案的这一部分是简单的CoreLocation。 在geocodeAddressString异步函数将地址发送给Apple之后,响应将提供给Swift方法geocodeComplete :
func geocodeComplete(placemarks:[CLPlacemark] ?,错误:Error?){
如果让地标=地标,则placemarks.count> 0 {
let lat = placemarks [0] .location?.coordinate.latitude ?? 0.0
let lon =地标[0] .location?.coordinate.longitude? 0.0
webView.evaluateJavaScript(
“ setLatLon('\(lat)','\(lon)')”,complementHandler:无)
}
}
此方法检查以确保为提供的地址找到至少一个地标,从第一个地标中提取纬度和经度,然后通过调用setLatLon JavaScript函数将其发送回HTML页面。
更新HTML页面
将纬度/经度发送回网页的过程与设置背景色的先前功能在功能上相同。
setLatLon JavaScript函数的实现如下:
函数setLatLon(lat,lon){
document.getElementById(“ latitude”)。value = lat;
document.getElementById(“ longitude”)。value = lon;
}
与背景颜色功能一样, setLatLon只需将HTML表单的INPUT字段值设置为传递的参数值。
摘要
WKWebView的最常见用法是在本机iOS应用程序的上下文中提供Web内容的简单显示-但是它可以做的更多,并且在本文中,我们已经看到了如何结合使用Web和本机组件来构建增强的本机应用程序,甚至混合本机/网络应用程序。
下载代码
以上片段提供了学习解决方案的核心功能。 完整的Xcode项目可在此处从Github下载。