Swift拦截所有网络请求

比如使用别人的SDK,看不了源码,可拦截其网络请求,拦截后可对请求做修改,包括重定向等

import UIKit

class TBURLProtocol: URLProtocol, URLSessionDataDelegate, URLSessionTaskDelegate{
    
    fileprivate var dataTask:URLSessionDataTask?
    fileprivate let sessionDelegateQueue = OperationQueue()
    
    class func startMonitor(){
        let sessionConfiguration = TBSessionConfiguration.shared
        URLProtocol.registerClass(TBURLProtocol.self)
        if !sessionConfiguration.isSwizzle{
            sessionConfiguration.load()
        }
    }
    
    class func stopMonitor(){
        let sessionConfiguration = TBSessionConfiguration.shared
        URLProtocol.unregisterClass(TBURLProtocol.self)
        if sessionConfiguration.isSwizzle{
            sessionConfiguration.unload()
        }
    }
    
    override class func canInit(with request: URLRequest) -> Bool {
        if URLProtocol.property(forKey: "TBURLProtocolHandledKey", in: request) != nil {
            return false
        }
        return true
    }

    override class func canonicalRequest(for request: URLRequest) -> URLRequest {
        let mutableReqeust = (request as NSURLRequest).mutableCopy() as! NSMutableURLRequest
         //在这里可以对请求修改
        URLProtocol.setProperty(true, forKey: "TBURLProtocolHandledKey",
                                in: mutableReqeust)
        return mutableReqeust as URLRequest
    }
    
    override func startLoading() {
        print("抓取请求地址: \(request.url!.absoluteString)")
        
        let defaultConfigObj = URLSessionConfiguration.default
        sessionDelegateQueue.maxConcurrentOperationCount = 1
        sessionDelegateQueue.name = "com.TB.session.queue"
        let defaultSession = Foundation.URLSession(configuration: defaultConfigObj,
                                                   delegate: self, delegateQueue: sessionDelegateQueue)
        dataTask = defaultSession.dataTask(with: self.request)
        dataTask!.resume()
    }
    
    override func stopLoading() {
        dataTask?.cancel()
        dataTask = nil
    }
    
    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        error == nil ? client?.urlProtocolDidFinishLoading(self) : client?.urlProtocol(self, didFailWithError: error!)
        self.dataTask = nil
    }
    
    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
        client?.urlProtocol(self, didLoad: data)
    }
    
    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
        client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .allowed)
        completionHandler(.allow)
    }
    
    func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {
        client?.urlProtocol(self, wasRedirectedTo: request, redirectResponse: response)
    }
}

class TBSessionConfiguration: NSObject {
    
    static var shared = TBSessionConfiguration()
    fileprivate override init(){}
    
    
    var isSwizzle = false
    
    func load(){
        isSwizzle = true
        guard let cls = NSClassFromString("__NSCFURLSessionConfiguration") ?? NSClassFromString("NSURLSessionConfiguration") else { return }
        swizzleSelector(selector: #selector(protocolClasses), fromClass: cls, toClass: TBSessionConfiguration.self)
    }
    
    func unload(){
        isSwizzle = false
        guard let cls = NSClassFromString("__NSCFURLSessionConfiguration") ?? NSClassFromString("NSURLSessionConfiguration") else { return }
        swizzleSelector(selector: #selector(protocolClasses), fromClass: cls, toClass: TBSessionConfiguration.self)
    }
    
    func swizzleSelector(selector: Selector, fromClass: AnyClass, toClass: AnyClass){
        let originalMethod = class_getInstanceMethod(fromClass, selector)
        let stubMethod = class_getInstanceMethod(toClass, selector)
        guard originalMethod != nil && stubMethod != nil else { return }
        method_exchangeImplementations(originalMethod!, stubMethod!)
    }
    
    @objc func protocolClasses() -> NSArray{
        return [TBURLProtocol.self]
    }
}

使用方法

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        TBURLProtocol.startMonitor()
        return true
    }

你可能感兴趣的:(Swift拦截所有网络请求)