Android/iOSで他アプリに簡単な値を送る方法

# はじめに
AndroidやiOSアプリを開発していて、自分のアプリから他のアプリを開きたい、簡単なコードを送って連携したい、そういうことはないでしょうか？実装していてちょっと苦労したのでメモがわりに残しておこうと思いました

# Android
![Android-App-Transition.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/924658/429ba76f-4a72-e91f-4391-91a27d361e1c.gif)

## 実装
### 送信側でやること

```MainActivity.kt
val sendIntent: Intent = Intent().apply {
                action = Intent.ACTION_SEND
                // 送信先アプリに送りたい文字列
                putExtra(Intent.EXTRA_TEXT, "C9C7BFC1-6397-4681-96CE-9C1BC1BA3745")
                // 送信先アプリのクラスを指定
                setClassName("com.sample.receiveappmessagesample", "com.sample.receiveappmessagesample.MainActivity");
                // 送信するデータの形式
                type = "text/text"
            }
            startActivity(sendIntent)
```
ちなみにテキスト以外にも画像なども送信できるようです。ちなみに送信に失敗すると`ActivityNotFoundException`が出ます

### 受信側でやること
```MainActivity.kt
class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(findViewById(R.id.toolbar))

+       if (intent?.type == "text/text") {
+           // 受信したらデータをToastに表示する
+           Toast.makeText(applicationContext, intent?.getStringExtra(Intent.EXTRA_TEXT), Toast.LENGTH_LONG).show()
+       }
+   }
    // 〜略〜
}
```

Manifestにも修正が必要かと思いきや、かなり簡単ですね

# iOS
![iOS-App-Transition.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/924658/7df7c879-e637-3340-cc49-bee46641d20d.gif)

## 実装
### 送信側でやること
ボタンタップをトリガーに動くようにしています。iOSの場合はカスタムURLスキーマという形で送信します。iOS10より前のバージョン向けの条件がありますが、iOS10ユーザは現時点でかなり少ないので不要かなと思います

```MainController.swift
    @IBAction func touchDownButton(_ sender: Any) {
        // [送信先アプリに送るURL]://?[送信するパラメータ]
        let url = URL(string: "test.scheme://?view_id=B438019A-2E7D-4D79-A077-FC56FEC30DC1")!
        if UIApplication.shared.canOpenURL(url) {
            if #available(iOS 10.0, *) {
                UIApplication.shared.open(url, options: [:], completionHandler: {
                    (success) in
                    print("Open \(success)")
                })
            }else{
                UIApplication.shared.openURL(url)
            }
        }
    }
```

iOSの場合、info.plistの編集も必要です。[TARGETS] > [Info] > [Custom iOS Target Properties]にLSApplicationQueriesSchemesを追加し、送信するURLを定義します

![send_infop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/924658/cf1b99a3-a4af-c24f-7342-df87c8063110.png)

iOSの場合も、送信に失敗すると下記のようなエラーが出ます
`-canOpenURL: failed for URL: "test.schemexxx://?view_id=B438019A-2E7D-4D79-A077-FC56FEC30DC1" - error: "The operation couldn’t be completed. (OSStatus error -10814.)"`

### 受信側でやること
受信したら適当にダイアログを表示することにしました

```SceneDelegate.swift
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    // 〜 略 〜 //
+   func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
+       guard let url = URLContexts.first?.url else {
+           return
+       }
+       let comp = NSURLComponents(url: url, resolvingAgainstBaseURL: false)
+       guard let queryValue = comp?.queryItems?.first?.value else {
+           return
+       }
+
+       let viewController = self.window!.rootViewController as! ViewController
+       viewController.showDialog(id: queryValue)
+   }
    // 〜 略 〜 //   
}
```

受信側のinfo.plistにも設定が必要です。URL Typesに受信したいURLを定義します

![receive_infop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/924658/85f658c2-4273-efcf-973b-75b28141dbaf.png)

# 最後に
どちらにしても、これらの方法でアプリ間メッセージ送信する場合、セキュアなデータは渡さないのが無難です。[カスタムURLスキームの乗っ取りとその対策](https://akaki.io/2021/url_scheme_hijack)ということもありますので。