WKWebView的15条应用指南
1.让一个web view充满屏幕
有时候你会看到有人向viewDidLoad()中添加代码,创建一个web view并让它充满整个可用区域。但这样效率很低,用起来很麻烦。
一个简单的方法是在你的视图控制器(view controller)中像这样加入一个属性:
1
|
let webView = WKWebView() |
之后覆盖loadView()方法,把它分配到你的视图控制器里:
1
2
3
|
override func loadView() { self.view = webView } |
这样一个专用的webView属性很有用,能让人更方便地引用它的属性和方法。
2. 加载远程内容
WKWebView的一个主要用途就是加载远程内容,但需要不止一行代码。你需要用一串字符创建URL,把它放在一个URLRequest中,之后请求web view加载它。
1
2
3
4
|
let request = URLRequest(url: url) webView.load(request) } |
如果你想加载大量URL的话,把这个行为放到一个扩展(extension)里会更简单.
1
2
3
4
5
6
7
8
|
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()方法加载你app bundle中存储的任何HTML。你需要提供指向一些HTML文件的URL,这些HTML文件需要在你的bundle中,此外还需要提供另一个URL,里面存有你希望web view加载的其他文件。
例如,如果你希望加载help.html,代码如下:
1
2
3
|
if let url = Bundle.main.url(forResource: "help" , withExtension: "html" ) { webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent()) } |
其中url.deletingLastPathComponent()告诉了WebKit它可以从包含help.html的目录中加载——这里还可以放图片或者CSS等。
4.读取HTML分段
你可以生成代码形式的HTML,并直接提供给WKWebView。下例展示了一个头信息:
1
2
3
4
5
6
7
8
9
|
let html = "" " <h1>Hello, Swift!</h1> "" " webView.loadHTMLString(html, baseURL: nil) |
注意loadHTMLString()的baseURL参数。如果从你的bundle中引用图片或者CSS等,你需要指定Bundle.main.resourceUR,这样才可以读取。像下面这样:
webView.loadHTMLString(html, baseURL: Bundle.main.resourceURL)
5.控制哪些站点可以被访问
WKWebView默认允许访问所有可用站点,但根据你制定的标准锁定站点也很容易。
首先,让一些对象符合WKNavigationDelegate——比如你的视图控制器,或者其他的:
1
|
class ViewController: UIViewController, WKNavigationDelegate { |
之后,让它不符合你web view的navigationDelegate。以视图控制器为例,代码如下
1
|
webView.navigationDelegate = self |
最后,执行decidePolicyFor方法,添加你想要的逻辑来判定网页是否允许被加载。下例中,允许用户访问苹果首页,而不能访问其他页面。
1
2
3
4
5
6
7
8
9
|
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.用外部浏览器打开一个链接
经常会遇到需要外部处理一些app中链接的情况,通过WKNavigationDelegate协议,这一步并不需要太多工作了。
首先让一个对象符合这个协议——比如你的视图控制器,或者其他的:
1
|
class ViewController: UIViewController, WKNavigationDelegate { |
之后把这个对象设置成你web view的navigation delegate。如果你是在用视图控制器,代码则如下
1
|
webView.navigationDelegate = self |
最后,根据自动判定从内部/外部加载网页的逻辑,执行decidePolicyFor方法。对于内部加载,确保你通过.cancel终止了decisionHandler(),这样就停止加载。而对于外部加载,则调用UIApplication.shared.open()从外部浏览器打开URL。
下例中,对于苹果主页以外的链接,都会从web view中打开。
1
2
3
4
5
6
7
8
9
10
|
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属性做到:
1
|
webView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: . new , context: nil) |
现在应该执行observeValue(forKeyPath:)方法,它会传递一串字符,说出有什么改变了。如果它被设定为“estimatedProgress”,我们就可以通过web view的最新estimatedProgress属性做很多事情:
1
2
3
4
5
|
override func observeValue(forKeyPath keyPath: String ?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if keyPath == "estimatedProgress" { print(Float(webView.estimatedProgress)) } } |
8.当发生改变时读取网页标题
你可以使用webView.title读取当前页面标题,但是因为随着用户浏览,页面标题可能改变,那么当标题改变时最好可以获得通知。
要做到这个,首先注册获取标题改变的通知
1
|
webView.addObserver(self, forKeyPath: #keyPath(WKWebView.title), options: . new , context: nil) |
现在执行observeValue(forKeyPath:)方法,它会通过字符串告诉你什么改变了,如果改变的是标题,我们就可以做下一步了。
下面的代码仅当标题变化时才会打印
1
2
3
4
5
6
7
|
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 view的backForwardList属性,它包含了backList和forwardList数组。
在每一个数组中,你可以读取每个被浏览页面的URL,以及被使用的标题。例如,你可以使用下面的循环打出用户访问过的站点列表。
1
2
3
|
for page in webView.backForwardList.backList { print( "User visited \(page.url.absoluteString)" ) } |
10.向页面注入JavaScript
在你的web view加载一些内容后,你可以使用evaluateJavaScript()方法在已渲染的页面中执行JavaScript。你只需要提供一些用于执行的JavaScript就可以了——例如读取一些数值,并当执行结束时关闭。
举个例子,如果你有一个包含
的页面,并且想读取“@twostraws”部分,则这么做:
1
2
3
4
5
|
webView.evaluateJavaScript( "document.getElementById('username').innerText" ) { (result, error) in if let result = result { print(result) } } |
11.读取和删除cookies
你可以使用web view的httpCookieStore属性,读取一个网站相关的完整cookies列表。它被埋藏在configuration.websiteDataStore属性下,但是只要你找到它,就可以用getAllCookies()来获取cookies列表,或用delete()来删除某个cookie。
下面例子中,代码会循环遍历所有cookies,并且当它找到名为“authentication”的cookie时就删除它,并把所有其他cookies打印出来:
1
2
3
4
5
6
7
8
9
|
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)
用户代理让你的服务器鉴别出正在访问页面的是哪种浏览器,常用于开启/限制某些特性是否可用。
如果你正在阅读自己的服务器上的网页,你可以把用户代理调整为你自己的字符串,这样你就可以鉴别你app的用户:
1
|
webView.customUserAgent = "My Awesome App" |
注意:当访问其他资源时,你确实能够改变用户代理,但是记住一些网站也许会读取用户代理字符串,如果这和它期望的不同,会感到混乱。
13.展示自定UI
WKWebView在iOS Safari app中有点像拥有自己独有标签,这意味着用户不能开启关闭新窗口来浏览多页面,它甚至不会显示JavaScript触发的警告或确认请求。
好在你可以通过WKUIDelegate协议改变这些:把一个对象设置为你web view的UI delegate,你就可以显示自定警告,管理自己的标签等等。
首先让一些对象,比如你的ViewController符合它:
1
|
class ViewController: UIViewController, WKUIDelegate { |
之后根据web view的uiDelegate属性配置视图控制器
1
|
webView.uiDelegate = self |
最后可选WKUIDelegate的任意个方法执行。比如当任意网页使用alert() JavaScript函数时,让WKWebView显示一个自定警告控制器:
1
2
3
4
5
6
|
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() } |
此外还有runJavaScriptConfirmPanelWithMessage用于展示确认或拒绝UI,runJavaScriptTextInputPanelWithPrompt用于请求用户输入文本,等等
注意:当你完成后,必须调用完成处理器(completion handler)。JavaScript在警告都完成之前无法继续执行,所以你需要让WebKit知道你什么时候做完了。
14.部分页面快照
你可以用常规的drawHierarchy()方法把页面转化为图片,此外还可以用WebKit的takeSnapshot()方法。它可以让你剪裁或调整图像大小。
下例会产生一个web view 左上部的150X50图片
1
2
3
4
5
6
7
8
|
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 views有内建的数据监测器,意味着它们可以把类似电话号码,日历事件,航班号等放到可输入的链接(tappable link)中。
默认这些都被禁用了,会按照设计渲染网页。但是可以不遵照它,使用自定的WKWebViewConfiguration对象创建你的web view就行了。
下例命令web view去检测所有可能的数据类型:
1
2
3
|
let config = WKWebViewConfiguration() config.dataDetectorTypes = [.all] let webView = WKWebView(frame: .zero, configuration: config) |
WKWebView的15条应用指南的更多相关文章
- 15条SQLite3语句
15条SQLite3语句 转自:http://www.thegeekstuff.com/2012/09/sqlite-command-examples/ SQLite3 is very light ...
- Web开发者不可不知的15条编码原则
HTML已经走过了近20的发展历程.从HTML4到XHTML,再到最近十分火热的HTML5,它几乎见证了整个互联网的发展.但是,即便到现在,有很多基础的概念和原则依然需要开发者高度注意.下面,向大家介 ...
- 从零开始学 iOS 开发的15条建议
事情困难是事实,再困难的事还是要每天努力去做是更大的事实. 因为我是一路自学过来的,并且公认没什么天赋的前提下,进步得不算太慢,所以有很多打算从零开始的朋友会问我,该怎么学iOS开发.跟粉丝群的朋友交 ...
- Web 开发者不可不知的15条编码原则
HTML 已经走过了近20的发展历程.从HTML4到XHTML,再到最近十分火热的HTML5,它几乎见证了整个互联网的发展.但是,即便到现在,有很多基础的概念和原则依然需要开发者高度注意.下面,向大家 ...
- iOS WKWebView添加进度条02
之前写了一个是关于webview添加进度条的,现在补一个WKWebView进度条. //添加一个全局属性 @property(nonatomic,strong)CALayer *progresslay ...
- 推荐15条MySQL改善经验,让系统更稳定
1. 为查询缓存优化查询 像 NOW() 和 RAND() 或是其它的诸如此类的SQL函数都不会开启查询缓存,谨慎使用 2.EXPLAIN 我们的SELECT查询(可以查看执行的行数) 可以让我们找到 ...
- 15条MySQL改善经验让系统更稳定
MySQL 作为目前的主流开源数据库, 既能挑战 “双11”,又能扛起 “618”,比起网红版数据库,MySQL 绝对是实力担当. 1. 为查询缓存优化查询 像 NOW() 和 RAND() 或是其它 ...
- 创业15条经验总结:温饱之后,创业公司CEO如何树“三观”?
都说创业改变命运,事实上不是,创业,时时刻刻,可能连“命”都保不住!创业公司最重要的只有“活下去”.满足了这个.才有资格谈其他.公司连饭都开不了,还谈什么其他?创业公司如果连生存问题都解决不了,高位的 ...
- [Effective JavaScript 笔记]第15条:当心局部块函数声明笨拙的作用域
嵌套函数声明.没有标准的方法在局部块里声明函数,但可以在另一个函数的顶部嵌套函数声明. function f(){return "global"} function test(x) ...
随机推荐
- python基础4 - 判断(if)语句
6. 判断(if)语句 6.1 if 判断语句基本语法 在 Python 中,if 语句 就是用来进行判断的,格式如下: if 要判断的条件: 条件成立时,要做的事情 …… 注意:代码的缩进为一个 t ...
- C++(零)— 提高程序运行效率
1.尽量减少值传递,多用引用来传递参数. 2.++i和i++引申出的效率问题,使用++i. 3.避免过大的循环,由计算机的硬件决定的. 4.局部变量VS静态变量,尽量使用局部变量. 5.减少除法运算的 ...
- Disruptor_学习_00_资源帖
一.官方 disruptor-github disruptor-api LMAX Disruptor 二.精选资料 Disruptor入门-官方文档翻译-方腾飞 Disruptor官方文档实现 Dis ...
- MySQL引擎各个引擎对比介绍
1.什么是存储引擎? 存储引擎类似于录制的视频文件,可以转换成不同的格式,如MP4,avi等格式,而存储在我们的磁盘上也会存在于不同类型的文件系统中如:Windows里常见的NTFS,fat32等.存 ...
- Magic Index 寻找数组中A[i]=i的位置(原题转自微信号待字闺中)
有一个有意思的题目叫做Magic Index:给定一个数组A,其中有一个位置被称为Magic Index,含义是:如果i是Magic Index,则A[i] = i.假设A中的元素递增有序.且不重复, ...
- 排列(加了点小set就过了,哈哈哈)
Ray又对数字的列产生了兴趣: 现有四张卡片,用这四张卡片能排列出很多不同的4位数,要求按从小到大的顺序输出这些4位数. 输入描述: 1 2 3 4 1 1 2 3 0 1 2 3 0 0 0 0输出 ...
- Codeforces 786C. Till I Collapse 主席树
题目大意: 给定一个长度为\(n\)的序列,要求将其划分为最少的若干段使得每段中不同的数字的种数不超过\(k\). 对于 \(k = 1 .. n\)输出所有的答案. \(n \leq 10^5\) ...
- shell split函数的使用
#!/bin/awk -f BEGIN{FS=","} {split($1,name," "); for (i in name) print name[i] }
- IntellJ IDEA快捷键汇总
今天开始使用IDEA,各种不习惯,一会Eclipse一会IDEA来回切换,需要一个熟悉的过程,记录一下常用的快捷键. IDEA常用快捷键 Alt+回车 导入包,自动修正Ctrl+N 查找类Ctrl+ ...
- ODP.NET OracleBulkCopy
using System;using System.Collections.Generic;using System.Linq;using System.Text;using Oracle.DataA ...