Skip to content

yoshimin/NearbyInteractionDemo

Repository files navigation

Nearby Interaction

https://developer.apple.com/videos/play/wwdc2020/10110/

Overview

Locate and interact with nearby devices using identifiers, distance, and direction.

Range, Orientation, and Line of Sight to interact with a nearby device

There are restrictions for NI to work best.

  • Within nine meters of each other.
  • In portrait orientation.
  • Facing each other with their back camera.

https://developer.apple.com/documentation/nearbyinteraction/initiating_and_maintaining_a_session

I can get a unit vector that points from the user in the direction of the tracked object addition to a distance. I can direction as a Cartesian triplet (x,y,z) in normalized units with a range of [0..1]. NI models direction as a coordinate on the unit sphere pointing toward the nearby object. The coordinate system is relative to the center of the device’s body. As the user looks at the device’s screen,

  • The x-axis extends positively to the right.
  • The y-axis extends positively upward.
  • The z-axis extends negatively starting at the device and moving away from the user.

https://developer.apple.com/documentation/nearbyinteraction/ninearbyobject/3601347-direction

Prepare

  1. Add NSLocalNetworkUsageDescription to Info.plist
    A message that tells the user why the app is requesting access to the local network.
<key>NSNearbyInteractionAllowOnceUsageDescription</key>
<string>XXXXXXXXXXXXXXX</string>
  1. Add NSBonjourServices to Info.plist
    Bonjour service types browsed by the app.
<key>NSBonjourServices</key>
<array>
	<string>_ni-demo._tcp</string>
</array>

Flow

image

Implement

1-2. startAdvertisingPeer / startBrowsingForPeers

let peerID = MCPeerID(displayName: UIDevice.current.name)
let appId = "com.sample.NearbyInteractionDemo"
let serviceType = "ni-demo"

let session = MCSession(peer: peerID, securityIdentity: nil, encryptionPreference: .required)
session.delegate = self

let advertiserDelegate = NearbyServiceAdvertiserDelegate(session: session)
// MEMO: serviceType needs to be 15 characters or fewer
let advertiser = MCNearbyServiceAdvertiser(peer: peerID, discoveryInfo: ["appId": appId], serviceType: serviceType)
advertiser.delegate = self

let browserDelegate = NearbyServiceBrowserDelegate(appId: appId, session: session)
let browser = MCNearbyServiceBrowser(peer: peerID, serviceType: serviceType)
browser.delegate = self

advertiser.startAdvertisingPeer()
browser.startBrowsingForPeers()
  1. invitePeer

MCNearbyServiceBrowserDelegate#browser(_:foundPeer:withDiscoveryInfo:) is called when a nearby peer is found.

func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) {
    browser.invitePeer(peerID, to: session, withContext: nil, timeout: 10)
}
  1. receive invitation from peer

MCNearbyServiceAdvertiserDelegate#advertiser(_:didReceiveInvitationFromPeer:withContext:invitationHandler:) is called when an invitation to join a session is received from a nearby peer.

func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: Data?, invitationHandler: @escaping (Bool, MCSession?) -> Void) {
    invitationHandler(true, session)
}
  1. send NIDiscoveryToken

  2. get NIDiscoveryToken from NISession

  3. send NIDiscoveryToken to connected peers using MCSession#send(_:toPeers:with:)

let nisession = NISession()
nisession.delegate = self

guard
  let discoveryToken = nisession.discoveryToken,
  let data = try?  NSKeyedArchiver.archivedData(withRootObject: discoveryToken, requiringSecureCoding: true)
else {
  fatalError("failed to prepare discovery token.")
}

session.send(data, toPeers: session.connectedPeers, with: .reliable)
  1. run NISession with NIDiscoveryToken

MCSessionDelegate#session(_:didReceive:fromPeer:) is called when NIDiscoveryToken is received from a nearby peer.

func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
  guard let discoveryToken = try? NSKeyedUnarchiver.unarchivedObject(ofClass: NIDiscoveryToken.self, from: data) else {
    fatalError("Unexpectedly failed to decode discovery token.")
  }
  let config = NINearbyPeerConfiguration(peerToken: discoveryToken)
  nisession.run(config)
}
  1. update nearbyObjects

NISessionDelegate#session(_:didUpdate:) is called when the session updates nearby objects.

NISessionDelegate#session(_:didRemove:reason:) is called when the session removes one or more nearby objects.

func session(_ session: NISession, didUpdate nearbyObjects: [NINearbyObject]) {
  // get distance(Float?) and direction(simd_float3?) from NINearbyObject
}

func session(_ session: NISession, didRemove nearbyObjects: [NINearbyObject], reason: NINearbyObject.RemovalReason) {
}

About

NearbyInteraction Framework x ComposableArchitecture x SwiftUI

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages