6

J'essaie d'implémenter ce tutoriel qui implémente un NSURLProtocol personnalisé avec NSURLConnection.Personnalisé NSURLProtocol avec NSURLSession

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

Il fonctionne comme prévu, mais maintenant que NSURLConnection est dépréciée dans iOS9, je suis en train de le convertir en NSURLSession.

Malheureusement, cela n'a pas fonctionné.

Je chargement d'un site dans UIWebView, si je l'utilise NSURLConnection il charge et travail tout comme prévu, toutes les requêtes HTTP de la WebView est capturé, mais pas lors de l'utilisation NSURLSession.

Toute aide est appréciée.

ici est mon 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

Comment savez-vous votre code ne fonctionne pas? Qu'avez-vous fait pour repérer vous-même le problème? Pouvez-vous revenir en arrière dans votre exemple de code et supprimer toutes les sections commentées? Ajoutez peut-être quelques commentaires sur ce que vous essayez d'accomplir dans chaque routine. –

+0

Hey, je suis nouveau dans le problème rapide et face à la mise en cache webview. J'essaie avec la même source, la page Web charger correctement et enregistrer dans le cache. Mais lorsque l'appareil est hors ligne, je ne peux pas l'obtenir à partir des données du cache. Peut-être que je dois mettre à jour le code avec urlsession. Pouvez-vous s'il vous plaît m'aider avec cette source s'il vous plaît :(https://drive.google.com/file/d/0B-5GPXUpPZh-Q2FOWEJudXRaQkE/view?usp=sharing –

Répondre

6

Je l'ai résolu.

Voici le code si quelqu'un en a besoin.

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

Merci l'homme. aidé beaucoup. Ci-dessous est la version 3 rapide de la même classe au cas où quelqu'un en aurait besoin. – deepax11

+0

Vous n'avez vraiment pas besoin d'utiliser une NSURLSession distincte pour chaque requête. C'est grossièrement inefficace. Vous devriez envisager d'utiliser une seule instance partagée (en utilisant une variable globale initialisée dans un bloc dispatch_once). – dgatwood

5

Le problème que vous rencontrez avec votre code est que vous utilisez la NSURLSession.sharedSession pour contenir votre tâche de données. En utilisant la session partagée, vous ne pouvez pas modifier le délégué de session afin qu'aucune de vos routines de délégué ne soit appelée.

Vous devrez créer une session personnalisée avec votre protocole établi en tant que délégué pour la session. Ensuite, lorsqu'on vous demande de commencer le chargement, vous pouvez créer une tâche de données dans cette session.

+0

Salut, merci pour la réponse, le code commenté est pour NSURLConnection Comme il est obsolète dans iOS9, j'ai besoin de le convertir en NSURLSession, ce que je fais, c'est que je veux surveiller toutes les requêtes http de uiwebview et enregistrer la réponse JSON de certaines requêtes url. Avec NSURLConnection je peux voir les demandes et le webview charge le site web et n'importe quel lien cliqué, mais avec le changement de NSURLSession le webview ne charge pas le site web – kupilot

+0

Oui, je comprends, comme je l'ai dit dans ma réponse, quand vous Si vous utilisiez NSURLConnection, vous avez configuré le délégué pour la connexion et vos méthodes déléguées ont collecté les données Dans votre nouveau code basé sur NSSession, vous devez créer une session personnalisée au lieu d'utiliser NSSession.sharedSession afin de pouvoir définir le délégué cette session afin que vos rappels de délégué de tâche et de données puissent être appelés. –

+0

merci pour votre aide, je l'ai résolu, voir ma réponse. – 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

Cela fonctionne mais montre le site Web complet. Ne pas afficher la vue du site mobile. – vp2698