Proxyman for iOS を使う！

[前回の記事](https://qiita.com/a_jike/items/52d22287a0ea6eb1cf5b)が地味にじわじわヒッソリとLGTM頂いているのでここでもう一つ、iOS実機で使用する方法を実際に使用しながら検証し記事に起こしてみた。

最終的にわかったことで結論から言うと、
iOS上でMap/Breakpoint/Scriptingなどでプロキシできることを期待していたが、
実際は**レスポンス内容を見たり、コピーしたりすることしかできなかった**......
というサゲでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/fd786a17-4407-5236-3d33-99d0d52f1850.png)
https://proxyman.io/ios

COMING SOON....
うーん、やられた。。
年間でライセンス更新しないといけないのでCOMING SOONとロックアイコン無くなってからライセンス更新したほうが良いと思う。。（2022/06/21現在）

じゃあなんで存在してるんだっていうと

* 全てのトラフィック、ネットワークアクティビティを監視できる！
* macOS版とシームレスにログ共有できる！

が今のところふれ込みのようで今後、デバッギングツールとしての発展を期待するしかなさそう。

目的が達成できなかったのが残念だが、とりあえずはレスポンス内容確認とかできるところまで記した内容を公開しておきます。。

# iOSアプリのインストール
[Proxyman for iOS](https://apps.apple.com/us/app/proxyman/id1551292695) は無料でインストール可能。
ただし、iOS上で機能をフルに使用する場合 有料ライセンスを購入する必要がある。

https://proxyman.io/pricing

## ライセンス更新
私のライセンスは３月に切れてしまっていたのでmacOSアプリの方でRenewする。
ライセンスキーってどこにあるか？
→ 登録メールアドレス宛に初回登録時に「[Proxyman] License Key」というタイトルで `PXM-` から始まるキー情報が来ていると思うのでそれをコピーしておく。

1. Proxyman > License... ウインドウを開く
1. Expiredしている旨のメッセージ横にある「Renew」ボタンを押す
1. ライセンスキーを入力
1. その後の決済処理を済ます



更新完了
![q_proxyman_ios_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/7c153b01-3c7c-edaf-12a9-67f49c1ccd91.png)


## 設定してみる
### 自分のアプリの通信をキャプチャ可能にしておく
Proxyman for iOSを起動するとHome画面はこんな感じ。
![q_proxyman_ios_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/7dc49c9f-2ce1-159b-0cbf-1eaf21e06e00.png)

Moreタブを選択して「Capture Traffic」をONにする
|before|after|
|---|---|
|![q_proxyman_ios_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/26525902-bede-2bd5-8abf-6c16d0a79c67.png)|![q_proxyman_ios_2-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/1cf76df6-8d84-eac3-29f2-5e8ce1075282.png)|

## 自分のアプリの通信がキャプチャされるか試す

1. 自分のアプリを起動する
1. 何か通信してみる

|1|2|
|---|---|
|![q_proxyman_ios_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/943551db-1cc8-b06a-74fa-d10093d2927a.png)|![q_proxyman_ios_3-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/e2ebb8cb-1151-9bf4-44f7-2ef4462ecd5c.png)|

因みに自分のアプリのソースはSwiftUIで以下のように中央に配置したボタンを押したら `script.google.com` 通して固定のJSONを返すマクロ実行するだけのサンプルアプリ
```Swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        Spacer(minLength: 100)
        VStack {
            HStack {
                Spacer(minLength: 100)
                Button("Send") {
                    let url = URL(string: "https://script.google.com/macros/s/＜ID＞/exec")!  // ＜ID＞には７２桁の任意のIDが入ります
                    let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
                        if let error = error {
                            print("Error: \(error.localizedDescription) \n")
                            return
                        }
                        
                        guard let data = data, let response = response as? HTTPURLResponse else {
                            print("No data or No response")
                            return
                        }

                        if response.statusCode == 200 {
                            let string = String(data: data, encoding: .utf8)
                            print(string)
                        } else {
                            // レスポンスのステータスコードが200でない場合などはサーバサイドエラー
                            print("サーバエラー ステータスコード: \(response.statusCode)\n")
                        }
                    }
                    task.resume()
                }
                Spacer(minLength: 100)
            }
        }
        Spacer(minLength: 100)
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
```

Google Apps Scriptの方では↓のようなレスポンスを返すようにしている。

```javascript
function doGet(e) {
  return ContentService.createTextOutput(JSON.stringify({'items': [{"id": "0", "name": "Zero"}, {"id": "1", "name": "One"}, {"id": "2", "name": "Two"}]}))
    .setMimeType(ContentService.MimeType.JSON);
}
```

## 証明書関連を設定しておく

これ系アプリの中でおそらく最も重要なステップ

|番|項目|スクショ|
|---|---|---|
|1|More > Certificate に移動|![q_proxyman_ios_4-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/8b720d84-9143-7b3f-3461-61d9d5ea5680.png)|
|2|ウォークスルー画面使って設定するか聞いてくる（選択肢ないけど）|![q_proxyman_ios_4-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/1cca1bd0-c3f1-e1d0-6502-78d5c4944dd5.png)|
|3|ウォークスルー画面１|![q_proxyman_ios_4-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/b4e1f712-05a9-f8d5-3034-1630ccf726f4.png)|
|4|ウォークスルー画面２<br />SSL証明書ダウンロードのため表示されているように「Allow」を選択してダウンロードする|![q_proxyman_ios_4-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/11773b35-00ee-6302-a637-cafbed1487bc.png)|
|5|ウォークスルー画面３<br />ダウンロードされたら表示されているようにインストールする|![q_proxyman_ios_4-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/c66663fa-2403-ecae-d909-e6fdec0ed6a9.png)|
|6|iOS設定 > 一般|<table border="0"><tr><td>最下部の「証明書信頼設定」</td><td>該当する証明書をONに</td><td></td></tr><tr><td><img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/3b84db98-8afe-52fe-a780-a3df5dbac886.png"></td><td><img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/d6c3a503-e8c9-e7be-4da5-34312a5dae0f.png"></td><td><img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/ab654ca4-1f95-31b0-b148-6fea04bf4852.png"></td></tr></table>|


Get Startedして画面が戻る。
「All Good!」は押しても特にアクションはない。

<img width="375" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/18f388ca-fc59-527a-90bb-27a7a8ce5f7e.png">

## レスポンス確認
macOS版とは異なり、プロセスごとのまとまりはない模様でHome画面でホストごとの一覧となっている。

### 暗号化を解く
まずはSSL証明書を有効化して、レスポンスを確認する

|番|項目|スクショ|
|---|---|---|
|1|[前述](https://qiita.com/drafts#自分のアプリの通信がキャプチャされるか試す)のサンプルアプリで通信を行うと `script.googleusercontent.com` がリストに出てくるので選択する。|<img width="375" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/24c8160c-764e-8fe9-f67c-67d9509cb7f5.png">|
|2|認識はされているが、暗号化されていて内容が確認できない状態|<img width="375" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/f76bd867-4eeb-d019-f496-d268d6202e47.png">|
|3|選択すると、Request/Responseが確認できる。「View Body」を見るとSSLプロキシを有効化するメッセージが表示されているので有効化する|<table><tr><td><img width="375" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/fe06359e-ce7f-a6d6-16d7-cdc0865bb44c.png"></td><td><img width="375" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/124f0e33-abcd-24e1-5d7c-4f68b336efb2.png"></td><td><img width="375" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/7a79cddf-96b3-08dc-c61d-f971f1ab1bab.png"></td></tr></table>|
|4|再度、サンプルアプリで通信を行うと正常にキャプチャされていることがわかる|<table border="0"><tr><td><img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/10b30ad1-0d9c-efb7-7684-c72a75bf184f.png"></td><td><img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/4b21f118-c730-8f6a-1722-bb992abd4b94.png"></td><td><img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/07bfcea3-548c-84d6-83dd-b0e6af87146c.png"></td></tr></table>|

今回は目的が達成できなかったのでここまで。
続きはProxyman for iOSで Map Local/Breakpoint/Scriptingに対応してから続きを書こうと思う。
無念。