【Kotlin研修11日目】暗黙的インテントを用いたアプリケーション間の連携

# アプリケーション間の連携
[参考1: 他のアプリからのアクティビティの開始を許可する](https://developer.android.com/training/basics/intents/filters?hl=ja)
[参考2: 研修3日目](https://qiita.com/b150005/items/f2c1d8236ac5e9770f4f)
[参考3: 研修6日目](https://qiita.com/b150005/items/d72f35af46bc19a40f97)
[参考4: 研修11日目](https://qiita.com/b150005/items/2ed0ea9be1bddc942c01)
`アプリケーション`内部での`アクティビティ`や`フラグメント`、`サービス`間の連携(=`画面遷移`)は`インテント`を利用するが、`アプリケーション`間の連携においても`インテント`を利用する。

> ## インテント
> `アクティビティ`・`フラグメント`・`サービス`間の橋渡し役を担うクラス。
`遷移元`と`遷移先`の情報をもつ。

> `Intent`オブジェクトは、`アクティビティ`・`フラグメント`・`サービス`の起動を行う。

ただし、`アプリケーション`内部の場合と`アプリケーション`間の場合では`インテント`の宣言方法が変わる。

|条件|インテント|
|:--|:--|
|`アプリケーション`内部|`明示的インテント`|
|`アプリケーション`間|`暗黙的インテント`|

## 明示的インテント
`アプリケーション`内部で、起動する`アクティビティ`等のクラス名を**明示的**に宣言する`インテント`。

## 暗黙的インテント
`アプリケーション`内部から見て、起動する`アクティビティ`等のクラス名が不明である場合に、`URI`を指定することで`OS`に起動先を委ねる`インテント`。

なお、`アクティビティ`の起動に関しては、指定された`URI`で一つの`アプリケーション`に絞れない場合は、`OS`が`アプリチューザ`を表示することで起動する`アプリケーション`を`ユーザ`に指定させる。

![暗黙的インテント.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673880/da00b695-2cb3-3a04-b20f-7ee87cfbc850.png)
[出典: インテントとインテントフィルタ(図1)](https://developer.android.com/guide/components/intents-filters?hl=ja)

### URI
[参考: URI](https://ferret-plus.com/4637)
`Web上での住所`を表す`URL`と`Web上での固有ID`を表す`URN`の総称。
`Uri`クラスで定義される。

### アプリチューザ
`OS`が指定された`URI`で起動する`アプリケーション`を1つに限定できない場合に、`ユーザ`に対して`起動先アプリケーション`の選択を迫るために表示される`チューザダイアログ`。

![アプリチューザ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673880/c534af2b-1277-6588-c320-f4eb50489085.png)

## 定義

```kotlin:明示的インテントと暗黙的インテント
// 明示的インテント
Intent(packageContext: Context!, cls: Class<*>!)
// パラメータ
// packageContext: 起動元コンテキスト
// cls: Javaクラス化した起動先コンテキスト
// -> KotlinのクラスをJavaに変換する場合は、"<Kotlinクラス名>::class.java"と記述

// 暗黙的インテント
Intent(action: String!, uri: Uri!)
// パラメータ
// action: インテントが実行するアクションを表すIntentクラス定数
// uri: 起動先コンテキストのURI
```

### アクションを表すIntentクラス定数
[参考: インテント](https://tech.pjin.jp/blog/2013/04/18/android%E3%80%80intent%E3%82%AF%E3%83%A9%E3%82%B9%EF%BC%88%E6%9A%97%E9%BB%99%E7%9A%84%E3%81%AAintent%EF%BC%89%E3%80%90android-tips%E3%80%91/)

|定数名|内容|
|:--|:--|
|`ACTION_VIEW`|画面の表示|
|`ACTION_CALL`|電話の発信|
|`ACTION_SEND`|メールの送信|

### Uriオブジェクトの生成
`半角英数字`や`一部の半角記号`(=`ハイフン-`・`ピリオド.`・`アンダースコア_`・`チルド~`など)以外の`String`型の文字列を`Uri`型に変換する場合は、**事前に**`URLエンコーディング`を行う必要がある。

#### URLエンコーディング
`URL`として使用できない文字を`16進数`のコードに変換(=`エンコード`)して使えるようにすること。

`URLエンコーディング`を行う場合、`URLEncoder`クラスの`encode()`メソッドを利用する。

##### 定義

```kotlin
// 文字エンコードを指定したURLエンコーディング
URLEncoder.encode(s: String, enc: String): String
// s: String型文字列
// enc: 文字エンコード
```

#### String型 → Uri型への変換
[参考: 研修10日目](https://qiita.com/b150005/items/cb214a4ed4dcb60d9c39#string%E5%9E%8Buri%E5%9E%8B%E3%81%AE%E5%A4%89%E6%8F%9B)
`String`型を`Uri`型に変換(=`パース; 解析`)する場合、`Uri`クラスの`parse()`メソッドを利用する。

```kotlin
// エンコード済みのString型URIをUri型に変換
Uri.parse(uriString: String!): Uri!
// パラメータ
// uriString: Uri型に変換するString型URI
```

## サンプルコード

```kotlin:MainActivity.kt
// EditTextに入力されたString型文字列
var searchWord = etSearchWord.text.toString()

// 文字エンコードを指定したURLエンコーディング
searchWord = URLEncoder.encode(searchWord, "UTF-8")

// 指定した文字列で検索した地図アプリのString型URI
// -> "geo:<緯度>,<経度>?q=<検索文字列>" で表現
val uriStr = "geo:0,0?q=${searchWord}"

// String型 → Uri型 への変換
val uri = Uri.parse(uriStr)

// 暗黙的インテント(=Intentオブジェクト)の生成
val intent = Intent(Intent.ACTION_VIEW, uri)

// アクティビティの起動
startActivity(intent)
// <- Context.startActivity(intent: Intent!): Unit
```