利用NSURLProtocol攔截UIWebView的網(wǎng)絡(luò)請(qǐng)求
在app加載webview的時(shí),我們可能需要對(duì)網(wǎng)頁(yè)做一些特殊的處理星著,比如:攔截網(wǎng)頁(yè)的接口請(qǐng)求修改后在轉(zhuǎn)發(fā)逻澳,修改或者監(jiān)聽(tīng)接口返回值,修改網(wǎng)頁(yè)的圖片等等合呐。料皇。。這時(shí)候就需要用到iOS提供的黑魔法NSURLProtocol爱谁。
根據(jù)官網(wǎng)的描述,在每一個(gè) HTTP 請(qǐng)求開(kāi)始時(shí),系統(tǒng)會(huì)創(chuàng)建一個(gè)合適的 NSURLProtocol 對(duì)象處理對(duì)應(yīng)的 URL 請(qǐng)求孝偎,因?yàn)?NSURLProtocol 是一個(gè)抽象類(lèi),所以我們需要做的就是寫(xiě)一個(gè)繼承自 NSURLProtocol 的類(lèi)凉敲,并通過(guò) - registerClass: 方法注冊(cè)我們的協(xié)議類(lèi)衣盾,然后 URL 加載系統(tǒng)就會(huì)在請(qǐng)求發(fā)出時(shí)使用我們創(chuàng)建的協(xié)議對(duì)象對(duì)該請(qǐng)求進(jìn)行處理。
首先爷抓,我們需要在加載webview的頁(yè)面注冊(cè)我們的URLProtocol類(lèi)
URLProtocol.registerClass(PKHRegisterURLProtocol.self)
在我們繼承自URLProtocol的類(lèi)中势决,重寫(xiě)canInit方法來(lái)選擇性的攔截網(wǎng)絡(luò)請(qǐng)求,也可以全部攔截:
/// 在這里攔截或者放行接口請(qǐng)求
///
/// - Parameter request: 本次請(qǐng)求
/// - Returns: 是否需要監(jiān)控
override open class func canInit(with request: URLRequest) -> Bool {
// 如果已經(jīng)攔截過(guò)請(qǐng)求就放行蓝撇,避免出現(xiàn)死循環(huán)
if (URLProtocol.property(forKey: RegisterURLProtocolKey, in: request) != nil) {
return false
}
return false
}
然后果复,重寫(xiě)canonicalRequest來(lái)對(duì)請(qǐng)求做設(shè)置,返回新的請(qǐng)求:
/// 在這里設(shè)置攔截的請(qǐng)求, 可以在這里統(tǒng)一設(shè)置接口請(qǐng)求, 比如往請(qǐng)求頭里面添加?xùn)|西
///
/// - Parameter request: 本次請(qǐng)求
/// - Returns: 我們自定義的請(qǐng)求
override open class func canonicalRequest(for request: URLRequest) -> URLRequest {
let newRequest = request as! NSMutableURLRequest
URLProtocol.setProperty(true, forKey: RegisterURLProtocolKey, in: newRequest)
print("request.URL.absoluteString = \(String(describing: request.url?.absoluteString))")
if let data = newRequest.httpBody {
let dataStr = String(data: data, encoding: .utf8)
print("requst數(shù)據(jù): \(dataStr)")
}
return newRequest as URLRequest
}
在startLoading和stopLoading做接口請(qǐng)求相關(guān)的工作渤昌,比如在startLoading中開(kāi)始網(wǎng)絡(luò)請(qǐng)求虽抄,在stopLoading中結(jié)束網(wǎng)絡(luò)請(qǐng)求:
/// 重寫(xiě)父類(lèi)開(kāi)始加載
override open func startLoading() {
let configuration = URLSessionConfiguration.default
sessionDelegateQueue = OperationQueue()
sessionDelegateQueue.maxConcurrentOperationCount = 1
sessionDelegateQueue.name = "com.pankehong.session.queue"
let session = URLSession(configuration: configuration, delegate: self, delegateQueue: sessionDelegateQueue)
dataTask = session.dataTask(with: request)
dataTask.resume()
}
/// 重寫(xiě)父類(lèi)的重復(fù)加載
override open func stopLoading() {
if dataTask != nil {
dataTask.cancel()
}
}
最后實(shí)現(xiàn)URLSessionDelegate,URLSessionDataDelegate的代理独柑,就可以對(duì)網(wǎng)絡(luò)請(qǐng)求返回的數(shù)據(jù)做相應(yīng)的處理了
// 當(dāng)服務(wù)端返回信息時(shí)迈窟,這個(gè)回調(diào)函數(shù)會(huì)被ULS調(diào)用,在這里實(shí)現(xiàn)http返回信息的截取
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
client?.urlProtocol(self, didLoad: data)
if let dataStr = String(data: data, encoding: .utf8) {
print("截取返回?cái)?shù)據(jù): \(dataStr)")
}
}
這只是URLProtocol的簡(jiǎn)單應(yīng)用忌栅,喜歡的朋友點(diǎn)個(gè)??