ush109rockのブログ

主にiOS/Androidの情報を発信していきます。

WiresharkのPermissionエラーの対応(iPhoneのパケットをキャプチャしたい場合)

動機

iOSアプリを開発中、サーバーからレスポンスが来ないのでパケットをキャプチャするためにWiresharkを使ったのですが、 その時にPermissionエラーが発生したのでその対応策を残しておきます。

前提

下記サイトで、Macに接続したパケットを取得するための設定を行っていること。 qiita.com

事象

Wiresharkのキャプチャオプションで 「rvi0」のネットワークインターフェースを選択した際に、エラーが発生。

f:id:ush109rock:20180420173357p:plain

バイスにキャプチャを取るための権限が無いと言っているので、権限を与えてやりましょう。

手順

1. 次のコマンドを入力する

cd /dev
ls -la | grep bp

ユーザー名とグループ名がユーザー自身ではないことを確認します。

f:id:ush109rock:20180420174151p:plain

※ちなみにbpとはbpf(Berkeley Packet Filter)のことで、キャプチャしたパケットをフィルタリングするものです。 (自分も詳しくないので興味がある方は、「linux bpf」とかでググってみてください)

2. bpfの所有権のユーザー名を自分自身に、グループ名をadminにします。

sudo chown uematsu:admin bp*

3. 所有権が変更されていることを確認します。

ls -la | grep bp

f:id:ush109rock:20180420174220p:plain

これで権限の変更は終了です。 再度Wiresharkのキャプチャオプションで 「rvi0」を選択してみてください。 パケットがキャプチャできるはずです。

URLSessionを用いた通信

背景

モバイルアプリ作っていると、APIで外部からデータを引っ張ってきたいと思うことが良くあります。 そういったときにAlamofireなどのサードパティーのライブラリを使いがちで、URLSessionを使ったことがない人がまあまあいると思います。そこでURLSessionを用いた基礎を書いていきます。

必要クラス

URLSession

ダウンロード周りのAPIを提供するクラス。
通信に必要なセッションを生成する。

URLSessionConfiguration

ダウンロードやアップロードする際、必ず設定すべき最初の手順。
バックグラウンド動作の有無や、タイムアウト時間など様々な設定をすることができる。

URLSessionTask

ファイルなどをダウンロードするなどのタスクが、URLSessionによって実行される。
下記のサブクラスによって振る舞いを決定することができる

  • URLSessionDataTask:ダウンロードする(小さいデータ)
  • URLSessionDownloadTask:ダウンロードする(大きなデータ)
  • URLSessionUploadTask:アップロードする

URLRequest

プロトコルまたはURLスキームに依存しないリクエストを行うことができる。
URLRequestを使わない場合GETメソッドでのリクエストしかできないが、 URLRequestを使うとPOSTメソッドでのリクエストを行うことがきる。

使い方

上記のクラスを用いてGETメソッドとPOSTメソッドでリクエストを投げる最小構成を書いていきます。

GETメソッド

class HTTPClient {
    func get() {
        let config: URLSessionConfiguration = URLSessionConfiguration.default
        let session: URLSession = URLSession(configuration: config)
        let url: URL = URL(string: "http://example.com")!
        
        session.dataTask(with: url, completionHandler: { (data, response, error) in
            // do something
        })
    }
}

let client: HTTPClient = HTTPClient()
client.get()

POSTメソッド

class HTTPClient {
    
    func post() {
        let config: URLSessionConfiguration = URLSessionConfiguration.default
        let session: URLSession = URLSession(configuration: config)
        let url: URL = URL(string: "http://example.com/post")!
        var req: URLRequest = URLRequest(url: url)
        req.httpMethod = "POST"
        req.httpBody = "post test".data(using: .utf8)
        
        let task = session.dataTask(with: req, completionHandler: { (data, response, error) in
            // do something
            print(error!)
        })
        task.resume()
    }
}

let client: HTTPClient = HTTPClient()
client.post()

GETでもPOSTでも書き方はほぼ同じで、POSTのときはURLRequestでhttp methodとhttp bodyの指定が必要です。

独自リスナーの作り方

はじめに

あるクラスで処理を行ってその結果をActivityや別クラスに通知したい場合、どのようにすればよいか。 本記事では、独自でリスナーを作り、それを特定のクラスで受け取る例を書いていきます。

リスナーとは

あるイベントが発生してくれたことを通知してくれるもの。

登場人物

  • リスナー
    イベント発生通知をしてくれる。

  • インターフェース
    イベントの通知元と通知先の仲介役。基本的にインターフェースを通して通知先に通知する。

  • レシーバー
    イベントを受け取る。

具体例

Calculation

public class CalculationListener {

    private ResultInterface listener;

    public Calculation(ResultInterface listener) {
        this.listener = listener;
    }

    public void calc(int a, int b) {
        int sum = a + b;
        this.listener.result(sum);
    }
}

ResultInterface

public interface ResultInterface {
    void result(int sum);
}

MainActivity

public class MainActivity extends AppCompatActivity implements ResultInterface {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Calculation obj = new CalculationListener(this);
        obj.calc(10,20);
    }

    @Override
    public void result(int sum) {
        String msg = String.valueOf(sum);
        Log.d("MainActivity", msg);
    }
}

もしくは

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Calculation obj = new CalculationListener(new ResultInterface() {
            @Override
            public void result(int sum) {
                String msg = String.valueOf(sum);
                Log.d("MainActivity", msg);
            }
        });
        obj.calc(10,20);
    }
}

結果

MainActivity: 30

解説

上記コードにおける、登場人物。

  • リスナー → CalculationListener
  • インターフェース → ResultInterface
  • レシーバー → MainActivity

ポイント

  1. CalculationListenerオブジェクト生成時、リスナー(CalculationListener)に通知先(MainActivity)を教えておく
  2. CalculationListenerで計算したあと、インタフェースを通して通知先に計算結果を教えてくれる。

まとめ

MainActivityを自分自身だとすると、
自分の連絡先を警察に教えておき、財布がみつかったら教えた連絡先に電話してください。 のような感じ。