我有一个应用 AWS Cognito 的 WKWebview。
对服务器的每个请求都必须在请求 header 中添加授权。
let access_token = "Bearer \(key)"
let header: [String: String] = [
"Authorization": access_token
]
if let url = URL(string: "https://myserverdomain.amazonaws.com/api/v3/graphs?date=2020-08-28") {
var request: URLRequest = URLRequest(url: url)
request.allHTTPHeaderFields = header
wkWebview.load(request)
}
使用此代码,我已经可以在页面中加载页面内容但 CSS。我检查了 chrome(使用 ModHeader chrome 扩展来添加标题),它工作正常,显示正确,也适用于 Android。我通过 Chrome 和 标签中的 CSS 链接检查,它与 HTML 文件不是同一个文件夹(我不知道是不是这个原因)。
<link rel="stylesheet" type="text/css" href="https://myserverdomain.amazonaws.com/assets/graphs/style.css"></script>
我只能使用代码加载 css 内容:let access_token = "Bearer \(key)"
let header: [String: String] = [
"Authorization": access_token
]
if let url = URL(string: "https://myserverdomain.amazonaws.com/assets/graphs/style.css") {
var request: URLRequest = URLRequest(url: url)
request.allHTTPHeaderFields = header
wkWebview.load(request)
}
UIWebview 已被弃用,有没有办法像往常一样使用全局标题设置 WKWebview?感谢您的帮助。
最佳答案
您可以将所有 webview 的请求重定向到您的 URLSession
与您的配置。为此,您可以注册您的自定义 URLProtocol
对于 https
方案。 WKWebView
有一个 hack使用 WKBrowsingContextController
拦截 url 请求私有(private)类(class)和您的URLProtocol
实现例如:
class MiddlewareURLProtocol : URLProtocol {
static let handledKey = "handled"
lazy var session : URLSession = {
// Config your headers
let configuration = URLSessionConfiguration.default
//configuration.httpAdditionalHeaders = ["Authorization" : "..."]
return URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
}()
var sessionTask : URLSessionTask?
override var task: URLSessionTask? {
return sessionTask
}
static func registerClass() {
let sel = NSSelectorFromString("registerSchemeForCustomProtocol:")
if let cls = NSClassFromString("WKBrowsingContextController") as? NSObject.Type, cls.responds(to:sel) {
// Register https protocol
cls.perform(sel, with: "https")
}
URLProtocol.registerClass(Self.self)
}
override class func canInit(with request: URLRequest) -> Bool {
return URLProtocol.property(forKey: Self.handledKey, in: request) == nil
}
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
return request
}
override class func requestIsCacheEquivalent(_ a: URLRequest, to b: URLRequest) -> Bool {
super.requestIsCacheEquivalent(a, to: b)
}
override func startLoading() {
let redirect = (request as NSURLRequest).mutableCopy() as! NSMutableURLRequest
URLProtocol.setProperty(true, forKey: Self.handledKey, in: redirect)
sessionTask = session.dataTask(with: redirect as URLRequest)
task?.resume()
}
override func stopLoading() {
task?.cancel()
}
}
extension MiddlewareURLProtocol : URLSessionDataDelegate {
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
if let err = error {
client?.urlProtocol(self, didFailWithError: err)
}
else {
client?.urlProtocolDidFinishLoading(self)
}
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .allowed)
completionHandler(.allow)
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
client?.urlProtocol(self, didLoad: data)
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, willCacheResponse proposedResponse: CachedURLResponse, completionHandler: @escaping (CachedURLResponse?) -> Void) {
completionHandler(proposedResponse)
}
func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {
let redirect = (request as NSURLRequest).mutableCopy() as! NSMutableURLRequest
Self.removeProperty(forKey: Self.handledKey, in: redirect)
client?.urlProtocol(self, wasRedirectedTo: redirect as URLRequest, redirectResponse: response)
self.task?.cancel()
let error = NSError(domain: NSCocoaErrorDomain, code: CocoaError.Code.userCancelled.rawValue, userInfo: nil)
client?.urlProtocol(self, didFailWithError: error)
}
}
只需在 app start 上注册您的协议(protocol)即可处理所有请求:func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
MiddlewareURLProtocol.registerClass()
...
}
注意:为了防止 Apple 对私有(private)类进行静态检查,您可以将类名存储在数组中:let className = ["Controller", "Context", "Browsing", "WK"].reversed().joined()
关于ios - 由于授权,WKWebview 无法加载 Assets 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63656053/