[iOS][Android] NFCタグを使ってスマホアプリを起動する

# やりたいこと
NFCタグにスマホを近づけてアプリを起動する
対象は　Android/iOS 両方。
実現するには、NFCタグへの情報書き込みとアプリの実装などが必要となります。

# 1. NFCタグへの書き込み
NFCタグへの書き込みは　[NFC Tools](https://play.google.com/store/apps/details?id=com.wakdev.wdnfc&hl=ja) を利用しました。
登録したNDEFレコードは以下の２つです。
　1. Data　(MIME)
　2. URL/URI
　3. アプリ(Android)

## 1.1 Data(MIME)レコード
Androidアプリを起動するための情報です。
| 項目 | 内容 |
|:-:|:-:|
| content-type | application/{ユニークなURI} |
| データ | 任意のテキスト |

ここではcontent-type は以下とします。
`application/vnd.dev.sunskysoft.myapp`
詳細は以下を参照。
https://developer.android.com/guide/topics/connectivity/nfc/nfc?hl=ja#mime

## 1.2 URL/URIレコード
iOS の UniveralLink のための情報です。
アプリ起動用の　URL として利用したい URL を登録してください。
**URLは実在するものである必要があります。**
ここでは以下とします。
`https://myapp.sunskysoft.dev`

## 1.3 アプリ(Android)レコード  （2023/1/21　追記）
Androidのアプリレコードを追加することで、アプリがインストールされていないAndroid端末で、　Google Play Store が開くようになります。
Android版の　NFC Tools を使って登録しましょう。
これはAARと呼ばれる仕組みで、詳しくは以下を参照ください。
[Androidアプリのレコード](https://developer.android.com/guide/topics/connectivity/nfc/nfc.html?hl=ja#aar)

# 2. iOSアプリの対応
UniversalLink という手法でアプリの起動を実現します。
対応は、アプリ側とWebサイト側の両方が必要です。

## 2.1 アプリ側の対応
Xcode上から Capability　に　Associated Domains を追加し、URLを登録します。
1. "Signing & Capabilities" 画面で "+ Capability" をクリックし、"Associated Domains" を追加します。
2. "Domains" に "applinks:{URL}" を追加します。 
ここでは　`applinks:myapp.sunskysoft.dev` を追加します。
（古い情報では "step" が表示されるというものが見受けられますが、Xcode 14 では表示されないようです。）

<details><summary>Signing が Automatically manage signing ON でない場合</summary>

Signing が Automatically manage signing ON でない場合は、以下の手順も必要となります。
① Apple Developer Programにアクセス
② Certificates, Identifiers & Profiles > Identifier > App IDs を選択
③ 利用する App IDs を編集して Associated Domains を Enabled に変更
</details>

## 2.2 Webサイト側の対応
Webサーバーのドメインルートに　`apple-app-site-association`　というファイルを置く必要があります。
ここでは `https://myapp.sunskysoft.dev` を対象にしてますので、このWebサーバーのドキュメントルートに配置します。

今回は　Laravel を利用したサイトを想定して、配置場所は以下とします。
`{Laravel Project}/public`

```json:apple-app-site-association
{
  "applinks": {
    "apps": [],
      "details": [
        {
          "appID":"{Team ID}.dev.sunskysoft.myapp",
          "paths":[ "*" ]
        }
      ]
    }
}
```
このファイルは　JSONファイルとして認識されないといけないため、Content-type が　application/json になるように同じフォルダ内の　.htaccess ファイルに以下を追記します。

```text:.htaccess
<Files apple-app-site-association>
    ForceType application/json
</Files>
```


# 3. Androidアプリの対応
詳細は以下を参照。
https://developer.android.com/guide/topics/connectivity/nfc/nfc?hl=ja#mime

## 3.1 AndroidManifest
NFC NDEFを検出した際に起動したい　Activity に　intent-filter を追加します。
```xml:AndroidManifest.xml
    <activity
        :
           <intent-filter>
               <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
               <category android:name="android.intent.category.DEFAULT"/>
               <data android:mimeType="application/vnd.dev.sunskysoft.myapp" />
           </intent-filter>
```

# 4. 実現できたこと
以上の対応で以下が実現できました。
<dl>
  <dt>iOSアプリ</dt>
  <dd>1. NFC を近づけると、アプリを起動する通知が表示される</dd>
  <dd>2. 通知をタップする</dd>
  <dd>3. アプリが起動する</dd>
  <dt>Androidアプリ</dt>
  <dd>1. NFC を近づける</dd>
  <dd>2. アプリが起動する</dd>
</dl>

これらは共に認証（サインイン）が必要です。
iOS の場合は検知後に認証可能ですが、Android は認証後でないとNFCを検知しないという違いがあるようです。

## 4.1 レコードの順序
今回は Data, URL の順で　NFCタグにレコードを書き込みましたが、逆順に書き込むとどうなるでしょう？
結果は以下の通り。

|  | Data -> URLの順 | URL -> Dataの順 |
|:-:|:-:|:-:|
| iOS | １つ目のDataは無視され<br>URLに反応して通知表示 |　１つ目のURLに反応し通知表示 |
| Android | １つ目のDataに反応して<br>アプリを起動| １つ目のURLに反応して<br>ブラウザ系アプリ選択を表示 |

なので、Data, URLの順がよい感じです。
ただしアプリがインストールされていない場合は、Androidでは１つ目のDataレコードを処理できずにOS標準の「収集された新しいタグ」画面が表示されてしまいます。

（2023/1/21　追記）
と、上記は　アプリ（Android)レコードを追加するまでの話。
AARを追加することで、アプリがインストールされていないAndroid端末では、Google Play Store が表示されるようになり、URLには反応しなくなります！

# 後記
今回はとりあえず、NFCタグからアプリを起動するところまでを実現できました。
タグ情報の内容やアプリの実装次第ではもっと工夫できるかもしれません。
また、実用性を高めるなら、その後引き続きNFCの情報が読めるようになると良いかと思いましたので、それはまたそのうちに。。。

(2023/1/22 追記）
[[Android] NFCタッチからアプリ起動と同時にタグを読み込む](https://qiita.com/sunskysoft/items/2434554577a0cbb8cb1e)　を投稿しました！