WiresharkのPermissionエラーの対応(iPhoneのパケットをキャプチャしたい場合)
動機
iOSアプリを開発中、サーバーからレスポンスが来ないのでパケットをキャプチャするためにWiresharkを使ったのですが、 その時にPermissionエラーが発生したのでその対応策を残しておきます。
前提
下記サイトで、Macに接続したパケットを取得するための設定を行っていること。 qiita.com
事象
Wiresharkのキャプチャオプションで 「rvi0」のネットワークインターフェースを選択した際に、エラーが発生。
デバイスにキャプチャを取るための権限が無いと言っているので、権限を与えてやりましょう。
手順
1. 次のコマンドを入力する
cd /dev ls -la | grep bp
ユーザー名とグループ名がユーザー自身ではないことを確認します。
※ちなみにbpとはbpf(Berkeley Packet Filter)のことで、キャプチャしたパケットをフィルタリングするものです。 (自分も詳しくないので興味がある方は、「linux bpf」とかでググってみてください)
2. bpfの所有権のユーザー名を自分自身に、グループ名をadminにします。
sudo chown uematsu:admin bp*
3. 所有権が変更されていることを確認します。
ls -la | grep bp
これで権限の変更は終了です。 再度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
ポイント
- CalculationListenerオブジェクト生成時、リスナー(CalculationListener)に通知先(MainActivity)を教えておく。
- CalculationListenerで計算したあと、インタフェースを通して通知先に計算結果を教えてくれる。
まとめ
MainActivityを自分自身だとすると、
自分の連絡先を警察に教えておき、財布がみつかったら教えた連絡先に電話してください。
のような感じ。