Skip to content

Instantly share code, notes, and snippets.

@tyrad
Created May 3, 2020 03:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tyrad/b5abbc56a9b16393f988247ed9e3ee57 to your computer and use it in GitHub Desktop.
Save tyrad/b5abbc56a9b16393f988247ed9e3ee57 to your computer and use it in GitHub Desktop.
URLProtocol直接拦截wkwebview请求会有问题,一般推荐自定义scheme的方式
//
// NSObject+NSURLProtocol_Wk.h
// URLProtocolDemo
//
// Created by panda on 2020/4/26.
// Copyright © 2020 quicktouch. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSURLProtocol (NSURLProtocol_Wk)
+ (void)wk_registerScheme:(NSString *)scheme;
+ (void)wk_unregisterScheme:(NSString *)scheme;
@end
NS_ASSUME_NONNULL_END
//
// NSObject+NSURLProtocol_Wk.m
// URLProtocolDemo
//
// Created by panda on 2020/4/26.
// Copyright © 2020 quicktouch. All rights reserved.
//
#import "NSURLProtocol+Wk.h"
#import <WebKit/WebKit.h>
FOUNDATION_STATIC_INLINE Class ContextControllerClass() {
static Class cls;
if (!cls) {
cls = [[[WKWebView new] valueForKey:@"browsingContextController"] class];
}
return cls;
}
FOUNDATION_STATIC_INLINE SEL RegisterSchemeSelector() {
return NSSelectorFromString(@"registerSchemeForCustomProtocol:");
}
FOUNDATION_STATIC_INLINE SEL UnregisterSchemeSelector() {
return NSSelectorFromString(@"unregisterSchemeForCustomProtocol:");
}
@implementation NSURLProtocol (NSURLProtocol_Wk)
+ (void)wk_registerScheme:(NSString *)scheme {
Class cls = ContextControllerClass();
SEL sel = RegisterSchemeSelector();
if ([(id)cls respondsToSelector:sel]) {
// 放弃编辑器警告
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[(id)cls performSelector:sel withObject:scheme];
#pragma clang diagnostic pop
}
}
+ (void)wk_unregisterScheme:(NSString *)scheme {
Class cls = ContextControllerClass();
SEL sel = UnregisterSchemeSelector();
if ([(id)cls respondsToSelector:sel]) {
// 放弃编辑器警告
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[(id)cls performSelector:sel withObject:scheme];
#pragma clang diagnostic pop
}
}
@end
class WkUrlProtocolEx: URLProtocol, URLSessionDataDelegate, URLSessionTaskDelegate {
private var dataTask: URLSessionDataTask?
private var urlResponse: URLResponse?
private var receivedData: NSMutableData?
static var CustomKey: String {
return "myCustomKey"
}
// MARK: NSURLProtocol
override class func canInit(with request: URLRequest) -> Bool {
print(request.url ?? "")
if URLProtocol.property(forKey: WkUrlProtocolEx.CustomKey, in: request) != nil {
return false
}
return true
}
// override class func canInit(with task: URLSessionTask) -> Bool {
// return false
// }
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
let mutableRequest = ((request as NSURLRequest).mutableCopy() as? NSMutableURLRequest)!
if let requestUrl = request.url {
print(requestUrl.absoluteString)
if requestUrl.absoluteString.hasPrefix("zy") || requestUrl.absoluteString.hasPrefix("ZY") {
// 简单测试使用
let str = requestUrl.absoluteString
var reStr = str.replacingOccurrences(of: "zys:", with: "https:")
reStr = str.replacingOccurrences(of: "zy:", with: "http:")
mutableRequest.url = URL(string: reStr)!
}
}
// URLProtocol.setProperty(true, forKey: "", in: mutableRequest)
mutableRequest.addValue("Cookie_VALUE", forHTTPHeaderField: "Cookie")
return (mutableRequest as URLRequest)
}
override func startLoading() {
let newRequest = (self.request as NSURLRequest).mutableCopy() as! NSMutableURLRequest
print("加载远程资源:" + newRequest.url!.absoluteString)
URLProtocol.setProperty("true", forKey: WkUrlProtocolEx.CustomKey, in: newRequest)
let defaultConfigObj = URLSessionConfiguration.default
let defaultSession = URLSession(configuration: defaultConfigObj, delegate: self, delegateQueue: nil)
self.dataTask = defaultSession.dataTask(with: newRequest as URLRequest)
self.dataTask!.resume()
}
override func stopLoading() {
self.dataTask?.cancel()
self.dataTask = nil
self.receivedData = nil
self.urlResponse = nil
}
// MARK: NSURLSessionDataDelegate
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
self.urlResponse = response
self.receivedData = NSMutableData()
completionHandler(.allow)
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
self.client?.urlProtocol(self, didLoad: data)
self.receivedData?.append(data)
}
// MARK: NSURLSessionTaskDelegate
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
if error != nil {
self.client?.urlProtocol(self, didFailWithError: error!)
} else {
self.saveCachedResponse()
self.client?.urlProtocolDidFinishLoading(self)
}
// if error != nil, error!.code != NSURLErrorCancelled {
// self.client?.URLProtocol(self, didFailWithError: error!)
// }
}
// MARK: Private methods
/**
Do whatever with the data here
*/
func saveCachedResponse() {
// refer to https://stackoverflow.com/questions/36297813/custom-nsurlprotocol-with-nsurlsession
// let timeStamp = NSDate()
// let urlString = self.request.url?.absoluteString
// let dataString = NSString(data: self.receivedData! as Data, encoding: String.Encoding.utf8.rawValue) as NSString?
// print("TimeStamp:\(timeStamp)\nURL: \(urlString)\n\nDATA:\(dataString)\n\n")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment