2016-03-30 10 views
6

私はNSURLConnectionでカスタムNSURLProtocolを実装するこのチュートリアルを実装しようとしています。カスタムNSURLProtocol with NSURLSession

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

期待どおりに動作しますが、今NSURLConnectionはiOS9に廃止されていることを、私はNSURLSessionに変換しようとしています。

不幸にも機能しませんでした。

私はuiwebviewでWebサイトをロードしていますが、NSURLConnectionをロードしてすべてが正常に動作すると、webviewからのすべてのHTTP要求がキャプチャされますが、NSURLSessionを使用しているときはキャプチャされません。

何か助けていただければ幸いです。

はここにあなたのコードを持っている問題は、あなたのデータのタスクを含むようにNSURLSession.sharedSessionを使用していることである私のコード

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

はどのようにあなたのコードが動作していない知っているのですか?自分で問題を追跡するために何をしましたか?コード例に戻って、コメントアウトされたすべてのセクションを削除できますか?おそらく、各ルーチンで達成しようとしていることについてのコメントを追加してください。 –

+0

ねえ、私はwebviewのキャッシュで迅速かつ直面している問題に新しいです。私は同じソースで試しています。ウェブページが正しく読み込まれ、キャッシュに保存されています。しかし、デバイスがオフラインのとき、私はキャッシュデータからそれを得ることができません。私はurlsessionでコードを更新する必要があります。あなたはこのソースで私を助けてください:(https://drive.google.com/file/d/0B-5GPXUpPZh-Q2FOWEJudXRaQkE/view?usp=sharing –

答えて

6

私はそれを解決しました。

誰でも必要とするコードです。

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

ありがとうございました。たくさん助けてくれました。以下は、誰かが必要な場合に備えて、同じクラスのswift 3バージョンです。 – deepax11

+0

実際には、リクエストごとに別々のNSURLSessionを使用する必要はありません。それは大いに非効率的です。代わりに、(dispatch_onceブロックで初期化されたグローバル変数を使用して)単一の共有インスタンスを使用することを検討する必要があります。 – dgatwood

5

です。共有セッションを使用することで、セッションデリゲートを変更することができず、デリゲートルーチンが呼び出されることはありません。

セッションの代理人として確立されたプロトコルでカスタムセッションを作成する必要があります。次に、ロードを開始するように頼まれたら、そのセッションでデータタスクを作成することができます。

+0

こんにちは、返信ありがとう、コメントアウトされたコードはNSURLConnectionですそれはiOS9で非難されているので、私はそれをNSURLSessionに変換する必要があります、私はuiwebviewからのすべてのHTTP要求を監視し、特定のURL要求からのJSON応答を保存したいと思います。 NSURLConnectionを使用すると、リクエストを見ることができ、webviewはロードされたWebサイトやリンクをロードしますが、NSURLSessionの変更によりwebviewにはロードされません。 – kupilot

+0

はい、私は理解しています。 NSURLConnectionを使用して接続のデリゲートを設定し、デリゲートメソッドがデータを収集しました。新しいNSSessionベースのコードでは、NSSession.sharedSessionを使用せずにカスタムセッションを作成してデリゲートをオンにする必要がありますセッションとデータタスクの代理コールバックを呼び出すことができます。 –

+0

助けてくれてありがとう、私はそれを解決した、私の答えを参照してください。 – kupilot

6

スウィフト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) 
     } 
    } 
} 
+0

これは動作していますが、完全なウェブサイトを表示しています。モバイルサイトのビューを表示しない。 – vp2698

関連する問題