Swift使用WKWebView在iOS应用中调用Web的方法详解

这篇文章主要介绍了Swift使用WKWebView在iOS应用中调用Web的方法详解,使用WKWebView便等于使用和Safari中相同的JavaScript解释器,用来替代过去的UIWebView,需要的朋友可以参考下

自从iOS8开始,Apple引入了WKWebView欲代替UIWebView。相比而言,WKWebView消耗内从更少,功能也更加强大。让我们来看看WKWebView怎么使用吧!

0.初始化
(1)首先需要引入WebKit库

复制代码代码如下:

#import <WebKit/WebKit.h>

(2)初始化方法分为以下两种

复制代码代码如下:

// 默认初始化
- (instancetype)initWithFrame:(CGRect)frame;
// 根据对webview的相关配置,进行初始化
- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration NS_DESIGNATED_INITIALIZER;

(3)加载网页与HTML代码的方式与UIWebView相同,代码如下:

复制代码代码如下:

WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]];
[self.view addSubview:webView];

1. WKWebView的代理方法
(1) WKNavigationDelegate
该代理提供的方法,可以用来追踪加载过程(页面开始加载、加载完成、加载失败)、决定是否执行跳转。

复制代码代码如下:

// 页面开始加载时调用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;
// 当内容开始返回时调用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;
// 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;
// 页面加载失败时调用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;

页面跳转的代理方法有三种,分为(收到跳转与决定是否跳转两种)

复制代码代码如下:

// 接收到服务器跳转请求之后调用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;
// 在收到响应后,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
// 在发送请求之前,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;

(2)WKUIDelegate

复制代码代码如下:

// 创建一个新的WebView
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;

剩下三个代理方法全都是与界面弹出提示框相关的,针对于web界面的三种提示框(警告框、确认框、输入框)分别对应三种代理方法。下面只举了警告框的例子。

复制代码代码如下:

/**
 *  web界面中有弹出警告框时调用
 *
 *  @param webView           实现该代理的webview
 *  @param message           警告框中的内容
 *  @param frame             主窗口
 *  @param completionHandler 警告框消失调用
 */
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(void (^)())completionHandler;

(3)WKScriptMessageHandler
这个协议中包含一个必须实现的方法,这个方法是提高App与web端交互的关键,它可以直接将接收到的JS脚本转为OC或Swift对象。(当然,在UIWebView也可以通过“曲线救国”的方式与web进行交互,著名的Cordova框架就是这种机制)

复制代码代码如下:

// 从web界面中接收到一个脚本时调用
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;

2.修改Info.plist
注意从iOS9开始,凡是涉及到网络操作的,都要在Info.plist中加入:

3.加载网页
先要在ViewController 导入WebKit:

复制代码代码如下:

import WebKit

然后:

复制代码代码如下:

var webview = WKWebView()
override func viewDidLoad() {
  super.viewDidLoad()
    //创建wkwebview
    let webview = WKWebView(frame: CGRectMake(0, 0, self.view.frame.width, self.view.frame.height))
    //创建网址
    let url = NSURL(string: "http://www.jianshu.com/users/040395b7230c/latest_articles")
    //创建请求
    let request = NSURLRequest(URL: url!)
    //加载请求
    webview.loadRequest(request)
    //添加wkwebview
    self.view.addSubview(webview)
}

运行效果如图:

4.获取网页标题
为了显示标题,首先给ViewController嵌入一个NavigationController。有了导航栏后,我们要调整一下webview的y轴位置,防止导航栏遮住网页上面部分,在viewDidLoad()里写上:

复制代码代码如下:

//获取导航栏高度
let navHeight = self.navigationController?.navigationBar.frame.height
//获取状态栏高度
let statusHeight = UIApplication.sharedApplication().statusBarFrame.height
webview = WKWebView(frame: CGRectMake(0, statusHeight+navHeight!,self.view.frame.width, self.view.frame.height))

其次,这里要用到WKNavigationDelegate,所以在viewDidLoad()里加上

复制代码代码如下:

self.webview.navigationDelegate = self

注意网页标题要在网页加载完成后才能获取,否则为空,于是我们用到‘处理网页加载完成‘这个方法:

复制代码代码如下:

func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
    self.navigationItem.title = self.webview.title
  }

运行效果如图:

5.前进和后退
首先我们要在navgationBar上添加前进和后退按钮:

复制代码代码如下:

var btnBack = UIBarButtonItem()
var btnForward = UIBarButtonItem()
func setNavBar() {
  btnBack = UIBarButtonItem(title: "后退", style: UIBarButtonItemStyle.Plain, target: self, action: "toBack")
  btnForward = UIBarButtonItem(title: "前进", style: UIBarButtonItemStyle.Plain, target: self, action: "toForward")
  self.navigationItem.leftBarButtonItem = btnBack
  self.navigationItem.rightBarButtonItem = btnForward
  }

然后我们用到了goBack()和goForward()方法,在前进或后退之前我们要判断一下网页是否能够前进或后退:

