原文地址
Wkwebview 是 iOS 上的一个强大平台,可以随时随地提供高性能的网页渲染。
在本文中,我收集了 WKWebView 最常用的15个用例,并为每个用例提供了实际操作的代码解决方案。 所以,如果你想解决一个特定的问题,或者你只是想看看 WebKit 能做什么,请继续阅读!
1. 在屏幕上创建一个webview视图
有时你会看到人们在 viewDidLoad ()中添加代码来创建一个 web 视图,然后填充所有可用的空间。 这种做法效率低下,而且难度远远超出需要。
一个更简单的方法是像这样在视图控制器中添加一个属性:
let webView = WKWebView()
然后重写 loadView ()方法,将其分配给视图控制器的视图,如下所示:
override func loadView() {
self.view = webView
}
拥有一个专用的 webView 属性是很有帮助的,这样您以后可以更容易地引用它的属性和方法。
2. 加载远程内容
既然 WKWebView 的主要用途之一是加载远程内容,那么奇怪的是它不只是一行代码。 相反,你可以从一个字符串创建一个 URL,将它包装在一个 URLRequest 中,然后要求 web 视图加载这个 URL:
if let url = URL(string: "https://www.apple.com") {
let request = URLRequest(url: url)
webView.load(request)
}
如果你打算经常加载 url,你可能会发现将这种行为包装在一个扩展中会更容易:
extension WKWebView {
func load(_ urlString: String) {
if let url = URL(string: urlString) {
let request = URLRequest(url: url)
load(request)
}
}
}
现在你可以通过运行 webView.load (“ https://www.apple.com”)
来加载一个网站。
3. 加载本地内容
Wkwebview 可以使用 loadFileURL ()方法加载存储在应用程序包中的任何 HTML。 你应该提供一个你知道在你的包中的某个 HTML 文件的 URL,以及另一个存储你想让 web 视图读取的任何其他文件的 URL。
例如,如果你想加载一个叫做“帮助”的文件,你可以使用如下代码:
if let url = Bundle.main.url(forResource: "help", withExtension: "html") {
webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent())
}
这个 url.deletingLastPathComponent ()部分告诉 WebKit 它可以从包含帮助 html 的目录中读取——这是放置任何资源(如图像、 JavaScript 或 CSS)的好地方。
4. 加载 HTML 片段
你可以在代码中生成 HTML,并将其直接提供给 WKWebView。例如,这会显示一个标题消息:
let html = """
<html>
<body>
<h1>Hello, Swift!</h1>
</body>
</html>
"""
webView.loadHTMLString(html, baseURL: nil)
注意,baseURL 参数设置为 loadHTMLString ()。 如果您正在引用包中的资产(如图像或 CSS) ,那么应该在那里指定 Bundle.main.resourceURL,以便可以加载它们。 例如:
webView.loadHTMLString(html, baseURL: Bundle.main.resourceURL)
5. 控制哪些网站可以访问
默认情况下,WKWebView 允许访问所有可用的网站,但是很容易锁定列表到您选择的任何标准。
首先,使某些东西符合 WKNavigationDelegate ——它可以是您的视图控制器,但不一定是。 例如:
class ViewController: UIViewController, WKNavigationDelegate {
其次,将该对象作为 web 视图的导航代表。 如果你正在使用你的视图控制器,你应该这样写:
webView.navigationDelegate = self
最后,实现 decidePolicyFor
方法,添加任何需要决定是否加载页面的逻辑。 举个例子,这个实现允许用户访问苹果的主页,除此之外:
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if let host = navigationAction.request.url?.host {
if host == "www.apple.com" {
decisionHandler(.allow)
return
}
}
decisionHandler(.cancel)
}
6. 在外部浏览器中打开链接
想要处理应用程序内部的一些链接和外部的其他链接是很常见的,多亏了 WKNavigationDelegate
协议,这并不需要太多的工作。
首先,使一个对象符合协议——它可能是您的视图控制器,但不一定是。 例如:
class ViewController: UIViewController, WKNavigationDelegate {
其次,将该对象设置为 web 视图的导航委托。 如果你正在使用视图控制器,你可以这样写:
webView.navigationDelegate = self
最后,使用任何逻辑来实现 decidePolicyFor 方法,以决定页面是内部加载还是外部加载。 对于内部负载,请确保使用。 取消,这样加载停止,同时调用 UIApplication.shared.open() 在外部浏览器中打开 URL。 举个例子,只要链接不进入苹果的主页,这个实现就可以载入网页视图中的所有链接:
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if let url = navigationAction.request.url {
if url.host == "www.apple.com" {
UIApplication.shared.open(url)
decisionHandler(.cancel)
return
}
}
decisionHandler(.allow)
}
7. 监控页面加载
加载一个网页意味着获取一些 HTML,下载它使用的任何 JavaScript 和 CSS,下载任何图片,等等。
为了帮助您的用户了解信息,最好监视页面加载并显示某种用户界面更新,以便他们知道正在发生什么事情。 这可以通过观察 estimatedProgress 属性来实现,如下所示:
webView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil)
现在应该实现 observeValue (forKeyPath:)方法,该方法将向您传递一个字符串,说明发生了什么更改。 如果设置为“估计进度” ,那么我们可以使用 web 视图的最新估计进度属性来做一些有趣的事情:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "estimatedProgress" {
print(Float(webView.estimatedProgress))
}
}
8. 阅读网页标题的变化
您可以使用 webView.title 来读取当前页面的标题,但是由于页面标题会随着用户的浏览而发生变化,您可能希望在页面发生变化时得到通知。
要做到这一点,首先注册以便在标题更改时接收通知:
webView.addObserver(self, forKeyPath: #keyPath(WKWebView.title), options: .new, context: nil)
现在实现 observeValue (forKeyPath:)方法。 这将传递给您一个字符串,说明什么更改了,如果这是“标题” ,那么您可以使用它做一些事情。
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "title" {
if let title = webView.title {
print(title)
}
}
}
9.阅读用户访问过的页面
如果你真的想建立一个有用的浏览器体验,你可能会想要阅读用户访问过的网站列表。 这些都可以在 web 视图的 backForwardList 属性中找到,该属性本身包含数组 backList 和 forwardList。
在每个数组中,您可以读取访问过的每个页面的 URL 以及所使用的标题。 例如,你可以使用这个循环打印出用户已经访问过的所有网站的列表:
for page in webView.backForwardList.backList {
print("User visited \(page.url.absoluteString)")
}
10.在页面中注入 JavaScript
一旦你的 web 视图加载了一些内容,你可以使用 evaluateJavaScript ()方法在渲染的页面中执行任何 JavaScript。 您所需要做的就是给它一些 JavaScript 来执行——例如,读取一些值——以及一个闭包,以便在执行结束时运行。
举个例子,如果你有一个包含 div id"username"@twostraw / div 的页面,并且你想阅读“@twostraw”部分,你会使用这个:
webView.evaluateJavaScript("document.getElementById('username').innerText") { (result, error) in
if let result = result {
print(result)
}
}
11.阅读和删除 cookies
您可以通过使用 web 视图的 httpCookieStore 属性来阅读与网站关联的 cookie 的完整列表。 这个属性隐藏在 configuration.websiteDataStore 属性之下,但是一旦找到它,就可以调用 getAllCookies ()获得一个 cookie 数组,或者调用 delete ()删除特定的 cookie。
例如,这段代码循环遍历所有 cookie,当它发现一个被称为“身份验证”的程序时,就删除它——所有其他 cookie 都会被打印出来:
webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in
for cookie in cookies {
if cookie.name == "authentication" {
self.webView.configuration.websiteDataStore.httpCookieStore.delete(cookie)
} else {
print("\(cookie.name) is set to \(cookie.value)")
}
}
}
12. 提供自定义 user agent
用户代理让你的 web 服务器识别访问页面的 web 浏览器类型,并且通常用于启用或限制可用的特性。
如果您正在从您自己的服务器读取页面,您可以将用户代理调整为您自己的字符串,以便您可以识别您的应用程序的用户。 例如:
webView.customUserAgent = "My Awesome App"
注意: 在访问其他资源时,没有什么可以阻止您更改用户代理,但请记住,一些网站可能会读取用户代理字符串,如果它不符合他们的期望,就会感到困惑。
13. 显示自定义用户界面
WKWebView有点像 iOS Safari 应用程序中的一个标签,这意味着用户不能打开或关闭新窗口来浏览多个页面,甚至不会显示由 JavaScript 触发的警告或确认请求。
幸运的是,您可以使用 WKUIDelegate 协议来改变这一点: 设置一个对象作为您的 web 视图的 UI 代表,您可以显示自定义警报,管理您自己的选项卡,等等。
首先,让一些对象,如你的视图控制器符合它:
class ViewController: UIViewController, WKUIDelegate {
其次,将视图控制器分配给 web 视图的 uiDelegate 属性:
webView.uiDelegate = self
最后,实现尽可能多的 WKUIDelegate 可选方法。 例如,当任何网页使用 alert () JavaScript 函数时,你可以让 WKWebView 显示一个自定义的警报控制器:
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
let ac = UIAlertController(title: "Hey, listen!", message: message, preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(ac, animated: true)
completionHandler()
}
还有用于显示 confirm 和 deny UI 的 runJavaScriptConfirmPanelWithMessage
,用于请求用户文本输入的runJavaScriptTextInputPanelWithPrompt
等等。
注意: 完成后必须调用完成处理程序。 的 alerts 是阻塞的,这意味着 JavaScript 在警报结束之前不会继续执行。 因此,如果你不让 WebKit 知道你什么时候完成,它就会抱怨。
14. 页面快照
虽然您可以使用常规的drawHierarchy()
方法将视图转换为图像,但是 WebKit 提供了自己的takeSnapshot()
方法,可以根据需要裁剪和调整图像的大小。
例如,这将从 web 视图的左上角生成一个150x50的图像:
let config = WKSnapshotConfiguration()
config.rect = CGRect(x: 0, y: 0, width: 150, height: 50)
webView.takeSnapshot(with: config) { image, error in
if let image = image {
print(image.size)
}
}
如果你不想要一个裁剪过的图片——也就是说你想要整个图片——只需要使用 nil 而不是config。
15. 探测数据
Web 视图具有内置的数据检测器支持,这意味着它们可以将电话号码、日历事件和航班号之类的内容添加到可伸缩链接中.
这些都是禁用的,所以默认行为是渲染网页,因为他们的设计,但它的琐碎覆盖-只是创建您的 web 视图使用自定义 WKWebViewConfiguration 对象。
例如,它指示 web 视图检测所有可能的数据类型:
let config = WKWebViewConfiguration()
config.dataDetectorTypes = [.all]
let webView = WKWebView(frame: .zero, configuration: config)