【问题标题】:WKWebview could not load asset files because of Authorization由于授权,WKWebview 无法加载资产文件
【发布时间】:2020-12-18 16:51:18
【问题描述】:

我有一个应用 AWS Cognito 的 WKWebview。 对服务器的每个请求都必须在请求头中添加授权。

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?

感谢您的帮助。

【问题讨论】:

    标签: ios swift amazon-cognito wkwebview


    【解决方案1】:

    您可以使用您的配置将所有 webview 的请求重定向到您的 URLSession。为此,您可以为https 方案注册您的自定义URLProtocolWKWebView 有一个 hack 来拦截带有 WKBrowsingContextController 私有类和您的 URLProtocol 实现的 url 请求,例如:

    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)
        }
    }
    

    只需在应用启动时注册您的协议即可处理所有请求:

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        MiddlewareURLProtocol.registerClass()
        ...
    }
    

    注意:为了防止 Apple 对私有类进行静态检查,您可以将类名存储在数组中:

    let className = ["Controller", "Context", "Browsing", "WK"].reversed().joined()
    

    【讨论】:

    • 这个怎么用?
    猜你喜欢
    • 2020-07-03
    • 2021-10-01
    • 2023-03-06
    • 1970-01-01
    • 2020-05-10
    • 2021-09-19
    • 2020-06-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多