2016-03-30 61 views
6

我想實現這個教程,它實現NSURLConnection的自定義NSURLProtocol。與NSURLSession自定義NSURLProtocol

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

它能正常工作,但現在NSURLConnection的是iOS9過時,我試圖將其轉換爲NSURLSession。

不幸的是它沒有工作。

我正在uiwebview中加載一個網站,如果我使用它加載的NSURLConnection,並且所有事情都按預期工作,則捕獲所有來自webview的http請求,但不會在使用NSURLSession時捕獲。

任何幫助表示讚賞。

這裏是我的代碼

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

你與你的代碼遇到的問題是,你正在使用的NSURLSession.sharedSession包含數據的任務。通過使用共享會話,您無法更改會話委託,因此您的委託例程都不會被調用。

您需要創建一個自定義會話,並將您的協議建立爲會話的委託。然後,當被要求開始加載時,您可以在該會話中創建一個數據任務。

+0

嗨,感謝您的答覆,註釋掉的代碼是NSURLConnection ,因爲它在iOS9中被棄用我需要將它轉換爲NSURLSession,我所做的是我想監視來自uiwebview的所有http請求並保存來自某些url請求的JSON響應。使用NSURLConnection可以正常工作,但現在它不贊成使用NSURLConnection,我可以看到請求和webview加載網站和任何鏈接點擊,但隨着NSURLSession的變化,web視圖不會加載網站 – 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

它的工作,但顯示完整的網站。 Dosen't顯示移動網站視圖。 – vp2698

相關問題