复制代码代码如下:

func toBack() {
   if self.webview.canGoBack {
     self.webview.goBack()
    }
  }

func toForward() {
  if self.webview.canGoForward {
    self.webview.goForward()
    }
}

最后在viewDidLoad()里加上调用setNavBar()方法:

复制代码代码如下:

setNavBar()

运行效果如图:

6.修改网页配置
现在,一个看似很简单的浏览器完成了,但如果我们把网址换成:
http://csol2.tiancity.com/homepage/article/Class_1166_Time_1.html
即在viewDidLoad()里修改:

复制代码代码如下:

let url = NSURL(string: "http://csol2.tiancity.com/homepage/article/Class_1166_Time_1.html")

我们会发现网页上列表里的文字,包括顶栏上的文字点击了没反应,问题出在哪里呢?这是因为系统阻止了不安全的连接。怎么解决呢?我们就要用到WKUIDelegate中的createWebViewWithConfiguration()这个方法让其允许导航,首先我们要设置自身代理,在viewDidLoad()里加上:

复制代码代码如下:

self.webview.UIDelegate = self

其次:

复制代码代码如下:

func webView(webView: WKWebView, createWebViewWithConfiguration configuration: WKWebViewConfiguration, forNavigationAction navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
     //如果目标主视图不为空,则允许导航
  if !(navigationAction.targetFrame?.mainFrame != nil) {
    self.webview.loadRequest(navigationAction.request)
    }
  return nil
  }

运行一下,发现点击跳转了!

7.处理js的提示框
现在把网址修改为

http://evt.tiancity.com/csol2/1565/home/index.php
即在viewDidLoad()里修改:

复制代码代码如下:

let url = NSURL(string: "http://evt.tiancity.com/csol2/1565/home/index.php")

往下拉,点击‘立即领取‘,本应该出现提示框,却发现什么也没发生。为此,我们要处理一下js的提示框事件。还记得一开始提到的那个方法吧,如下:

复制代码代码如下:

func webView(webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: () -> Void) {
  let alert = UIAlertController(title: nil, message: message, preferredStyle: .Alert)
  alert.addAction(UIAlertAction(title: "Ok", style: .Default, handler: { (_) -> Void in
    completionHandler()
    }))
   self.presentViewController(alert, animated: true, completion: nil)
  }

这里要创建一个警告框来显示,现在再运行一下看看?!

8.添加进度条
我们知道UIWebView是无法获取网页加载的进度的,于是也就无法创建进度条了,当然我们可以以某种算法模拟网页加载,自己设置进度条的值。而WKWebView却提供了获取网页加载进度的方法,支持KVO,也就是estimatedProgress。另外还有loading是否正在加载和title页面标题。
我们得创建一个进度条:

复制代码代码如下:

var progBar = UIProgressView()
//以下代码添加到viewDidLoad()
progBar = UIProgressView(frame: CGRectMake(0, 0, self.view.frame.width, 30))
  progBar.progress = 0.0
  progBar.tintColor = UIColor.redColor()
  self.webview.addSubview(progBar)

然后给网页添加监听进度,同样在viewDidLoad()里:

复制代码代码如下:

self.webview.addObserver(self, forKeyPath: "estimatedProgress", options: NSKeyValueObservingOptions.New, context: nil)

再处理KVO:

复制代码代码如下:

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
  if keyPath == "estimatedProgress" {
    self.progBar.alpha = 1.0
    progBar.setProgress(Float(webview.estimatedProgress), animated: true)
         //进度条的值最大为1.0
     if(self.webview.estimatedProgress >= 1.0) {
      UIView.animateWithDuration(0.3, delay: 0.1, options: UIViewAnimationOptions.CurveEaseInOut, animations: { () -> Void in
        self.progBar.alpha = 0.0
        }, completion: { (finished:Bool) -> Void in
          self.progBar.progress = 0
        })
      }
    }
}

这里设置进度条的值很重要,因为我们发现,其实进度条的值总比网页加载的实际值慢一些,两者并不同步。如果你不添加动画使进度条加载完成后消失,你会发现进度条还没到最右边中途就不见了。所以我们要用个动画来实现。此外,如果把self.progBar.progress = 0这句语句,即清零的功能放到别的方法中去,比如说放到开始导航的时候来清零,你会发现进度条的动画有问题,会来回转。总之,怎么处理进度条的动画很讲究,我试了好多次发现这个方法相对来说稳定一些。所以我建议大家可以换个进度条的样式,即不依赖于值的显示,如可以转圈圈等等。现在有好多第三方库可以使用,大家可以上cocoapods去查找。

还有一点别忘了,对于KVO模式,有add一定要remove,否则会崩溃。我们可以在视图消失的时候添加remove:

复制代码代码如下:

override func viewWillDisappear(animated: Bool) {
  webview.removeObserver(self, forKeyPath: "estimatedProgress")
  }

大家可以换些网址试试!

9.最终效果图

10.总结
WKWebView的简单使用就介绍到这里了!大家有兴趣可以为其添加更多功能!如果喜欢本文的话别忘了点击喜欢哦!

