Skip to main content

WebKit

WKWebView

打开活动监视器,然后在模拟器打开 QB,会看到 WebKit 新创建了几个进程:

img

在一个客户端中,多个 WKWebView 实例共享一个 UI 进程(和 App 进程共享),共享一个 Networking 进程,每个 WKWebView 实例独享一个 Web 进程。

img

网页加载

Populating the page: how browsers work - Web performance | MDN

App 中的 Cookie 管理使用的 HTTPCookieStrorage,WKWebView 的 Cookie 管理使用的是 WKHttpCookieStore。这两个 Cookie 是可以同步的,但是同步会有明显的延迟。

对于 iOS 上,Cookie 文件有两种:

  • bundleID.binarycookies 这是 HttpCookieStorage 持久化的 Cookie
  • Cookies.binarycookies 这是 WKWebView 持久化的 Cookie

WebProcess 的 Cookie 如何同步到 App 进程?监听到 WKWebViewCookie 发生变化的时候,将 Cookie 同步到 App 进程。

func setupWebView() {
webView.configuration.websiteDataStore.httpCookieStore.add(self)
}

// WKHTTPCookieStoreObserver协议的方法
func cookiesDidChange(in cookieStore: WKHTTPCookieStore) {
cookieStore.getAllCookies { array in
array.forEach {
HTTPCookieStorage.shared.setCookie($0)
}
}
}

App 进程的 Cookie 如何同步到 WebProcess? HOOK NSHTTPCookieStorage 中读写 Cookie 的接口,并且监听网络请求中 "Set-Cookie" 关键字,在 App 进程 Cookie 发生变化时同步到 WKWebView。

Dark Mode

自己的网站想适配深色模式:sandoche/Darkmode.js: 🌓 Add a dark-mode / night-mode to your website in a few seconds

浏览器想对所有网站适配深色模式:darkreader/darkreader: Dark Reader Chrome and Firefox extension

网络请求拦截

网络请求拦截总是存在需求:缓存需求、监控需求、代理需求(大王卡免流)

重写 +[WKWebView handlesURLScheme:] 方法,将所有请求拦截:

+ (BOOL)handlesURLScheme:(NSString *)urlScheme {
return NO;
}

设置 -[WKWebViewConfiguration setURLSchemeHandler:forURLScheme:]

实现 @protocol WKURLSchemeHandler 的方法,用 NSURLSession 处理网络请求:

- (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask;
- (void)webView:(WKWebView *)webView stopURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask;

证书校验

NSURLProtectionSpace: A server or an area on a server, commonly referred to as a realm, that requires authentication.

Handling an authentication challenge | Apple Developer Documentation 服务器需要验证用户的身份,否则就会回 401 Forbidden。

Performing Manual Server Trust Authentication | Apple Developer Documentation(文章不长,多看几遍加深理解)

When you use a secure connection (such as https) with a URL request, your NSURLSessionDelegate receives an authentication challenge with an authentication type of NSURLAuthenticationMethodServerTrust. Unlike other challenges where the server is asking your app to authenticate itself, this is an opportunity for you to authenticate the server’s credentials.

- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *_Nullable credential))completionHandler {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
NSString *host = challenge.protectionSpace.host;
if ([host isEqualToString:@"127.0.0.1"]) {
SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
return;
}
}
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
}