45
44

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

iOSで通信を監視しよう

Posted at

通信を管理する仕組み

iOSでの通信の管理にはNSURLSessionとNSURLProtocolを使おうという話。

アプリ内の通信をすべて共通の仕組みでデバッグして、APIへのリクエスト・webviewでのリクエスト・・・すべての通信を監視してユーザーの体験を変えたりすることもできますよって話。

NSURLProtocol

An NSURLProtocol object handles the loading of protocol-specific URL data. The NSURLProtocol class itself is an abstract class that provides the infrastructure for processing URLs with a specific URL scheme. You create subclasses for any custom protocols or URL schemes that your app supports.

何をするのかというとアプリ内にプロトコルを新しく定義してアプリケーション全体の通信をフックして処理をしたりする。webviewアプリでは特定ドメインへのアクセスを制限したり、クエリによってコンテンツを切り替えたりという時に便利。

実装

今回は自分の使っているパケットキャプチャの実装の一部を見てみる。

//CaptureProtocol.swift
class CaptureProtocol: NSURLProtocol ,NSURLSessionDelegate, NSURLSessionDataDelegate{
    
    
    override class func canInitWithRequest(request: NSURLRequest) -> Bool {
        // ここでtrueを返した場合、そのリクエストをこのプロトコルで行う
        return CaptureManager.sharedInstance.isNeedCheckRequest(request)
    }
    
    override class func canonicalRequestForRequest (request: NSURLRequest) -> NSURLRequest {
        return request;
    }
    
    override func startLoading() {
        
        // リクエストのタスクはこのプロトコルに移るのでここでリクエストを投げる
        let session:NSURLSession = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: self, delegateQueue: nil)

        session.dataTaskWithRequest(request) { (data, response, error) -> Void in
            if error != nil{
                self.client?.URLProtocol(self, didFailWithError: error!)
                return
            }
            
            // クライアントに渡すところも実装してあげないとリダイレクトをしくじることがある
            self.client?.URLProtocol(self, didReceiveResponse: response!, cacheStoragePolicy: NSURLCacheStoragePolicy.Allowed)
            self.client?.URLProtocol(self, didLoadData: data!)
            self.client?.URLProtocolDidFinishLoading(self)
        }.resume()
    }
    
    override func stopLoading() {}
    
    
    func URLSession(session: NSURLSession, task: NSURLSessionTask, willPerformHTTPRedirection response: NSHTTPURLResponse, newRequest request: NSURLRequest, completionHandler: (NSURLRequest?) -> Void) {
        
        self.client?.URLProtocol(self, wasRedirectedToRequest: request, redirectResponse: response)
        
    }
    
    
    func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
        self.client?.URLProtocol(self, didLoadData: data)
    }
    
    func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {
        self.client?.URLProtocol(self, didReceiveResponse: response, cacheStoragePolicy: NSURLCacheStoragePolicy.Allowed)
    }
    
    func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
        if error != nil{
            self.client?.URLProtocol(self, didFailWithError: error!)
        }else{
            self.client?.URLProtocolDidFinishLoading(self)
        }
    }
}

上記のプロトコルに処理させるための実装

// 有効化
NSURLProtocol.registerClass(CaptureProtocol)

// NSURLSessionから利用
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.protocolClasses = [CaptureProtocol.self]

この実装さえしておけばこのコンフィギュレーションを使ってNSURLSessionからリクエストを送れば監視できる。

ちょっと無理やり感もあるが、webviewでのリクエストをフックしたいというときにいちいちdelegateにいろいろ書いていると親WebViewに手を加えなければいけなかったり、もともと使っている実装には非常に面倒だ。
このやり方の場合、NSURLProtocolを継承したクラスを作って、どっかで有効化してやればいいので既存のコードは汚さないでいい。

使いどこは選ぶが、使いようによっては便利だと思う。

45
44
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
45
44

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?