iosswiftnsurlsessionnsurlprotocolnsurlsessiondatatask

Custom NSURLProtocol with NSURLSession


I'm trying to implement this tutorial which implements a custom NSURLProtocol with NSURLConnection.

https://www.raywenderlich.com/76735/using-nsurlprotocol-swift

It works as expected, but now that NSURLConnection is deprecated in iOS9, I'm trying to convert it to NSURLSession.

Unfortunatly it didn't work.

I'm loading a website in uiwebview, if I use NSURLConnection it loads and everything work as expected, all http requests from the webview is captured, but not when using NSURLSession.

Any help is appreciated.

here is my code

    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)\n\nDATA:\(dataString)\n\n")
    }


    }

Solution

  • I've solved it.

    Here is the code if anyone needs it.

    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)\n\nDATA:\(dataString)\n\n")
    }
    
    
    }