添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

语言: swift, 版本:4.2,XCode:10.2
写作时间:2019-04-23

WKWebView

WKWebView在iOS 8 以后提供的高性能的Web容器. 本文列举15个最常用的用法。

1. 创建一个WKWebView覆盖全屏

在viewDidLoad() 中创建WKWebView,并增加为view的subView或者直接替换掉view. 这样做的弊端是,后续想要用到WKWebView就比较困难.

一种简单的方式是增加一个WKWebView的属性:

let webView = WKWebView()

在 loadView() 的方法去设置ViewController‘s view:

override func loadView() {
    self.view = webView

拥有一个WKWebView的属性,可以方便后面引用webview的属性和方法。

2. 加载远程内容URL

WKWebView最重要的功能是加载一个远程内容的url, 它比较古怪不是一句代码调用. 反而,先用string创建一个URL对象, 接着封装为URLRequest对象, 最后通知WKWebView去加载URLRequest对象:

func loadRemoteUrl(_ urlString: String) {
    if let url = URL(string: urlString) {
        let request = URLRequest(url: url)
        webView.load(request)

如果比较频繁调用远程URLs,可以给WKWebView封装一个extension,使加载URL变成一句话方法:

extension WKWebView {
    func load(_ urlString: String) {
        if let url = URL(string: urlString) {
            let request = URLRequest(url: url)
            load(request)

现在可以一句话加载远程内容URL

webView.load("https://www.apple.com").

3. 加载本地内容

WKWebView可以用 loadFileURL() 加载已经预置在bundle里面的HTML. 你可以提供File URL指向bundle中HTML文件.

举个?, 如果你要加载一个文件叫 “help.html” :

func loadLocalFile() {
    if let url = Bundle.main.url(forResource: "help", withExtension: "html") {
        let path = url.deletingLastPathComponent()
        print("url: \(url)")
        print("path: \(path)")
        webView.loadFileURL(url, allowingReadAccessTo: path)
 

help.html , 这里help.css的路径为相对路径,因为Bundle下面的路径都会被打包到根目录下,详情请看下面的文件截图。

<link href="help.css" rel="stylesheet" /> </head> <h1>Hi, do you need help?</h1> <a href="https://www.apple.com">apple.com</a> <div id="username">@zgpeace</div> phone:<span class="nowrap">18686868866</span> </body> </html>

url.deletingLastPathComponent()告诉WebKit它可以读取在目录下,help.html引用的文件,比如images, JavaScript, CSS.

help.css

h1 {
    margin-top:200px;
    color:red;
 

参数allowingReadAccessTo 用url, 或者url.deletingLastPathComponent(),都能加载出css的样式。难道是目录如果是同一个文件夹都可以用这两种方式来用?知情者帮忙指正,谢谢。

在这里插入图片描述
运行效果如下:
在这里插入图片描述

4. 4. 加载HTML片段字符串

WKWebView可以直接加载HTML代码字符串:

func loadHtmlFragments() {
        let html = """
                <link href="help.css" rel="stylesheet" />
            </head>
                <h1>Hello, Swift!</h1>
            </body>
        </html>
//        webView.loadHTMLString(html, baseURL: nil)
        webView.loadHTMLString(html, baseURL: Bundle.main.resourceURL)

方法webView.loadHTMLString(html, baseURL: nil)中注意参数baseURL. 如果你引用相关资源比如 images, 或者 CSS, 你可以指定 Bundle.main.resourceURL:

webView.loadHTMLString(html, baseURL: Bundle.main.resourceURL)

5. 5. 控制哪些网站可以访问

WKWebView默认允许访问所有网站, 当然这个权限是可以配置的.
首先,需要把类遵循代理协议 WKNavigationDelegate – 它可以是view controller, 也可以是其它类. 比如:

class ViewController: UIViewController, WKNavigationDelegate {

接着, 设置webView的navigation delegate为当前类:

webView.navigationDelegate = self

最后, 实现方法decidePolicyFor, 增加逻辑决定哪些页面可以加载。作为例子, 下面的实现允许访问host为www.apple.com的网站:

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 protocol.

首先, 标志类遵循代理协议WKNavigationDelegate:

class ViewController: UIViewController, WKNavigationDelegate {

接着, 设置webView的navigation delegate为当前类:

webView.navigationDelegate = self

最后, 实现代理方法decidePolicyFor,表明哪些逻辑用内部App还是外部浏览器打开. 外部浏览器打开用方法UIApplication.shared.open() ,接着需要断开App内部打开的逻辑,用方法decisionHandler(),参数用.cancel .

举个?, 这里的实现host为www.apple.com的网站用外部浏览器打开:

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. 监控页面打开进度

加载web页面流程包括,抓取相关HTML, 下载用到JavaScript,CSS, images, 等.

为了提升用户体验,需要告诉用户加载的进度. 实现这需要观察observing属性estimatedProgress :

webView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil)

增加观察者属性后,接着实现通知方法observeValue(forKeyPath:) , 它可以通知你一个字符串改变的内容. 如果是属性“estimatedProgress”的改变,可以通过进度条的方式告诉用户,这里只是 打印进度信息:

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:) method. 这里会传递给你更新的标题,可以更新导航栏信息.

这里只是打印更新的标题:

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. 读取访问过的历史页面

浏览器可以前进和后退,就是因为这些痕迹都被记录. 这些都存储在webView的属性backForwardList中, 它包含了两个数组backList, forwardList.

在这两个数组中,你可以访问所有前进和后退的页面,一般会用到标题和链接url:

func printHistoryBackList() {
    for page in webView.backForwardList.backList {
        print("User visited title:\(page.title), url: \(page.url.absoluteString)")

10. 注射JavaScript到页面中

一旦webView加载内容,你可以调用方法evaluateJavaScript()去执行任何JavaScript到已渲染完毕的页面. 你仅仅需要执行JavaScript – 读取网页上的内容, 比如 – 当JavaScript运行后,下面的闭包执行.

举个?, 你的页面包含内容 <div id="username">@twostraws</div> and you wanted to read the “@zgpeace” , 你可以通过下面代码获取:

func injectJavaScriptIntoAPage() {
        webView.evaluateJavaScript("document.getElementById('username').innerText") { (result, error) in
        if let result = result {
            print(result)

11. 读取和删除cookies

可以通过webView属性httpCookieStore读取cookies列表. 这是藏在configuration.websiteDataStore的属性, 一旦你找到它可以调用方法getAllCookies()获取cookies数组, 或者调用方法delete()去删除指定的cookie.

举个?, 下面代码遍历所有cookies, 如果找到名字叫“authentication”则删掉它 – 其它的cookies则打印出来:

func manageCookies() {
        webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { (cookies) in
        for cookie in cookies {
            if cookie.name == "authentication" {
                self.webView.configuration.websiteDataStore.httpCookieStore.delete(cookie, completionHandler: nil)
            } else {
                print("\(cookie.name) is set to \(cookie.value)")

12. 设置user agent

User agents可以告诉服务器端web servers,去鉴别客户端浏览器就是App里面的,常用于访问一些受限制的资源.

如果你从服务端读取页面,你可以设置user agent,使服务器端可以鉴别是你的App:

func customUserAgent() {
	print("old agent: \(String(describing: webView.customUserAgent))")
	webView.customUserAgent = "My Awesome App"
	print("new agent: \(String(describing: webView.customUserAgent))")

注意: 你可以修改user agent,当你去访问其它资源的时候。但是记住,有些网站可能会困惑,浏览器怎么会是没见过的名字.

13. 显示定制的UI

WKWebView就像只有一个长条tab的iOS Safari app, 说明用户不能打开或者关闭一个新的windows去浏览多个页面, 并且它不能由JavaScript触发后显示Alert或者Confirmation确认请求弹框.

幸运的是,你可以实现上面的诉求通过代理协议WKUIDelegate: 设置webView的UI delegate, 你就可以显示定制的alerts, 管理你的tabs, 等.

首先,设置类遵循协议WKUIDelegate:

class ViewController: UIViewController, WKUIDelegate {

接着,指派webView的uiDelegate属性为当前对象:

webView.uiDelegate = self

最后,实现WKUIDelegate的方法.
举个?,通过WKWebView显示alert controller, 当html页面用JavaScript的方法alert():

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 显示text input控件,索取用户反馈, 等等.

注意: 在执行结束后,你必须调用completion handler. JavaScript’s alerts会被阻塞, 这就意味着JavaScript execution不会显示Alert页面直到completion handler 结束. 结果是, WebKit会投诉如果你不告诉它已经处理完毕,告诉的方法就是completionHandler().

func showingAlertUI() {
    webView.evaluateJavaScript("alert('boom');", completionHandler: nil)

14. 快照页面的一部分(也可以全部)

虽然你可以用方法drawHierarchy(),把view转换为image, WebKit可以用方法takeSnapshot()剪切任意大小的image.

举个?,可以从左上角开始剪切150x50 image, 并把剪切的页面当做subView显示于view上面:

func snapshotPartOfThePage() {
   let config = WKSnapshotConfiguration()
    config.rect = CGRect(x: 0, y: 200, width: 150, height: 50)
    webView.takeSnapshot(with: config) { (image, error) in
        if let image = image {
            print(image.size)
            let imageView = UIImageView(image: image)
            self.view.addSubview(imageView)

如果你要截屏整个view – 把cofnig改为nil即可.

15. 检测数据

WebViews已经支持数据类型检测, 比如电话号码 phone numbers, 日历事件calendar events, 航班号码flight numbers都可以编程可点击的链接 tappable links.

上面数据类型默认是普通文本, 但是可以被覆盖 – 当你创建webView时候 ,定制参数对象WKWebViewConfiguration.

举个?, 这里命令webView去检测所有可能地数据类型:

let config = WKWebViewConfiguration()
config.dataDetectorTypes = [.all]
let webView = WKWebView(frame: .zero, configuration: config)
 

结果截图,可以对比第3小节的截图
在这里插入图片描述

16. webview中遇到的问题

_blank 问题:

a便签中如果有_blank属性,表示在新的窗口打开页面,但是我们打不开,解决办法是添加如下代理的实现,直接在当前窗口加载url

-(WKWebView )webView:(WKWebView )webView createWebViewWithConfiguration:(WKWebViewConfiguration )configuration forNavigationAction:(WKNavigationAction )navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
if (!navigationAction.targetFrame.isMainFrame) {
    [webView loadRequest:navigationAction.request];
return nil;

cookie问题、白屏问题

参考 WKWebView 那些坑解决的,都有不错的解决方法

17. WKWebview代理

WKWebView有两个代理,WKUIDelegate 和 WKNavigationDelegate。WKNavigationDelegate主要处理一些跳转、加载处理操作;WKUIDelegate主要处理UI相关的操作:确认框,警告框,提示框。因此WKNavigationDelegate更加常用。下面是WKNavigationDelegate的代理列表:

///二、页面是否加载 ,相当于shouldStartLoadWithRequest

- (void) webView: (WKWebView *) webView decidePolicyForNavigationAction: (WKNavigationAction*) navigationAction decisionHandler: (void (^)(WKNavigationActionPolicy)) decisionHandler
    //允许跳转
    decisionHandler(WKNavigationResponsePolicyAllow);
    //不允许跳转
    //decisionHandler(WKNavigationResponsePolicyCancel);

///三、页面开始加载

- (void)webView:(WKWebView*)webView didStartProvisionalNavigation:(WKNavigation*)navigation

///四、收到响应

- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler 
    //允许跳转
    decisionHandler(WKNavigationResponsePolicyAllow);
    //不允许跳转
    //decisionHandler(WKNavigationResponsePolicyCancel);

///五、收到数据

- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation 

///六、页面加载完成

- (void)webView:(WKWebView*)webView didFinishNavigation:(WKNavigation*)navigation

///七、页面加载失败

- (void)webView:(WKWebView*)theWebView didFailNavigation:(WKNavigation*)navigation withError:(NSError*)error

/// 八、跳转失败

- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error

/// 九、重定向

- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation

///十、这个目的解决白屏问题 (ios9以上)

- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView API_AVAILABLE(macosx(10.11), ios(9.0))
    [self loadRequestWithUrl:self.strCurrentURL];

WKUIDelegate有下面三个代理:

- (void)                        webView:(WKWebView*)webView
     runJavaScriptAlertPanelWithMessage:(NSString*)message
                       initiatedByFrame:(WKFrameInfo*)frame
                      completionHandler:(void (^)(void))completionHandler
- (void)                        webView:(WKWebView*)webView
   runJavaScriptConfirmPanelWithMessage:(NSString*)message
                       initiatedByFrame:(WKFrameInfo*)frame
                      completionHandler:(void (^)(BOOL result))completionHandler
- (void)                        webView:(WKWebView*)webView
  runJavaScriptTextInputPanelWithPrompt:(NSString*)prompt
                            defaultText:(NSString*)defaultText
                       initiatedByFrame:(WKFrameInfo*)frame
                      completionHandler:(void (^)(NSString* result))completionHandler

https://github.com/zgpeace/WKWebViewGuide

https://www.hackingwithswift.com/articles/112/the-ultimate-guide-to-wkwebview
http://www.cnblogs.com/NSong/p/6489802.html
https://jianli2017.top/wiki/Hybird/webview/gome-Webview/

语言: swift, 版本:4.2,XCode:10.2写作时间:2019-04-23WKWebViewWKWebView在iOS 8 以后提供的高性能的Web容器. 本文列举15个最常用的用法。1. 创建一个WKWebView覆盖全屏在viewDidLoad() 中创建WKWebView,并增加为view的subView或者直接替换掉view. 这样做的弊端是,后续想要用到WKWebV...
NSRectscreenRect = [[NSScreen mainScreen] frame]; CGFloat w =screenRect.size.width; CGFloat h =screenRect.size.height; CGRect rect=  CGRectMake(0, 0, w, h); NSWindow*fullScreenWindow= [super initW
目前iOS系统已经更新到iOS11,大多数项目向下兼容最多兼容到iOS8,因此,在项目中对WebView组件进行重构再封装时,打算直接舍弃UIWebView转用WKWebView。 如果你目前正在网上浏览关于WKWebView的一些文章,... 公众号从 3月2号 开始,总共发了 42 期小集合集,以及 130+ 篇文章; 微博话题 #iOS知识小集# 共收录 170+ 开发 tip; 发了一本 《JS-Native 交互书》,大家可以在公众号中留言 jn 获取下载地址; 和 老司机团队 及 SwiftGG团... 好像大概也许是一年前, Mac OS系统发布了深色模式外观, 看着挺刺激, 时至今日用着也还挺爽的 终于,随着iPhone11等新手机的发售, iOS 13系统也正式发布了, 伴随着手机版的深色模式也出现在了大众视野 我们这些iOS程序猿也有事情做了, 原有项目适配iOS13系统, 适配Dark Mode深色模式 虽然现在并没有要求强制适配Da...
我不生产代码,只是代码的搬运工!无意间看到一篇博客里面全是第三方,简直“丧心病狂”,能看到怀疑人生。总有一款适合你. ————————————————&gt; 在掘金上又看到一篇(这篇做了整理 有一些很少用到的蓝牙 陀螺仪 图表等):https://juejin.im/entry/589591c08d6d81005838f860 1、通过CocoaPods安装 AFNe...
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
matlab绘制函数图像 MATLAB (Matrix Laboratory) 是一种用于数值计算的高级编程语言和交互式环境,由 MathWorks 公司开发。它广泛用于算法开发、数据可视化、数据分析以及数值计算的高级技术计算语言和交互式环境。以下是一些 MATLAB 的基本特性和使用方式: 1. 基本语法 变量:MATLAB 中的变量不需要预先声明,直接赋值即可。 数组:MATLAB 使用方括号 [] 创建数组,数组索引从 1 开始。 运算符:包括加、减、乘、除、乘方等。 函数:MATLAB 有大量内置函数,也可以编写自定义函数。 2. 绘图 MATLAB 提供了丰富的绘图功能,如绘制线图、散点图、柱状图、饼图等。 matlab x = 0:0.01:2*pi; y = sin(x); plot(x, y); title('Sine Function'); xlabel('x'); ylabel('y'); 3. 数据分析 MATLAB 可以处理各种类型的数据,包括矩阵、向量、数组等,并提供了许多数据分析函数,如统计函数、信号处理函数等。 4. 脚本和函数
iOS 中的 WKWebView 是一个用于在应用程序中显示网页内容的控件。它是 WebKit 框架的一部分,提供了更先进的功能和性能,与 UIWebView 相比具有更好的效果。 WKWebView 支持现代 Web 技术,如 JavaScript、CSS 和 HTML5,并提供了更强大的性能和稳定性。它还支持多线程处理、JavaScript 与原生代码的交互、内容加载和显示的控制等功能。 你可以使用 WKWebView 来加载并显示网页内容,也可以通过配置 WKWebView 的属性和委托来实现更多的定制化和交互功能。例如,你可以监听网页加载进度、处理网页中的链接点击事件、注入 JavaScript 代码等。 要在你的 iOS 应用中使用 WKWebView,首先需要导入 WebKit 框架,并创建一个 WKWebView 实例。然后,通过设置 WKWebView 的属性和委托,来实现你想要的功能和交互。 希望这个简介对你有所帮助!如果你还有其他问题,我会尽力解答。