在本文中,我们将为您详细介绍WKWebView在Safari中打开来自某些域的链接的相关知识,并且为您解答关于选择在safari中打开的疑问,此外,我们还会提供一些关于BAWKWebViewBAWKW
在本文中,我们将为您详细介绍WKWebView在Safari中打开来自某些域的链接的相关知识,并且为您解答关于选择在safari中打开的疑问,此外,我们还会提供一些关于BAWKWebView BAWKWebView 分类封装 WKWebView、ios uiwebview wkwebview注意点小记、iOS UIWebView 和 WKWebView 的 cookie 获取,设置,删除、IOS UIWebView:在safari中打开链接的有用信息。
本文目录一览:- WKWebView在Safari中打开来自某些域的链接(选择在safari中打开)
- BAWKWebView BAWKWebView 分类封装 WKWebView
- ios uiwebview wkwebview注意点小记
- iOS UIWebView 和 WKWebView 的 cookie 获取,设置,删除
- IOS UIWebView:在safari中打开链接
WKWebView在Safari中打开来自某些域的链接(选择在safari中打开)
在我的应用程序中,我想在WKWebView中从 我的 域(例如:communionchapelefca.org)内打开链接,然后在Safari中打开来自
其他 域(例如:google.com)的链接。我希望以编程方式执行此操作。
我已经找到了一些关于Stack溢出的解决方案,但是它们似乎都是基于Obj-C的,我正在寻找使用Swift的解决方案。
ViewController.swift:
import UIKitimport WebKitclass ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let myWebView:WKWebView = WKWebView(frame: CGRectMake(0, 0, UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height)) myWebView.loadRequest(NSURLRequest(URL: NSURL(string: "http://www.communionchapelefca.org/app-home")!)) self.view.addSubview(myWebView)
答案1
小编典典您可以实现WKNavigationDelegate
,添加decidePolicyForNavigationAction
方法,然后在其中检查navigationType和所请求的url。我在下面使用了
**google.com** ,但您可以将其更改为您的域:
Xcode 8.3•Swift 3.1或更高版本
import UIKitimport WebKitclass ViewController: UIViewController, WKNavigationDelegate { let webView = WKWebView() override func viewDidLoad() { super.viewDidLoad() webView.frame = view.bounds webView.navigationDelegate = self let url = URL(string: "https://www.google.com")! let urlRequest = URLRequest(url: url) webView.load(urlRequest) webView.autoresizingMask = [.flexibleWidth,.flexibleHeight] view.addSubview(webView) } func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { if navigationAction.navigationType == .linkActivated { if let url = navigationAction.request.url, let host = url.host, !host.hasPrefix("www.google.com"), UIApplication.shared.canOpenURL(url) { UIApplication.shared.open(url) print(url) print("Redirected to browser. No need to open it locally") decisionHandler(.cancel) } else { print("Open it locally") decisionHandler(.allow) } } else { print("not a user click") decisionHandler(.allow) } }}
BAWKWebView BAWKWebView 分类封装 WKWebView
BAWKWebView BAWKWebView 介绍
BAWKWebView
-
1、用分类封装 WKWebView,代码无任何侵入更改
-
2、用 block 方式实现所需代理回调,更加方便,代码更简洁
-
3、一行代码搞定 request、URL、URLString、本地 HTML文件、HTMLString等请求
-
4、一个 block 搞定 title、progress、currentURL、当前网页的高度等等所需
-
5、有博爱封装好的 BAWebViewController 可以直接使用,也可以参考自定义浏览器【参考demo】
-
6、WKWebView 自定义 request post 数据到 JS(使用分类)
-
7、WKWebView OC 拦截 JS URL 处理,详见demo
-
8、修复 WKWebView 中的 alert 不能弹出的 bug!(详见 demo5)
-
9、新增 cell 中 WKWebView 高度自适应 demo(demo 有小部分遗留问题待解决)
-
10、自定义修改 navigator.userAgent(详见 demo BAWebViewController)
BAWKWebView BAWKWebView 官网
https://github.com/BAHome/BAWKWebView
ios uiwebview wkwebview注意点小记
概述
wkwebview是苹果公司推出的替代uiwebview的方案,它在内存占用和稳定性方面有很大的优势,性能对比此篇文章就不讲了。
但是就目前情况而言,uiwebview还有有一些不能被完全替代的原因,比如wkwebview无法用NSURLProtocol拦截请求,因此无法通过NSURLProtocol实现加载离线化资源。
本文主要是记录自己在使用的时候碰到的一些坑。
方法注入
uiwebview目前的方式就是直接通过JS定义方法,然后使用JSC来获得JS方法的回调。
wkwebview可以直接使用addScriptMessageHandler来添加需要监听的方法,然后在userContentController中处理监听事件。
主要的区别是,uiwebview的注入只对当前界面生效,在加载新的url或者界面刷新后就会失效。而wkwebview的注入对整个wkwebview生效,界面刷新不会对其有影响。
所以在uiwebview上如果有注入全局方法的需求,通过直接运行JS代码注入不可行,一般可以使用拦截自定scheme和host的方式来做方法注入。
cookie
uiwebview的cookie与NSHTTPCookieStorage 同步,每次访问都会带上NSHTTPCookieStorage 中的内容,包括在页面中输入document.cookie也能获取到NSHTTPCookieStorage 中的cookie。
wkwebview不是及时同步
但是wkwebview的cookie和NSHTTPCookieStorage 就不能及时同步,注意是不能及时同步,并不是不同步。主要体现在以下两个方面:
1、当NSHTTPCookieStorage 的中的cookie被修改了,cookie是会同步到wkwebview的,但是不是及时同步的,比如说我修改了NSHTTPCookieStorage的值之后然后马上打开一个wkwebview,wkwebview不一定能获取到我刚刚修改的cookie。
2、当我使用document.cookie在wkwebview中设置cookie的时候,我当前设置的cookie是会回写到NSHTTPCookieStorage中,但是也不是及时的。
由于不及时同步,我们就说一下可能会有的问题,举例两个场景:
1、wkwebview没有获取到cookie,然后触发登陆逻辑后修改NSHTTPCookieStorage 跳回wkwebview,这时候wkwebview很有可能还是没有cookie的,因为wkwebview的cookie不是及时同步的。
2、某一模块为了满足自己的需求,修改了NSHTTPCookieStorage 中的一个cookie,而这个cookie刚好和其他模块重名了,由于wkwebview会回写cookie到NSHTTPCookieStorage 中,因此它会把原来这个名字的cookie给覆盖掉。而不仅仅存在cookie的value被修改,导致其他模块cookie错误的的问题,如果expire被修改了,也同时会给其他模块带去cookie过期的问题。
wkwebview对cookie的处理
目前网上的处理方法主要有以下两种:
1、在webview发起请求的时候附带cookie。
2、在webview创建的时候js注入cookie。
这两个方法都能解决wkwebview不能及时同步NSHTTPCookieStorage 的问题,但是无法解决wkwebview的cookie修改后不能及时回写到NSHTTPCookieStorage 的问题。
还是举个例子:
第一个wkwebview中的JS修改了一段cookie之后,没过多久又打开了第二个wkwebview,第二个wkwebview是很可能获取不到第一个wkwebview对cookie的修改的。最根本原因就是由于wkwebview的cookie无法及时回写到NSHTTPCookieStorage 。
那么这种情况如何解决呢?答案就是wkProcessPool。
WKProcessPool
使用同一个WKProcessPool的wkwebview可以共享cookie数据,但是WKProcessPool中的cookie并不和NSHTTPCookieStorage 一样会本地存储。在APP重启后WKProcessPool中的cookie会被重置。
cookie仍然存在的问题
1、 第一个wkwebview中的JS修改了一段cookie之后,没过多久又打开了一个uiwebview,uiwebview如何能及时同步到wkwebview对cookie的修改?
2、如果某个模块在wkwebview中修改了cookie的值,导致NSHTTPCookieStorage 中的cookie被篡改或者过期,如何定位到该模块的问题?
iOS UIWebView 和 WKWebView 的 cookie 获取,设置,删除
Cookie简介 说到Cookie,或许有些小伙伴会比较陌生,有些小伙伴会比较熟悉。如果项目中,所有页面都是纯原生来实现的话,一般Cookie这个东西或许我们永远也不会接触到。但是,这里还是要说一下Cookie,因为它真的很重要,由它产生的一些坑也很多。
Cookie 在 web中应用比较多,主要是记录一个状态,比如我在网页上登录了,我就可以拿到网页登录后 Cookie,下次再 Cookie 的生效期内我就可以不用输入账号密码,直接跳转登录状态,在App中,Cookie最常用的也就是维持登录状态了.因为笔者最近就在做这个,其中也遇到过很多坑,这里说先踩坑和用法
iOS Cookie 的管理
NSHTTPCookie和NSHTTPCookieStorage iOS中进行HTTP网络请求Cookie管理主要由两个类负责,一个类是NSHTTPCookieStorage类,一个是NSHTTPCookie类。
NSHTTPCookieStorage
NSHTTPCookieStorage类采用单例的设计模式,其中管理着所有HTTP请求的Cookie信息 官方解释:NSHTTPCookieStorage 是一个用来管理 cookie 存储的单例。一个 NSHTTPCookie 单例代表一个 cookie。通常来讲,cookie 可以在应用间共享,并且在进程之间保持同步。 对于单进程,Session cookies (这里的 cookie 对象的 isSessionOnly 方法返回 YES
)是局部的并且不能被共享。
常用方法
// 获取单例对象
+ (NSHTTPCookieStorage *)sharedHTTPCookieStorage;
// 所有Cookie数据数组 其中存放NSHTTPCookie对象
@property (nullable , readonly, copy) NSArray<NSHTTPCookie *> *cookies;
// 手动设置一条Cookie数据
- (void)setCookie:(NSHTTPCookie *)cookie;
// 删除某条Cookie信息
- (void)deleteCookie:(NSHTTPCookie *)cookie;
// 删除某个时间后的所有Cookie信息 iOS8后可用
- (void)removeCookiesSinceDate:(NSDate *)date NS_AVAILABLE(10_10, 8_0);
// 获取某个特定URL的所有Cookie数据
- (nullable NSArray<NSHTTPCookie *> *)cookiesForURL:(NSURL *)URL;
// 为某个特定的URL设置Cookie
- (void)setCookies:(NSArray<NSHTTPCookie *> *)cookies forURL:(nullable NSURL *)URL mainDocumentURL:(nullable NSURL *)mainDocumentURL;
// Cookie数据的接收协议
枚举如下:
typedef NS_ENUM(NSUInteger, NSHTTPCookieAcceptPolicy) {
NSHTTPCookieAcceptPolicyAlways, //接收所有Cookie信息
NSHTTPCookieAcceptPolicyNever, //不接收所有Cookie信息
NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain //只接收主文档域的Cookie信息
};
@property NSHTTPCookieAcceptPolicy cookieAcceptPolicy;
系统下面的两个通知与Cookie管理有关:
据说,在Mac OS是cookie可以共享的(Session cookies 不能共享),在Mac OS app中更改cookie的接收策略会影响到其他正在运行的在使用cookie storage的app.这时NSHTTPCookieStorage会发出两个通知:
// Cookie数据的接收协议改变时发送的通知
FOUNDATION_EXPORT NSString * const NSHTTPCookieManagerAcceptPolicyChangedNotification;
// 管理的Cookie数据发生变化时发送的通知
FOUNDATION_EXPORT NSString * const NSHTTPCookieManagerCookiesChangedNotification;
NSHTTPCookie介绍
NSHTTPCookie是具体的HTTP请求Cookie数据对象.
// 下面两个方法用于对象的创建和初始化 都是通过字典进行键值设置
- (nullable instancetype)initWithProperties:(NSDictionary<NSString *, id> *)properties;
+ (nullable NSHTTPCookie *)cookieWithProperties:(NSDictionary<NSString *, id> *)properties;
// 返回Cookie数据中可用于添加HTTP头字段的字典
+ (NSDictionary<NSString *, NSString *> *)requestHeaderFieldsWithCookies:(NSArray<NSHTTPCookie *> *)cookies;
// 从指定的响应头和URL地址中解析出Cookie数据
+ (NSArray<NSHTTPCookie *> *)cookiesWithResponseHeaderFields:(NSDictionary<NSString *, NSString *> *)headerFields forURL:(NSURL *)URL;
// Cookie数据中的属性字典
@property (nullable, readonly, copy) NSDictionary<NSString *, id> *properties;
// 请求响应的版本
@property (readonly) NSUInteger version;
// 请求相应的名称
@property (readonly, copy) NSString *name;
// 请求相应的值
@property (readonly, copy) NSString *value;
// 过期时间
@property (nullable, readonly, copy) NSDate *expiresDate;
// 请求的域名
@property (readonly, copy) NSString *domain;
//请求的路径
@property (readonly, copy) NSString *path;
// 是否是安全传输
@property (readonly, getter=isSecure) BOOL secure;
// 是否只发送HTTP的服务
@property (readonly, getter=isHTTPOnly) BOOL HTTPOnly;
// 响应的文档
@property (nullable, readonly, copy) NSString *comment;
// 相应的文档URL
@property (nullable, readonly, copy) NSURL *commentURL;
// 服务端口列表
@property (nullable, readonly, copy) NSArray<NSNumber *> *portList;
HTTP cookie的属性键 属性 | 解读
NSHTTPCookieName | Cookie的名字
NSHTTPCookieValue | Cookie的值
NSHTTPCookieOriginURL | 和域名一样,NSHTTPCookieDomain或NSHTTPCookieOriginURL必须指定一个值
NSHTTPCookieVersion | 接收器的版本
NSHTTPCookieDomain | 域名
NSHTTPCookiePath | Cookie 存放路径
NSHTTPCookieSecure | Cookie是否只应通过安全通道发送,设置Cookie的secure属性为true。
只会在HTTPS和SSL等安全协议中传输此类Cookie。默认为false
NSHTTPCookieComment | 包含Cookie的评论,只有有效的版本1的cookies或更高版本。 这头字段是可选的
NSHTTPCookieCommentURL | 接收器的评论URL
NSHTTPCookieDiscard | Cookie是否应在会议结束时丢弃NSString,字符串值必须是“true”或“假”。
这个字段是可选的。 默认为“假”,除非这是Cookie是第1版或以上,
NSHTTPCookieMaximumAge未指定,在这种情况下,它被假定为“TRUE”
NSHTTPCookieMaximumAge | NSString对象,包含一个整数,在Cookie内保持最多几秒 。
仅适用于第1版和更高版本的有效。 默认为“0”。 此字段是可选的
NSHTTPCookiePort | 接收机的端口
- UIWebView的 Cookie 机制
UIWebView 在浏览网页后会将网页中的 cookie 自动存入 NSHTTPCookieStorage 标准容器中,[NSHTTPCookieStorage sharedHTTPCookieStorage]这个单例管理,在后续访问中会将 cookie 自动带到 request 请求当中。并且在同一个app内多个UIWebView之间共享。
- webView 中获取 cookie
//加载成功
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *requestUrl = webView.request.URL.absoluteString;
NSLog(@" requestUrl: %@",requestUrl);
//设置原始 cookie 根据key 存储本地
NSMutableArray *cookieArray = [[NSMutableArray alloc] init];
//网页加载完成取出 cookies
NSArray *nCookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
NSHTTPCookie *cookie;
for (id c in nCookies) {
if ([c isKindOfClass:[NSHTTPCookie class]]) {
cookie=(NSHTTPCookie *)c;
//我这里是cookie存入字典中 去重
if ([cookie value]) {
//如果 vaule 值不为 nil 存入字典中,
[self.mutableDic setValue:[cookie value] forKey:[cookie name]];
}
//设置原始 cookie
NSMutableDictionary *cookieProperties = [NSMutableDictionary dictionary];
[cookieProperties setObject:cookie.name forKey:NSHTTPCookieName];
[cookieProperties setObject:cookie.value forKey:NSHTTPCookieValue];
[cookieProperties setObject:cookie.domain forKey:NSHTTPCookieDomain];
[cookieProperties setObject:cookie.path forKey:NSHTTPCookiePath];
[cookieProperties setObject:[[NSDate date] dateByAddingTimeInterval:2629743] forKey:NSHTTPCookieExpires];
[cookieArray addObject:cookieProperties];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
}
}
//cookie 存入本地
[[NSUserDefaults standardUserDefaults] setObject:cookieArray forKey:@"cookieArray"];
[[NSUserDefaults standardUserDefaults] synchronize];
//下面 cookie 去重是为了得到 key=Value;形式的字符串,这里由于我有需求这样做,实际中下面可以忽略
NSMutableString *cookieValue = [NSMutableString stringWithFormat:@""];
// cookie重复,先放到字典进行去重,再进行拼接
for (NSString *key in self.mutableDic) {
NSString *appendString = [NSString stringWithFormat:@"%@=%@;", key, [self.mutableDic valueForKey:key]];
[cookieValue appendString:appendString];
}
NSLog(@"######################## %@ ####################",cookieValue);
- 设置 cookie
NSMutableArray* cookieDictionary = [[NSUserDefaults standardUserDefaults] valueForKey:@"cookieArray"];
NSLog(@"cookie dictionary found is %@",cookieDictionary);
if (cookieDictionary)
{
for (NSInteger i = 0; i < cookieDictionary.count; i++)
{
NSLog(@"cookie found is %@",[cookieDictionary objectAtIndex:i]);
NSDictionary *cookieDic = [cookieDictionary objectAtIndex:i];
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieDic];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
}
}
//设置请求之前加载 cookie 确保 cookie 在请求头之前设置
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.URLString] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];
//加载网页
[self.webView loadRequest:request];
- 删除 cookie
// 清空 cookie
- (void)deleteCookie {
// 清空 cookie
NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *_tmpArray = [NSArray arrayWithArray:[cookieJar cookies]];
for (id obj in _tmpArray) {
[cookieJar deleteCookie:obj];
}
}
- WKWebView 的 Cookie 机制
NSURLCache和NSHTTPCookieStroage无法操作(WKWebView)WebCore进程的缓存和Cookie WKWebView实例将会忽略任何的默认网络存储器(NSURLCache, NSHTTPCookieStorage, NSCredentialStorage) 和一些标准的自定义网络请求类(NSURLProtocol,等等.),WKWebView实例不会把Cookie存入到App标准的的Cookie容器(NSHTTPCookieStorage)中,因为 NSURLSession/NSURLConnection等网络请求使用NSHTTPCookieStorage进行访问Cookie,所以不能访问WKWebView的Cookie,现象就是WKWebView存了Cookie,其他的网络类如NSURLSession/NSURLConnection却看不到。这是很多人的说法。 还有一种是说法是通过实践发现 WKWebView 实例其实也会将 Cookie 存储于 NSHTTPCookieStorage 中,但存储时机有延迟,因为WKWebView内也有cookie的容器,而且每隔一段时间就和app侧NSHTTPCookieStorage进行同步,而且这个同步是进程级别的同步,而且这个同步是单向。 至于以上两种说法,最终WKWebView Cookie 问题在于 WKWebView 发起的请求不会自动带上存储于 NSHTTPCookieStorage 容器中的 Cookie。
-
iOS11 iOS11 的 API 可以解决该问题,只要是存在 WKHTTPCookieStore 里的 cookie,WKWebView 每次请求都会携带,存在 NSHTTPCookieStorage 的cookie,并不会每次都携带。于是会发生首次 WKWebView 请求不携带 Cookie 的问题。
-
ios 11 WKWebView cookie 的注入
在执行 -[WKWebView loadReques:] 前将 NSHTTPCookieStorage 中的内容复制到 WKHTTPCookieStore 中,以此来达到 WKWebView Cookie 注入的目的。示例代码如下:
[self copyNSHTTPCookieStorageToWKHTTPCookieStoreWithCompletionHandler:^{
NSURL *url = [NSURL URLWithString:@"https://www.v2ex.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[_webView loadRequest:request];
}];
- (void)copyNSHTTPCookieStorageToWKHTTPCookieStoreWithCompletionHandler:(nullable void (^)())theCompletionHandler; {
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
WKHTTPCookieStore *cookieStroe = self.webView.configuration.websiteDataStore.httpCookieStore;
if (cookies.count == 0) {
!theCompletionHandler ?: theCompletionHandler();
return;
}
for (NSHTTPCookie *cookie in cookies)
{
[cookieStroe setCookie:cookie completionHandler:^{
if ([[cookies lastObject] isEqual:cookie])
{
!theCompletionHandler ?: theCompletionHandler();
return;
}
}];
}
}
-
ios11 之前 注入 Cookie 就是从之前保存 cookie 的 NSHTTPCookieStorage 中取出相关 Cookie,然后在再次请求访问的时候在 request 中注入 Cookie。注入Cookie同样有多种方式。
-
1.JS注入1
//取出 storage 中的cookie并将其拼接成正确的形式
NSArray<NSHTTPCookie *> *tmp = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
NSMutableString *jscode_Cookie = [@"" mutableCopy];
[tmp enumerateObjectsUsingBlock:^(NSHTTPCookie * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop)
{
NSLog(@"%@ = %@", obj.name, obj.value);
[jscode_Cookie appendString:[NSString stringWithFormat:@"document.cookie = ''%@=%@'';", obj.name, obj.value]];
}];
WKUserContentController* userContentController = WKUserContentController.new;
WKUserScript * cookieScript = [[WKUserScript alloc] initWithSource: @"" injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
[userContentController addUserScript:cookieScript];
WKWebViewConfiguration* webViewConfig = WKWebViewConfiguration.new;
webViewConfig.userContentController = userContentController;
WKWebView * webView = [[WKWebView alloc] initWithFrame:CGRectMake(/*set your values*/) configuration:webViewConfig];
- JS注入2
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
[webView evaluateJavaScript:@"document.cookie =''TeskCookieKey1=TeskCookieValue1'';" completionHandler:^(id result, NSError *error) {
//...
}];
}
- NSMutableURLRequest 注入Cookie
NSURL *url = request.URL;
NSMutableString *cookies = [NSMutableString string];
NSMutableURLRequest *requestObj = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];
NSArray *tmp = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
NSDictionary *dicCookies = [NSHTTPCookie requestHeaderFieldsWithCookies:tmp];
NSString *cookie = [self readCurrentCookie];
[requestObj setValue:cookie forHTTPHeaderField:@"Cookie"];
[_webView loadRequest:requestObj];
-(NSString *)readCurrentCookie
{
NSMutableDictionary *cookieDic = [NSMutableDictionary dictionary];
NSMutableString *cookieValue = [NSMutableString stringWithFormat:@""];
NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (NSHTTPCookie *cookie in [cookieJar cookies]) {
[cookieDic setObject:cookie.value forKey:cookie.name];
}
// cookie重复,先放到字典进行去重,再进行拼接
for (NSString *key in cookieDic) {
NSString *appendString = [NSString stringWithFormat:@"%@=%@;", key, [cookieDic valueForKey:key]];
[cookieValue appendString:appendString];
}
return cookieValue;
}
获取Cookie
由于 WKWebView 的 Cookie 存储容器 WKWebsiteDataStore 是私有存储,所以无法从这里获取到Cookie,目前的方法是(1)从网站返回的 response headerfields 中获取。(2)通过调用js的方法获取 cookie。
- 1.从网站返回的 response headerfields 中获取,因为cookie都存在http respone的headerfields,找到能获得respone的WKWebView回调,打印
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
NSArray *cookies =[NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:response.URL];
//读取wkwebview中的cookie 方法1
for (NSHTTPCookie *cookie in cookies) {
// [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
NSLog(@"wkwebview中的cookie:%@", cookie);
}
//读取wkwebview中的cookie 方法2 读取Set-Cookie字段
NSString *cookieString = [[response allHeaderFields] valueForKey:@"Set-Cookie"];
NSLog(@"wkwebview中的cookie:%@", cookieString);
//看看存入到了NSHTTPCookieStorage了没有
NSHTTPCookieStorage *cookieJar2 = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (NSHTTPCookie *cookie in cookieJar2.cookies) {
NSLog(@"NSHTTPCookieStorage中的cookie%@", cookie);
}
//下面是将 原始cookie本地 化
NSMutableArray *cookieArray = [[NSMutableArray alloc] init];
for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
NSMutableDictionary *cookieProperties = [NSMutableDictionary dictionary];
[cookieProperties setObject:cookie.name forKey:NSHTTPCookieName];
[cookieProperties setObject:cookie.value forKey:NSHTTPCookieValue];
[cookieProperties setObject:cookie.domain forKey:NSHTTPCookieDomain];
[cookieProperties setObject:cookie.path forKey:NSHTTPCookiePath];
[cookieProperties setObject:[NSNumber numberWithInt:cookie.version] forKey:NSHTTPCookieVersion];
[cookieProperties setObject:[[NSDate date] dateByAddingTimeInterval:2629743] forKey:NSHTTPCookieExpires];
[cookieArray addObject:cookieProperties];
}
[[NSUserDefaults standardUserDefaults] setValue:cookieArray forKey:@"cookieArray"];
[[NSUserDefaults standardUserDefaults] synchronize];
decisionHandler(WKNavigationResponsePolicyAllow);
}
// 页面加载完成之后调用需要重新给WKWebView设置Cookie防止因为a标签跳转,导致下一次跳转的时候Cookie丢失。
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
//取出cookie
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
//js函数
NSString *JSFuncString =
@"function setCookie(name,value,expires)\
{\
var oDate=new Date();\
oDate.setDate(oDate.getDate()+expires);\
document.cookie=name+''=''+value+'';expires=''+oDate+'';path=/''\
}\
function getCookie(name)\
{\
var arr = document.cookie.match(new RegExp(''(^| )''+name+''=({FNXX==XXFN}*)(;|$)''));\
if(arr != null) return unescape(arr[2]); return null;\
}\
function delCookie(name)\
{\
var exp = new Date();\
exp.setTime(exp.getTime() - 1);\
var cval=getCookie(name);\
if(cval!=null) document.cookie= name + ''=''+cval+'';expires=''+exp.toGMTString();\
}";
//拼凑js字符串
NSMutableString *JSCookieString = JSFuncString.mutableCopy;
for (NSHTTPCookie *cookie in cookieStorage.cookies) {
NSString *excuteJSString = [NSString stringWithFormat:@"setCookie(''%@'', ''%@'', 1);", cookie.name, cookie.value];
[JSCookieString appendString:excuteJSString];
}
//执行js
[webView evaluateJavaScript:JSCookieString completionHandler:^(id obj, NSError * _Nullable error) {
NSLog(@"%@",error);
}];
}
- 通过 JS 获取 cookie
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {
[webView evaluateJavaScript:[NSString stringWithFormat:@"document.cookie"] completionHandler:^(id _Nullable response, NSError * _Nullable error) {
if (response != 0) {
NSLog(@"\n\n\n\n\n\n document.cookie%@,%@",response,error);
}
}];
}
##注意 document.cookie 的方法获取 cookie并不支持跨越获取,如果设置 httponly则获取不到 cookie 不论是(1)还是(2)方法,似乎都无法解决302请求的 Cookie 问题。举例来说,假设你要访问网站A,在A中点击登录,跳转页面到B地址,在B中完成登录之后302跳转回A网站。此时cookie是存在于B地址的 response 中的,在A地址的 response 中并没有 cookie 的字段。然而我们只能获取到A地址的 response ,无法截获到B地址的response。因此获取不到该类型网站的 cookie 。 由于我并没有遇到302这样的问题,所有看了下网上的资料,希望对遇到这个问题的小伙伴一下办法,网上给出的解决办法是:
- 1.加载一个本地为空的html,域名指向你的第一次加载的url的域名。
//加载本地html
[self.webView loadHTMLString:@"" baseURL:[NSURL URLWithString:@"https:/a.com"]];
- 2.通过以下方法,在第一次加载完成后,将需要设置的Cookies设置到WKWebView中,因为是加载的本地的html以下方法会立即执行。
// 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
if (isFirstLoaded) {
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
//js函数
NSString *JSFuncString =
@"function setCookie(name,value,expires)\
{\
var oDate=new Date();\
oDate.setDate(oDate.getDate()+expires);\
document.cookie=name+''=''+value+'';expires=''+oDate+'';path=/''\
}";
//拼凑js字符串,按照自己的需求拼凑Cookie
NSMutableString *JSCookieString = JSFuncString.mutableCopy;
for (NSHTTPCookie *cookie in cookieStorage.cookies) {
if (![cookie.name isEqualToString:@"__cust"]) {
NSString *excuteJSString = [NSString stringWithFormat:@"setCookie(''%@'', ''%@'', 3);", cookie.name, cookie.value];
[JSCookieString appendString:excuteJSString];
}
}
//执行js
[webView evaluateJavaScript:JSCookieString completionHandler:^(id obj, NSError * _Nullable error)
{
//加载真正的第一次Request
[self loadRealRequest];
}];
}
}
如果cookie 存储到本地获取本地的 cookie
//修改从 storage 中读取 cookie 的方法
-(NSString *)readCurrentCookie{
NSMutableArray* cookieDictionary = [[NSUserDefaults standardUserDefaults] valueForKey:@"cookieArray"];
NSLog(@"cookie dictionary found is %@",cookieDictionary);
for (int i=0; i < cookieDictionary.count; i++) {
NSLog(@"cookie found is %@",[cookieDictionary objectAtIndex:i]);
NSMutableDictionary* cookieDictionary1 = [[NSUserDefaults standardUserDefaults] valueForKey:[cookieDictionary objectAtIndex:i]];
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieDictionary1];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
}
NSMutableDictionary *cookieDic = [NSMutableDictionary dictionary];
NSMutableString *cookieValue = [NSMutableString stringWithFormat:@""];
NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (NSHTTPCookie *cookie in [cookieJar cookies]) {
[cookieDic setObject:cookie.value forKey:cookie.name];
}
// cookie重复,先放到字典进行去重,再进行拼接
for (NSString *key in cookieDic)
{
NSString *appendString = [NSString stringWithFormat:@"%@=%@;", key, [cookieDic valueForKey:key]];
[cookieValue appendString:appendString];
}
return cookieValue;
}
清除 cookie
#pragma mark - 清空cookie
-(void)deleCookie {
// NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
// NSArray *_tmpArray = [NSArray arrayWithArray:[cookieJar cookies]];
// for (id obj in _tmpArray) {
// [cookieJar deleteCookie:obj];
// }
if (@available(iOS 9.0, *)) {//iOS9及以上
WKWebsiteDataStore *dateStore = [WKWebsiteDataStore defaultDataStore];
[dateStore fetchDataRecordsOfTypes:[WKWebsiteDataStore allWebsiteDataTypes]
completionHandler:^(NSArray<WKWebsiteDataRecord *> * __nonnull records)
{
for (WKWebsiteDataRecord *record in records)
{
//取消备注,可以针对某域名做专门的清除,否则是全部清除
//if ( [record.displayName containsString:@"baidu"])
//{
[[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:record.dataTypes
forDataRecords:@[record] completionHandler:^
{
NSLog(@"Cookies for %@ deleted successfully",record.displayName);
}];
//}
}
}];
}
else { //iOS9以下
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *cookiesFolderPath = [libraryPath stringByAppendingString:@"/Cookies"];
NSError *errors;
[[NSFileManager defaultManager] removeItemAtPath:cookiesFolderPath error:&errors];
}
}
##最后 UIWebView 和 WKWebView 所遇到问题 cookie 同步,获取,删除,设置这些问题,目前就这么多解决办法吧,我一开始尝试用 WKWebView 获取 cookie 但是最后遇到网页跨域问题以及低版本兼容问题我还是换回 UIWebView 了,如果有更好的解决办法可以在下面留言,谢谢!
来自:https://www.cnblogs.com/ningmengcao-ios/p/9578218.html
原文出处:https://www.cnblogs.com/benxiaokang/p/ios-uiwebview-he-wkwebview-de-cookie-huo-qu-she-zh.html
IOS UIWebView:在safari中打开链接
#import "showBlock.h" @implementation showBlock; @synthesize mainViewContObj; - (void) showView { UIWebView *aWebView = [[UIWebView alloc] initWithFrame:CGRectMake(0,320,50)]; aWebView.autoresizesSubviews = YES; aWebView.autoresizingMask = (UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth); [aWebView setDelegate:[self mainViewContObj]]; Nsstring *urlAddress = @"http://localhost/test/index.PHP"; NSURL *url = [NSURL URLWithString:urlAddress]; NSURLRequest *requestObj = [NSURLRequest requestWithURL:url]; [aWebView loadRequest:requestObj]; UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0,0)]; [[[self mainViewContObj] view] addSubview:aWebView]; } @end
它工作正常,并加载带有html内容的index.PHP文件,但我想在safari浏览器中打开这个html文件的链接,我需要做些什么呢?
解决方法
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { // This practically disables web navigation from the webView. if (navigationType == UIWebViewNavigationTypeLinkClicked) { [[UIApplication sharedApplication] openURL:[request URL]]; return FALSE; } return TRUE; }
今天关于WKWebView在Safari中打开来自某些域的链接和选择在safari中打开的分享就到这里,希望大家有所收获,若想了解更多关于BAWKWebView BAWKWebView 分类封装 WKWebView、ios uiwebview wkwebview注意点小记、iOS UIWebView 和 WKWebView 的 cookie 获取,设置,删除、IOS UIWebView:在safari中打开链接等相关知识,可以在本站进行查询。
本文标签: