使用NSURLSession自定义NSURLProtocol
我试图实现这个教程,它实现了带有NSURLConnection的自定义NSURLProtocol。
https://www.raywenderlich.com/76735/using-nsurlprotocol-swift
它按预期工作,但现在NSURLConnection已在iOS9中被弃用,我试图将其转换为NSURLSession。
不幸的是它没有工作。
我在uiwebview中加载一个网站,如果我使用它加载的NSURLConnection并且一切按预期工作,那么来自webview的所有http请求都会被捕获,但在使用NSURLSession时不会被捕获。
任何帮助表示赞赏。
这是我的代码
    import UIKit
    class MyProtocol: NSURLProtocol, NSURLSessionDataDelegate, NSURLSessionTaskDelegate, NSURLSessionDelegate {
    //var connection: NSURLConnection!
    var mutableData: NSMutableData!
    var response: NSURLResponse!
    var dataSession: NSURLSessionDataTask!
    override class func canInitWithRequest(request: NSURLRequest) -> Bool {
        if NSURLProtocol.propertyForKey("MyURLProtocolHandledKey", inRequest: request) != nil {
            return false
        }
        return true
    }
    override class func canonicalRequestForRequest(request: NSURLRequest) -> NSURLRequest {
        return request
    }
    override class func requestIsCacheEquivalent(aRequest: NSURLRequest,
        toRequest bRequest: NSURLRequest) -> Bool {
            return super.requestIsCacheEquivalent(aRequest, toRequest:bRequest)
    }
    override func startLoading() {
        let newRequest = self.request.mutableCopy() as! NSMutableURLRequest
        NSURLProtocol.setProperty(true, forKey: "MyURLProtocolHandledKey", inRequest: newRequest)
        self.dataSession = NSURLSession.sharedSession().dataTaskWithRequest(newRequest)
        dataSession.resume()
        self.mutableData = NSMutableData()
    }
        override func stopLoading() {
        print("Data task stop")
        self.dataSession.cancel()
        self.mutableData = nil
    }
    func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {
        self.response = response
        self.mutableData = NSMutableData()
        print(mutableData)
    }
    func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
        self.client?.URLProtocol(self, didLoadData: data)
        self.mutableData.appendData(data)
    }
    func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
        if (error == nil)
        {
            self.client!.URLProtocolDidFinishLoading(self)
            self.saveCachedResponse()
        }
        else
        {
            self.client?.URLProtocol(self, didFailWithError: error!)
        }
    }
    func saveCachedResponse () {
        let timeStamp = NSDate()
        let urlString = self.request.URL?.absoluteString
        let dataString = NSString(data: self.mutableData, encoding: NSUTF8StringEncoding) as NSString?
        print("TiemStamp:(timeStamp)nURL: (urlString)nnDATA:(dataString)nn")
    }
    }
我解决了它。
这里是代码,如果任何人需要它。
import Foundation
class MyProtocol1: NSURLProtocol, NSURLSessionDataDelegate, NSURLSessionTaskDelegate
{
private var dataTask:NSURLSessionDataTask?
private var urlResponse:NSURLResponse?
private var receivedData:NSMutableData?
class var CustomKey:String {
    return "myCustomKey"
}
// MARK: NSURLProtocol
override class func canInitWithRequest(request: NSURLRequest) -> Bool {
    if (NSURLProtocol.propertyForKey(MyProtocol1.CustomKey, inRequest: request) != nil) {
        return false
    }
    return true
}
override class func canonicalRequestForRequest(request: NSURLRequest) -> NSURLRequest {
    return request
}
override func startLoading() {
    let newRequest = self.request.mutableCopy() as! NSMutableURLRequest
    NSURLProtocol.setProperty("true", forKey: MyProtocol1.CustomKey, inRequest: newRequest)
    let defaultConfigObj = NSURLSessionConfiguration.defaultSessionConfiguration()
    let defaultSession = NSURLSession(configuration: defaultConfigObj, delegate: self, delegateQueue: nil)
    self.dataTask = defaultSession.dataTaskWithRequest(newRequest)
    self.dataTask!.resume()
}
override func stopLoading() {
    self.dataTask?.cancel()
    self.dataTask       = nil
    self.receivedData   = nil
    self.urlResponse    = nil
}
// MARK: NSURLSessionDataDelegate
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask,
                didReceiveResponse response: NSURLResponse,
                                   completionHandler: (NSURLSessionResponseDisposition) -> Void) {
    self.client?.URLProtocol(self, didReceiveResponse: response, cacheStoragePolicy: .NotAllowed)
    self.urlResponse = response
    self.receivedData = NSMutableData()
    completionHandler(.Allow)
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
    self.client?.URLProtocol(self, didLoadData: data)
    self.receivedData?.appendData(data)
}
// MARK: NSURLSessionTaskDelegate
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
    if error != nil && error!.code != NSURLErrorCancelled {
        self.client?.URLProtocol(self, didFailWithError: error!)
    } else {
        saveCachedResponse()
        self.client?.URLProtocolDidFinishLoading(self)
    }
}
// MARK: Private methods
/**
 Do whatever with the data here
 */