后记
既然说WKWebView相比UIWebView消耗的内存更少,那么我们就来实际对比一下,我们让它们加载同一个网站,结果如图
(左为UIWebView,右为WKWebView):

时间: 2024-10-25 17:22:03

Swift使用WKWebView在iOS应用中调用Web的方法详解的相关文章

oc中字典的实现方法详解

一:字典的基本概念 Foundation中的字典(NSDictionary,NSMutableDictionary)是由键-值对组成的数据集合.正如,我们在字典里查找单词的定义一样. 通过key(键),查找的对应的value(值),key通常是字符串对象,也可以是其他任意类型对象.在一个字典对象中,key的值必须是唯一的. 此外,字典对象的键和值不可以为空(nil),如果需要在字典中加入一个空值,可以加入NSNull对象 二:不可变字典-NSDictionary 1:初始化(以一个元素和多个元素

并发编程(六)Object类中线程相关的方法详解

一.notify() 作用:唤醒一个正在等待该线程的锁的线程 PS : 唤醒的线程不会立即执行,它会与其他线程一起,争夺资源 /** * Object类的notify()和notifyAll()方法详解 */ public class MyNotify { // 在多线程间共享的对象上使用wait private String[] shareObj = {"true"}; public static void main(String[] args) { MyNotify test =

iOS中 三种随机数方法详解

ios 有如下三种随机数方法: 1 2 3 4 5 6 7 8 9 10 //第一种 srand((unsigned)time(0)); //不加这句每次产生的随机数不变 int i = rand() % 5; //第二种 srandom(time(0)); int i = random() % 5; //第三种 int i = arc4random() % 5 ; 注: ① rand()和random()实际并不是一个真正的伪随机数发生器,在使用之前需要先初始化随机种子,否则每次生成的随机数一

iOS开发中的UDID和UUID详解

今天突然想和大家聊聊UDID和UUID的问题,虽然平时我们对这两个东西很忽视,往往也很难区分这两个东西.今天就来好好谈谈. [UDID] UDID的全名为 Unique Device Identifier :设备唯一标识符.从名称上也可以看出,UDID这个东西是和设备有关的,而且是只和设备有关的,有点类似于MAC地址.我在上一篇博客中<iOS应用发布流程详解>提到了真机调试,然后需要把UDID这个东西添加到Provisoning Profile授权文件中,也就是把设备唯一标识符添加进去,以此来

iOS开发中MVC、MVVM模式详解

iOS中的MVC(Model-View-Controller)将软件系统分为Model.View.Controller三部分 Model: 你的应用本质上是什么(但不是它的展示方式) Controller:你的Model怎样展示给用户(UI逻辑) View:用户看到的,被Controller操纵着的 Controller可以直接访问Model,也可以直接控制View. 但Model和View不能互相通信. View可以通过action-target的方式访问Controller,比如我们在Sto

JSP中的内置对象和Struts中的Web资源的详解

JSP中的内置对象有如下几种: request :继承于HttpServletRequest, HttpServletRequest继承ServletRequest, 获得的Request对象的方法:只能在Servlet中获取的doGet()和doPost()方法中获取 作用:封装用户请求信息 response   : 继承于HttpServletResponse,   HttpServletResponse继承ServletResponse 获得response对象的方法:只能在Servlet

PHP 中 16 个魔术方法详解

前言 PHP中把以两个下划线__开头的方法称为魔术方法(Magic methods),这些方法在PHP中充当了举足轻重的作用. 魔术方法包括: __construct(),类的构造函数 __destruct(),类的析构函数 __call(),在对象中调用一个不可访问方法时调用 __callStatic(),用静态方式中调用一个不可访问方法时调用 __get(),获得一个类的成员变量时调用 __set(),设置一个类的成员变量时调用 __isset(),当对不可访问属性调用isset()或emp

C语言中宏定义使用方法详解

C语言中的宏替换详解 首先看一个问题: #include <stdio.h> #define    PRINT_CLINE()    printf("%d", ______) int main(void) { PRINT_CLINE(); PRINT_CLINE(); return 0; } 在横线处填上适当的代码,使得上面这段代码的输出为34. 我想一般人看到这个问题的时候头脑里都没有明确的思路来解答这个它.我看到这个问题的时候想出了各种办法来解答它,最终还是没有通过编译

[51单片机] Keil C51中变量的使用方法详解

引言    8051内核单片机是一种通用单片机,在国内占有较大的市场份额.在将C语言用于51内核单片机的研究方面,Keil公司做得最为成功.由于51内核单片机的存储结构的特殊性,Keil C51中变量的使用与标准C有所不同.正确地使用变量,有利于获得高效的目标代码.下面详细介绍Keil C51中变量的使用方法. 1 CPU存储结构与变量的关系    变量都需要有存储空间,存储空间的不同使得变量使用时的工作效率也不同.    标准C的典型运行环境是8086(含IA-32系列)内核,其存储结构是CP