2016-03-30 22 views
6

Ich versuche dieses Tutorial zu implementieren, das ein benutzerdefiniertes NSURLProtocol mit NSURLConnection implementiert.Benutzerdefiniertes NSURLProtocol mit NSURLSession

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

Es funktioniert wie erwartet, aber jetzt, dass NSURLConnection in iOS9 veraltet ist, ich versuche es zu NSURLSession zu konvertieren.

Leider hat es nicht funktioniert.

Ich lade eine Website in uiwebview, wenn ich NSURLConnection es lädt und alles funktioniert wie erwartet, alle HTTP-Anfragen aus der Webansicht wird erfasst, aber nicht bei der Verwendung von NSURLSession.

Jede Hilfe wird geschätzt.

hier ist mein 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") 
    } 


    } 
+0

Wie wissen Sie, Ihr Code funktioniert nicht? Was hast du getan, um das Problem selbst aufzuspüren? Können Sie das Codebeispiel erneut ausführen und alle auskommentierten Abschnitte entfernen? Vielleicht fügen Sie einige Kommentare hinzu, was Sie in jeder Routine erreichen möchten. –

+0

Hey, ich bin neu in Swift und konfrontiert Problem mit Webview Caching. Ich versuche mit der gleichen Quelle die Webseite richtig zu laden und im Cache zu speichern. Aber wenn das Gerät offline ist, kann ich es nicht aus den Cache-Daten abrufen. Möglicherweise muss ich den Code mit URLSession aktualisieren. Können Sie mir bitte mit dieser Quelle bitte helfen :(https://drive.google.com/file/d/0B-5GPXUpPZh-Q2FOWEJudXRaQkE/view?usp=sharing –

Antwort

6

Ich habe es gelöst.

Hier ist der Code, wenn jemand es braucht.

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


} 
+0

Danke Mann. hat mir sehr geholfen. Unten ist schnelle 3-Version der gleichen Klasse für den Fall, dass jemand es braucht. – deepax11

+0

Sie müssen wirklich keine separate NSURLSession für jede Anfrage verwenden. Das ist grob ineffizient. Sie sollten stattdessen eine einzelne gemeinsam genutzte Instanz verwenden (indem Sie eine globale Variable verwenden, die in einem dispatch_once-Block initialisiert wurde). – dgatwood

5

Das Problem, das Sie mit Ihrem Code haben, ist, dass Sie die die NSURLSession.sharedSession verwenden, um Ihre Daten Aufgabe zu enthalten. Wenn Sie die freigegebene Sitzung verwenden, können Sie den Sitzungsdelegaten nicht ändern, sodass keine Ihrer Delegierungsroutinen aufgerufen wird.

Sie müssen eine benutzerdefinierte Sitzung mit Ihrem Protokoll erstellen, das als Delegat für die Sitzung eingerichtet wurde. Wenn Sie dann aufgefordert werden, mit dem Laden zu beginnen, können Sie in dieser Sitzung eine Datenaufgabe erstellen.

+0

Hallo, danke für die Antwort, der auskommentierte Code ist für NSURLConnection , da es in iOS9 veraltet ist, muss ich es in NSURLSession konvertieren, Was ich tue, ist, dass ich alle HTTP-Anfragen von uiwebview überwachen und die JSON-Antwort von bestimmten URL-Anfragen speichern möchte.Der Code funktionierte gut mit NSURLConnection, aber jetzt Mit NSURLConnection kann ich die Anfragen sehen und das Webview lädt die Webseite und jeden Link, aber mit der Änderung zu NSURLSession lädt die Webansicht die Webseite nicht. " – kupilot

+0

Ja, ich verstehe. Wie ich in meiner Antwort gesagt habe, wenn du es sagst Wenn Sie NSURLConnection verwenden, richten Sie den Delegaten für die Verbindung ein, und Ihre Delegate-Methoden erfassen die Daten.In Ihrem neuen NSSession-basierten Code müssen Sie eine benutzerdefinierte Sitzung erstellen, anstatt NSSession.sharedSession zu verwenden, damit Sie den Delegaten aktivieren können diese Sitzung, damit Ihre Callbacks für Sitzungs- und Datenaufgabendelegaten aufgerufen werden können. –

+0

danke für deine Hilfe, ich habe es gelöst, Siehe meine Antwort. – kupilot

6

Swift 3-Version:

// 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) 
     } 
    } 
} 
+0

Es funktioniert, zeigt aber die komplette Webseite. Die Ansicht der mobilen Site wird nicht angezeigt. – vp2698

Verwandte Themen