Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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


    }
like image 280
kupilot Avatar asked Mar 30 '16 01:03

kupilot


People also ask

What is the difference between NSURLSession and NSURLConnection?

NSURLSession also provides nicer interfaces for requesting data using blocks, in that it allows you to combine them with delegate methods for doing custom authentication handling, redirect handling, etc., whereas with NSURLConnection, if you suddenly realized you needed to do those things, you had to refactor your code ...

What is NSURLProtocol?

What Is NSURLProtocol? A set of classes known as the URL Loading System, handles URL requests. You need to know them to find out how iOS handles your app's requests to load a URL-based resource. At the heart of the URL Loading System is the NSURL class.

Is NSURLSession asynchronous?

Like most networking APIs, the NSURLSession API is highly asynchronous.


1 Answers

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


}
like image 114
kupilot Avatar answered Sep 20 '22 04:09

kupilot