如何使用 Apple 的 NearbyInteraction 框架连接多个设备(实现多个正在进行的会话)

Posted

技术标签:

【中文标题】如何使用 Apple 的 NearbyInteraction 框架连接多个设备(实现多个正在进行的会话)【英文标题】:How to connect multiple devices (implement multiple ongoing sessions) using Apple's NearbyInteraction Framework 【发布时间】:2021-02-20 01:46:30 【问题描述】:

我正在编写一个应用程序,该应用程序需要具有使用 Apple 的 NearbyInteraction 框架连接的多个 iPhone 的功能。我需要有多个正在进行的 NISession 才能在任何特定时间将多个 iPhone 相互连接。我一直在玩 Apple 提供的一个项目的示例代码,它只实现了一个允许一个会话在任何特定时间存在的程序。可以在以下位置找到:https://developer.apple.com/documentation/nearbyinteraction/implementing_interactions_between_users_in_close_proximity

我正在通过 MultipeerConnectivity 发送发现令牌(需要启动每个新会话),这似乎工作正常。下面的代码或多或少是 Apple 提供的代码,适用于一个会话。如果我使用另一部 iPhone 尝试创建第二个会话,我会从第二个设备接收到发现令牌(通过 MultiPeer 连接),但是当第二个会话应该同时启动时,两个会话都会失效并停止工作。

是否有人可以帮助我正确地指导我如何调整下面的代码以允许多个正在进行的会话连接多个设备?

func startup() 
    // Create the NISession.
    session = NISession()
    session?.delegate = self

    // Since the session is new, this token has not been shared.
    sharedTokenWithPeer = false

    // If 'connectedPeer' exists, share the discovery token if needed.
    if connectedPeer != nil && mpc != nil 
        if let myToken = session?.discoveryToken 
            print("Initializing...")
            if !sharedTokenWithPeer 
                shareMyDiscoveryToken(token: myToken) 
            
         else 
            fatalError("Unable to get self discovery token, is this session invalidated?")
        
     else 
        print("Discovering Peer...")
        startupMPC()
        currentDistanceDirectionState = .unknown
    


func session(_ session: NISession, didUpdate nearbyObjects: [NINearbyObject]) 
    guard let peerToken = peerDiscoveryToken else 
        fatalError("don't have peer token")
    

    // Find the right peer.
    let peerObj = nearbyObjects.first  (obj) -> Bool in
        return obj.discoveryToken == peerToken
    

    guard let nearbyObjectUpdate = peerObj else 
        return
    


func session(_ session: NISession, didRemove nearbyObjects: [NINearbyObject], reason: NINearbyObject.RemovalReason) 
    guard let peerToken = peerDiscoveryToken else 
        fatalError("don't have peer token")
    
    // Find the right peer.
    let peerObj = nearbyObjects.first  (obj) -> Bool in
        return obj.discoveryToken == peerToken
    

    if peerObj == nil 
        return
    

    switch reason 
    case .peerEnded:
        // Peer stopped communicating, this session is finished, invalidate.
        session.invalidate()

        // Restart the sequence to see if the other side comes back.
        startup()

    case .timeout:

        // Check the configuration is still valid and re-run the session.
        if let config = session.configuration 
            session.run(config)
        
        print("Peer Timeout")
    default:
        fatalError("Unknown and unhandled NINearbyObject.RemovalReason")
    



// Sharing and receiving discovery token via mpc mechanics

func startupMPC() 
    if mpc == nil 
        // Avoid any simulator instances from finding any actual devices.
        #if targetEnvironment(simulator)
        mpc = MPCSession(service: "nisample", identity: "com.example.apple-samplecode.simulator.peekaboo-nearbyinteraction", maxPeers: 7)
        #else
        mpc = MPCSession(service: "nisample", identity: "com.example.apple-samplecode.peekaboo-nearbyinteraction", maxPeers: 7)
        #endif
        mpc?.peerConnectedHandler = connectedToPeer
        mpc?.peerDataHandler = dataReceivedHandler
        mpc?.peerDisconnectedHandler = disconnectedFromPeer
    
    mpc?.invalidate()
    mpc?.start()


func connectedToPeer(peer: MCPeerID) 
    guard let myToken = session?.discoveryToken else 
        fatalError("Unexpectedly failed to initialize nearby interaction session.")
    
    print(peer.displayName)
    if connectedPeer.count > 1 
        //fatalError("Already connected to a peer.")
        print(connectedPeer)
    

    if !sharedTokenWithPeer 
        shareMyDiscoveryToken(token: myToken)
    

    connectedPeer.append(peer)
    peerDisplayName = peer.displayName


func disconnectedFromPeer(peer: MCPeerID) 
    if connectedPeer.contains(peer) 
        connectedPeer.removeAll(where: $0 == peer)
        sharedTokenWithPeer = false
    


func dataReceivedHandler(data: Data, peer: MCPeerID) 
    guard let discoveryToken = try? NSKeyedUnarchiver.unarchivedObject(ofClass: NIDiscoveryToken.self, from: data) else 
        fatalError("Unexpectedly failed to decode discovery token.")
    
    peerDidShareDiscoveryToken(peer: peer, token: discoveryToken)


func shareMyDiscoveryToken(token: NIDiscoveryToken) 
    guard let encodedData = try?  NSKeyedArchiver.archivedData(withRootObject: token, requiringSecureCoding: true) else 
        fatalError("Unexpectedly failed to encode discovery token.")
    
    mpc?.sendDataToAllPeers(data: encodedData)
    sharedTokenWithPeer = true


func peerDidShareDiscoveryToken(peer: MCPeerID, token: NIDiscoveryToken) 
    // Create an NI configuration
    peerDiscoveryToken = token

    let config = NINearbyPeerConfiguration(peerToken: token)

    // Run the session
    session?.run(config)

【问题讨论】:

【参考方案1】:

从您提供的代码摘录来看,您只创建了 1 个NISession。这不适用于超过 1 个同行。 您需要为每个对等设备创建一个NISession 对象。您可以将会话存储在字典中(他们在 WWDC 视频中推荐)。您可以使用 MCPeerID 作为密钥来识别对等设备。这对我有用。

【讨论】:

以上是关于如何使用 Apple 的 NearbyInteraction 框架连接多个设备(实现多个正在进行的会话)的主要内容,如果未能解决你的问题,请参考以下文章

如何配置 Mailgun 以与 Sign in with Apple 和 Apple 的中继服务一起使用?

如何申请apple merchant id

如何在 ionic 3 应用程序中添加“使用 Apple 登录”?

如何使用 JavaScript 从 Apple Pay 获取与 Apple Pay 帐户关联的用户电子邮件地址

如何使用 SKKeyframeSequence 绘制渐变:根据 Apple 文档

Apple 映射 URL 方案,如何使用 near 参数