【问题标题】:iOS intercept all network traffic from my app?iOS 拦截来自我的应用程序的所有网络流量?
【发布时间】:2017-06-26 19:19:49
【问题描述】:

我想为来自我的应用的所有网络调用添加代理。类似的东西

func intercept(request: URLRequest) {
  if isOk(request) {
    return // the request continues as normally
  } else if isIntercepted(request) {
    let res = HTTPURLResponse(url: url, statusCode: 200, httpVersion: "HTTP/2", headerFields: ["Content-Type": "application/json"])
    res.value = "{\"ok\":true}" // not that exactly work, but you get the idea
    request.end(res)
  } else {
    let res = HTTPURLResponse(url: url, statusCode: 401, httpVersion: "HTTP/2")
    res.value = "forbidden"
    request.end(res)
  }
}

我希望将其应用于来自我的应用的所有呼叫。即来自我的代码以及我正在使用的所有库和框架。可能吗?

我发现了有关读取其他应用程序的流量(不可能)和在从我的代码开始的调用上设置代表的问题。我想更进一步,1) 将自动应用于所有流量,2) 包括来自第 3 方的流量

【问题讨论】:

    标签: ios networking proxy


    【解决方案1】:

    这是 URLProtocol 类的工作。

    来自 Apple 的文档:

    NSURLProtocol 对象处理特定协议 URL 的加载 数据。 NSURLProtocol 类本身是一个抽象类 提供用于处理具有特定 URL 的 URL 的基础结构 方案。您为任何自定义协议或 URL 方案创建子类 您的应用支持。

    您需要实现自己的URLProtocol 子类并将其注册到应用程序以供使用。此后,从应用程序初始化的所有连接都将使用该协议,您将能够处理/阻止您想要的任何请求。

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
    {
        guard URLProtocol.registerClass(MyURLProtocol.self) else
        {
            abort()
        }
    
        return true
    }
    

    此外,如果您使用的是URLSession(并且应该!),那么您还必须通过会话配置注册您的课程:

    func getURLSessionConfiguration() -> URLSessionConfiguration
    {
        let configuration = URLSessionConfiguration.default
    
        configuration.protocolClasses = [
            MyURLProtocol.self
        ]
    
        return configuration
    }
    
    let session = URLSession(configuration: getURLSessionConfiguration())
    

    然后,您可以通过 URLProtocol 子类的 startLoading() 方法管理您想要阻止的任何内容:

    override func startLoading()
    {
        if !self.isOK()
        {
            let error = NSError(domain: "GuardURLProtocol", code: 10, userInfo: [NSLocalizedDescriptionKey: "Connection denied by guard"])
            self.client?.urlProtocol(self, didFailWithError: error)
        }
        else if let task = self.task
        {
            task.resume()
        }
    }
    

    还有更多的方法你必须实现,你应该阅读documentation from Apple

    但作为一个小发明(并为我自己练习),I have written a generic blocker protocol,你应该检查一下它是如何工作的。在GuardURLProtocol.swift 文件的底部有一个示例子类 (BlockFPTURLSession),其中所有 FTP 请求都被架构阻止。

    如果您使用我上面链接的类,并尝试打开 FTP 连接,您将看到以下错误:

    2017-02-16 23:09:45.846 URLProtocol[83111:7456862] Error: Error Domain=GuardURLProtocol Code=10 "Connection denied by guard" UserInfo={NSLocalizedDescription=Connection denied by guard}
    

    玩得开心!

    【讨论】:

    • 谢谢,太好了!你知道我会如何嘲笑回应吗?例如,如果实际响应是 heypasteit.com/clip/7WCWX 我如何传递它?我试过client?.urlProtocol(self, didLoad: response.data(using: .utf8)!) client?.urlProtocolDidFinishLoading(self) 其中response 是上面的文字
    • 我认为您还需要调用 self.client?.urlProtocolDidFinishLoading(self) 来告诉 URL 连接/会话加载最终完成,因为可能会多次调用 didLoad... 来传递响应数据块,并且只调用一次并不意味着连接完成。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多