func saveCachedResponse () {
    let timeStamp = NSDate()
    let urlString = self.request.URL?.absoluteString
    let dataString = NSString(data: self.receivedData!, encoding: NSUTF8StringEncoding) as NSString?
    print("TimeStamp:(timeStamp)nURL: (urlString)nnDATA:(dataString)nn")
}
}
您使用代码时遇到的问题是您正在使用NSURLSession.sharedSession来包含您的数据任务。 通过使用共享会话,您无法更改会话委托,因此您的委托例程都不会被调用。
您需要创建一个自定义会话,并将您的协议建立为会话的代表。 然后,当被要求开始加载时,您可以在该会话中创建一个数据任务。
Swift 3版本:
//  CustomURLProtocol.swift
class CustomURLProtocol: URLProtocol, URLSessionDataDelegate, URLSessionTaskDelegate {
  private var dataTask: URLSessionDataTask?
  private var urlResponse: URLResponse?
  private var receivedData: NSMutableData?
  class var CustomHeaderSet: String {
      return "CustomHeaderSet"
  }
  // MARK: NSURLProtocol
  override class func canInit(with request: URLRequest) -> Bool {
      guard let host = request.url?.host, host == "your domain.com" else {
          return false
      }
      if (URLProtocol.property(forKey: CustomURLProtocol.CustomHeaderSet, in: request as URLRequest) != nil) {
          return false
      }
      return true
  }
  override class func canonicalRequest(for request: URLRequest) -> URLRequest {
      return request
  }
  override func startLoading() {
      let mutableRequest =  NSMutableURLRequest.init(url: self.request.url!, cachePolicy: NSURLRequest.CachePolicy.useProtocolCachePolicy, timeoutInterval: 240.0)//self.request as! NSMutableURLRequest
      //Add User Agent
      var userAgentValueString = "myApp"
     mutableRequest.setValue(userAgentValueString, forHTTPHeaderField: "User-Agent")
      print(mutableRequest.allHTTPHeaderFields ?? "")
      URLProtocol.setProperty("true", forKey: CustomURLProtocol.CustomHeaderSet, in: mutableRequest)
      let defaultConfigObj = URLSessionConfiguration.default
      let defaultSession = URLSession(configuration: defaultConfigObj, delegate: self, delegateQueue: nil)
      self.dataTask = defaultSession.dataTask(with: mutableRequest 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 as Data)
      self.receivedData?.append(data as Data)
  }
  // MARK: NSURLSessionTaskDelegate
  func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
      if error != nil { //&& error.code != NSURLErrorCancelled {
          self.client?.urlProtocol(self, didFailWithError: error!)
      } else {
          //saveCachedResponse()
          self.client?.urlProtocolDidFinishLoading(self)
      }
  }
}
上一篇: Custom NSURLProtocol with NSURLSession
下一篇: UIWebView slow loading using NSUrlProtocol Xamarin.Forms
