iOS 14からMultipeer ConnectivityがErrorCode -72008で繋がらなくなったときの解決方法

# はじめに

LiDARセンサー付きの iPhone がどうしても欲しくて、最近自身のスマホを iPhone 12 Pro に機種変更しました。
早速、LiDARセンサーの性能を試すべく、Multipeer Conectivity で連携できる自作のARアプリをiPhone 12 ProにXcodeでビルドし、あらかじめ用意してあったもう一台のiPhoneとともにアプリを立ち上げたのですが、

**あれ？デバイス同士の連携ができない......？**

と異変に気づき、Xcode でコンソールを確認してみると、

```
2020-12-01 00:34:28.593776+0900 MCSample[28078:11026553] [MCNearbyServiceBrowser] NSNetServiceBrowser did not search with error dict [{
    NSNetServicesErrorCode = "-72008";
    NSNetServicesErrorDomain = 10;
}].
2020-12-01 00:34:28.593778+0900 MCSample[28078:11026556] [MCNearbyServiceAdvertiser] Server did not publish: errorDict [{
    NSNetServicesErrorCode = "-72008";
    NSNetServicesErrorDomain = 10;
}].
```

という今まで見たことのないエラーログが出ているではありませんか...！
[「なぁにこれぇ」って武藤遊戯みたいな反応](https://www.youtube.com/watch?v=Ig1OdKm16cE) になったのですが、調べまくってなんとか解決できたので、ここにその方法を残しておこうと思います。

# エラーの原因

今回上記のエラーが発生した iPhone 12 Pro は初期搭載OSバージョンが iOS 14.1でした。
手元でさまざまなOSバージョンの端末で試してみたのですが、そもそも上記のエラーは **iOS 14から発生している**ことがわかりました。
そのことから、iOS 14から追加された新機能に絞って調べてみると、[WWDC 2020 の Support local network privacy in your app のセッション](https://developer.apple.com/videos/play/wwdc2020/10110/) で、**iOS 14からローカルネットワークへの通信にユーザの許可が必要になった**ことがわかり、そのための追加実装が抜けていたことが今回のエラーの原因だったとわかりました。

# 解決する方法

このエラーを解決する方法はApple公式ドキュメントである [Discovering Peers with MultipeerConnectivity | Apple Developer Documentation](https://developer.apple.com/documentation/nearbyinteraction/discovering_peers_with_multipeerconnectivity) の「Add Bonjour Services Plist Keys」の章にちゃんと記載されていました。
が、ドキュメントを読んでいて、解釈が少々わかりづらいポイントがあったので、その点については後述します。

## ① ローカルネットワークの利用許可ダイアログの説明文を追加する

まず、今回の対応を行うことで表示されるようになる以下のダイアログの説明文を`Info.plist`に追加します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46227/9d0688cf-6e15-43b1-81c5-dfb92c692434.jpeg" width=350>

Property Listから追加する場合は、`Privacy - Local Network Usage Description`の値に 利用許可を求める説明文 を追加しましょう。

![スクリーンショット 2020-12-01 1.38.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46227/5065cf38-1172-0896-f05d-038f3b90036d.png)

Source Codeから追加する場合は、以下のように追記しましょう。

```
<key>NSLocalNetworkUsageDescription</key>
<string>利用許可を求める説明文</string>
```

## ② Bonjour サービスで検索するサービス名の追加

Bonjour（ボンジュール）って急にフランス語が出てきて草生えたのですが、
Bonjour とは、Apple社が開発・提供し、Mac/iPhoneに標準装備されている**ネットワーク機器を何の設定も行わず簡単に接続するための技術** の名称でした。
https://developer.apple.com/bonjour/

iOS 14以降の Multipeer Connectivity では、Bonjour サービスで検索するために、`Info.plist`に検出してもらうサービス名を追加する必要があります。

ここで、公式ドキュメントである [Discovering Peers with MultipeerConnectivity | Apple Developer Documentation](https://developer.apple.com/documentation/nearbyinteraction/discovering_peers_with_multipeerconnectivity) の「Add Bonjour Services Plist Keys」の章を見直してみると、`NSBonjourServices`に追加する`._tcp`と`._udp`のプレフィックスはそれぞれ`_myAppName`と記載されています。**ここが大きなハマりポイントでした。**

最初ドキュメントを見たときに、`_myAppName` って Product Name もしくは Display Name のことかな？ と思って試してみたのですが、**全然違いました 😇**
困り果ててググってみると、 [Apple Developer Forums で同じ問題に対するQ&Aの回答](https://developer.apple.com/forums/thread/660994?answerId=641309022#641309022) を発見し、完全に理解しました。
`_myAppName`とは、[MCNearbyServiceAdvertiser](https://developer.apple.com/documentation/multipeerconnectivity/mcnearbyserviceadvertiser) と [MCNearbyServiceBrowser](https://developer.apple.com/documentation/multipeerconnectivity/mcnearbyservicebrowser) の生成時に共通で使用する **[serviceType: String](https://developer.apple.com/documentation/multipeerconnectivity/mcnearbyservicebrowser/1407110-servicetype)** の先頭に`_`を加えた文字列のことだったのです。

なので、`Info.plist`には、

Property Listから追加する場合は、以下のように `Bonjour services` の Array に 
`_serviceType._tcp` と `_serviceType._udp` の Item をそれぞれ追加しましょう。

![スクリーンショット 2020-12-01 2.22.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46227/5a64e3eb-4b28-b0a9-c2b2-717bb8a6cb18.png)

Source Codeから追加する場合は、以下のように追記しましょう。

```
<key>NSBonjourServices</key>
<array>
    <string>_serviceType._tcp</string>
    <string>_serviceType._udp</string>
</array>
```

以上の①、②の対応を行い、再度ビルドすることで無事にエラーが出なくなり、連携できるようになりました。

# まとめ

- iOS 14以降で Multipeer Conectivity を利用するには、**ローカルネットワークの利用許可ダイアログの説明文**と**Bonjour サービスで検索するサービス名**の`Info.plist`への追加が必要になった
- 対応方法が記載されている [Discovering Peers with MultipeerConnectivity | Apple Developer Documentation](https://developer.apple.com/documentation/nearbyinteraction/discovering_peers_with_multipeerconnectivity) の「Add Bonjour Services Plist Keys」の章の`_myAppName`には [MCNearbyServiceAdvertiser](https://developer.apple.com/documentation/multipeerconnectivity/mcnearbyserviceadvertiser) と [MCNearbyServiceBrowser](https://developer.apple.com/documentation/multipeerconnectivity/mcnearbyservicebrowser) の生成時に共通で使用する **[serviceType: String](https://developer.apple.com/documentation/multipeerconnectivity/mcnearbyservicebrowser/1407110-servicetype)** の先頭に`_`を加えた文字列を使うことが正解

# 参考リンク一覧

- [Multipeer iOS 14 Error -72008 | Apple Developer Forums](https://developer.apple.com/forums/thread/659563)
- [Error on Multipeer Connectivity after updating to Xcode 12 and iPadOS 14 | Apple Developer Forums](https://developer.apple.com/forums/thread/660994)
- [Discovering Peers with MultipeerConnectivity | Apple Developer Documentation](https://developer.apple.com/documentation/nearbyinteraction/discovering_peers_with_multipeerconnectivity)
- [iOS 14でローカルネットワークの利用 - Qiita](https://qiita.com/KenNagami/items/e0a603221def205b71ea)