😎

シミュレータで試せるNearbyInteractionの最小実装(Swift)

2023/05/24に公開

はじめに

iOS 14 から NearbyInteraction とかあったなあというのを思い出しました。

iOS14の新機能、Nearby Interaction

デバイス間の相対位置が確認できるやつみたいです。

こんな感じでシミュレータでも確認ができます。
near

公式のサンプルもあるのですがトークンのやりとりに MultipeerConnectivity などを使わないといけないのでできるだけ少ないコードで動作確認できるものを目指してみました。

環境

  • Xcode 14.3
  • iOS 16.4

トークンの取得

NearbyInteraction を試すには NIDiscoveryToken を端末間でやりとりする必要があります。

ちゃんとしたアプリを作るなら CoreBluetoothMultipeerConnectivity などを使ってやりとりする必要があるかと思います。今回はシミュレータで動かしてみたかっただけなのでファイルに書き出してそのファイルを手動で渡すことにします。

MultipeerConnectivity 使ってやりたい方はこちらを参考にどうぞ(ファイルの読み書きしているところを書き換えればいけると思います)。

Multipeer ConnectivityでのP2P通信(Swift)

実装

ストーリーボードはこんな感じでラベルとボタンを置いただけです。

storyboard

コードはこんな感じで 50 行くらいでおさまりました👏

import UIKit
import NearbyInteraction

final class ViewController: UIViewController {

    // ここ書き換える
    private let isWriting = true

    @IBOutlet private weak var label: UILabel!
    private var session: NISession!
    private let tokenDirectoryPath = NSHomeDirectory() + "/Documents"
    private var tokenFilePath: String {
        return tokenDirectoryPath + "/token"
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        print("directoryPath: \(tokenDirectoryPath)")
        if NISession.deviceCapabilities.supportsPreciseDistanceMeasurement {
            session = NISession()
            session.delegate = self
        }
    }

    @IBAction private func tokenKonekone(_ sender: Any) {
        if isWriting {
            writeToken()
        } else {
            readToken()
        }
    }

    private func writeToken() {
        if let discoveryToken = session.discoveryToken,
           let token = try? NSKeyedArchiver.archivedData(withRootObject: discoveryToken, requiringSecureCoding: true) {
            FileManager.default.createFile(atPath: tokenFilePath, contents: token, attributes: nil)
        }
    }

    private func readToken() {
        if let data = FileManager.default.contents(atPath: tokenFilePath),
           let token = try? NSKeyedUnarchiver.unarchivedObject(ofClass: NIDiscoveryToken.self, from: data) {
            let config = NINearbyPeerConfiguration(peerToken: token)
            session.run(config)
        }
    }
}

extension ViewController: NISessionDelegate {

    func session(_ session: NISession, didUpdate nearbyObjects: [NINearbyObject]) {
        label.text = String(format: "%0.2f m", nearbyObjects.compactMap { $0.distance }.max() ?? 0)
    }
}

動作確認

シミュレータは iOS 16 未満か iOS 16.4 を使ってください。iOS 16.1 で確認してみましたが NISession() でクラッシュします。

参考:NISession creation not working

以下が実行手順です。

  1. シミュレータ A で private let isWriting = true の状態で実行
  2. コンソールにトークン保存用フォルダのパスが出力される
  3. Finder -> 移動 -> フォルダへ移動... を開きコピペして該当フォルダに移動
  4. シミュレータ A のアプリを停止
  5. シミュレータ B で private let isWriting = false の状態で実行
  6. 3同様にシミュレータ B のフォルダに移動
  7. シミュレータ B のアプリを起動したままシミュレータ A のアプリを起動
  8. シミュレータ A でボタンを押下してトークンを出力
  9. シミュレータ A のフォルダの token ファイルをシミュレータ B のフォルダに移動
  10. シミュレータ B でボタンを押下すれば完成!

おわりに

これでサクッと NearbyInteraction で遊べるようになりました✌️

U1 チップ対応端末も増えてきたのでいろいろ遊べる気がします。

参考サイト

Discussion