一、引言
在iOS8之前,在应用中嵌入网页通常需要使用UIWebView这样一个类,这个类通过URL或者HTML文件来加载网页视图,功能十分有限,只能作为辅助嵌入原生应用程序中。虽然UIWebView也可以做原生与JavaScript交互的相关处理,然而也有很大的局限性,JavaScript要调用原生方法通常需要约定好协议之后通过Request来传递。WebKit框架中添加了一些原生与JavaScript交互的方法,增强了网页视图与原生的交互能力。并且WebKit框架中采用导航堆栈的模型来管理网页的跳转,开发者也可以更加容易的控制和管理网页的渲染。关于UIWebView的相关使用,在前面的博客中有详细介绍,地址如下。
UIWebView的使用详解:http://my.oschina.net/u/2340880/blog/469916。
二、WebKit框架概览
WebKit框架中涉及的类很多,框架的设计十分面向对象和模块化,开发者在使用时可以轻松的写出结构清晰的代码。在进行使用前,我们首先应该清楚整个框架的结构和开发思路,下面一张脑图中基本列出了WebKit框架中所涉及到的所有重要的类以及他们之间的相互关系:
如上图所示,WebKit框架中最核心的类应该属于WKWebView了,这个类专门用来渲染网页视图,其他类和协议都将基于它和服务于它。
WKWebView:网页的渲染与展示,通过WKWebViewConfiguration可以进行配置。
WKWebViewConfiguration:这个类专门用来配置WKWebView。
WKPreference:这个类用来进行M相关设置。
WKProcessPool:这个类用来配置进程池,与网页视图的资源共享有关。
WKUserContentController:这个类主要用来做native与JavaScript的交互管理。
WKUserScript:用于进行JavaScript注入。
WKScriptMessageHandler:这个类专门用来处理JavaScript调用native的方法。
WKNavigationDelegate:网页跳转间的导航管理协议,这个协议可以监听网页的活动。
WKNavigationAction:网页某个活动的示例化对象。
WKUIDelegate:用于交互处理JavaScript中的一些弹出框。
WKBackForwardList:堆栈管理的网页列表。
WKBackForwardListItem:每个网页节点对象。
三、使用WKWebViewConfiguration对WebView进行配置
使用下面的代码可以创建一个WKWebView视图,创建WebView视图时,需要使用WKWebViewConfiguration来进行配置:
WKWebView * WK;
WKWebViewConfiguration * config = [[WKWebViewConfiguration alloc]init];
WK = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height-40) configuration:config];
[WK loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]];
WKWebViewConfiguration中可以进行配置的方法和属性如下:
//设置进程池
WKProcessPool * pool = [[WKProcessPool alloc]init];
config.processPool = pool;
WKProcessPool类中没有暴露任何属性和方法,配置为同一个进程池的WebView会共享数据,例如Cookie、用户凭证等,开发者可以通过编写管理类来分配不同维度的WebView在不同进程池中。
//进行偏好设置
WKPreferences * preference = [[WKPreferences alloc]init];
//最小字体大小 当将javaScriptEnabled属性设置为NO时,可以看到明显的效果
preference.minimumFontSize = 0;
//设置是否支持javaScript 默认是支持的
preference.javaScriptEnabled = YES;
//设置是否允许不经过用户交互由javaScript自动打开窗口
preference.javaScriptCanOpenWindowsAutomatically = YES;
config.preferences = preference;
WKPerference实例为WebView提供一个偏好设置。
//设置内容交互控制器 用于处理JavaScript与native交互
WKUserContentController * userController = [[WKUserContentController alloc]init];
//设置处理代理并且注册要被js调用的方法名称
[userController addScriptMessageHandler:self name:@"name"];
//js注入,注入一个测试方法。
NSString *javaScriptSource = @"function userFunc(){window.webkit.messageHandlers.name.postMessage( {\"name\":\"HS\"})}";
WKUserScript *userScript = [[WKUserScript alloc] initWithSource:javaScriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];// forMainFrameOnly:NO(全局窗口),yes(只限主窗口)
[userController addUserScript:userScript];
config.userContentController = userController;
WKUserContentController专门用来管理native与JavaScript的交互行为,addScriptMessageHandler:name:方法来注册要被js调用的方法名称,之后再JavaScript中使用window.webkit.messageHandlers.name.postMessage()方法来像native发送消息,支持OC中字典,数组,NSNumber等原生数据类型,JavaScript代码中的name要和上面注册的相同。在native代理的回调方法中,会获取到JavaScript传递进来的消息,如下:
-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
//这里可以获取到JavaScript传递进来的消息
}
WKScriptMessage类是JavaScript传递的对象实例,其中属性如下:
//传递的消息主体
@property (nonatomic, readonly, copy) id body;
//传递消息的WebView
@property (nullable, nonatomic, readonly, weak) WKWebView *webView;
//传递消息的WebView当前页面对象
@property (nonatomic, readonly, copy) WKFrameInfo *frameInfo;
//消息名称
@property (nonatomic, readonly, copy) NSString *name;
WKUserContentController实例的addUserScript:用于注入JavaScript代码,后面会专门介绍。
//设置数据存储store
config.websiteDataStore = [WKWebsiteDataStore defaultDataStore];
WebKit框架采用其本身的缓存框架,WKWebsiteDataStore类用来处理数据的存储,其中属性和方法如下:
@interface WKWebsiteDataStore : NSObject
//获取默认的存储器 此存储器为持久性的会被写入磁盘
+ (WKWebsiteDataStore *)defaultDataStore;
//获取一个临时的存储器
+ (WKWebsiteDataStore *)nonPersistentDataStore;
//存储器是否是临时的
@property (nonatomic, readonly, getter=isPersistent) BOOL persistent;
//所有可以存储的类型
+ (NSSet<NSString *> *)allWebsiteDataTypes;
@end
//设置是否将网页内容全部加载到内存后再渲染
config.suppressesIncrementalRendering = NO;
//设置HTML5视频是否允许网页播放 设置为NO则会使用本地播放器
config.allowsInlineMediaPlayback = YES;
//设置是否允许ariPlay播放
config.allowsAirPlayForMediaPlayback = YES;
//设置视频是否需要用户手动播放 设置为NO则会允许自动播放
config.requiresUserActionForMediaPlayback = NO;
//设置是否允许画中画技术 在特定设备上有效
config.allowsPictureInPictureMediaPlayback = YES;
//设置选择模式 是按字符选择 还是按模块选择
/*
typedef NS_ENUM(NSInteger, WKSelectionGranularity) {
//按模块选择
WKSelectionGranularityDynamic,
//按字符选择
WKSelectionGranularityCharacter,
} NS_ENUM_AVAILABLE_IOS(8_0);
*/
config.selectionGranularity = WKSelectionGranularityCharacter;
//设置请求的User-Agent信息中应用程序名称 iOS9后可用
config.applicationNameForUserAgent = @"HS";
四、WKWebView中的属性和方法解析
下面列举了WKWebView中常用的属性和方法。
//设置导航代理
@property (nullable, nonatomic, weak) id <WKNavigationDelegate> navigationDelegate;
//设置UI代理
@property (nullable, nonatomic, weak) id <WKUIDelegate> UIDelegate;
//导航列表
@property (nonatomic, readonly, strong) WKBackForwardList *backForwardList;
//通过url加载网页视图
- (nullable WKNavigation *)loadRequest:(NSURLRequest *)request;
//通过文件加载网页视图
- (nullable WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessURL NS_AVAILABLE(10_11, 9_0);
//通过HTML字符串加载网页视图
- (nullable WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
//通过data数据加载网页视图
- (nullable WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL NS_AVAILABLE(10_11, 9_0);
//渲染导航列表中的某个网页节点
- (nullable WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item;
//网页标题
@property (nullable, nonatomic, readonly, copy) NSString *title;
//网页的url
@property (nullable, nonatomic, readonly, copy) NSURL *URL;
//网页是否正在加载中
@property (nonatomic, readonly, getter=isLoading) BOOL loading;
//加载进度 可以监听这个属性的值配合UIProgressView来设计进度条
@property (nonatomic, readonly) double estimatedProgress;
//是否全部是安全连接
@property (nonatomic, readonly) BOOL hasOnlySecureContent;
//证书列表
@property (nonatomic, readonly, copy) NSArray *certificateChain;
//是否可以回退
@property (nonatomic, readonly) BOOL canGoBack;
//是否可以前进
@property (nonatomic, readonly) BOOL canGoForward;
//回退网页
- (nullable WKNavigation *)goBack;
//前进网页
- (nullable WKNavigation *)goForward;
//刷新网页
- (nullable WKNavigation *)reload;
//忽略缓存的刷新
- (nullable WKNavigation *)reloadFromOrigin;
//停止加载
- (void)stopLoading;
//执行JavaScript代码
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ __nullable)(__nullable id, NSError * __nullable error))completionHandler;
//是否允许右滑返回手势
@property (nonatomic) BOOL allowsBackForwardNavigationGestures;
WKBackForwardList类为导航管理的网页列表类,其中属性方法意义如下:
@interface WKBackForwardList : NSObject
//当前所在的网页节点
@property (nullable, nonatomic, readonly, strong) WKBackForwardListItem *currentItem;
//前进的一个网页节点
@property (nullable, nonatomic, readonly, strong) WKBackForwardListItem *forwardItem;
//回退的一个网页节点
@property (nullable, nonatomic, readonly, strong) WKBackForwardListItem *backItem;
//获取某个index的网页节点
- (nullable WKBackForwardListItem *)itemAtIndex:(NSInteger)index;
//获取回退的节点数组
@property (nonatomic, readonly, copy) NSArray<WKBackForwardListItem *> *backList;
//获取前进的节点数组
@property (nonatomic, readonly, copy) NSArray<WKBackForwardListItem *> *forwardList;
@end
在WebKit中,网页节点被抽象成为了WKBackForwardListItem类,这个类中封装的属性如下:
@interface WKBackForwardListItem : NSObject
//当前节点的URL
@property (readonly, copy) NSURL *URL;
//当前节点的标题
@property (nullable, readonly, copy) NSString *title;
//创建此WebView的初始URL
@property (readonly, copy) NSURL *initialURL;