본문 바로가기
TIL (Today I Learned)

[iOS] NearbyInteraction란?

by Bokoo14 2024. 1. 13.

WWDC20에서 공개한 신기술

Apple의 U1 칩 → 고주파수 기능을 사용해 디바이스 위치 인식. 블루투스보다 훨씬 더 정확한 위치 제공

더보기

 

Nearby Interaction은 Apple의 기술로, 근거리에 있는 iOS 기기 간에 통신 및 상호 작용을 제공하는 프레임워크입니다.

기기들은 Wi-Fi, Bluetooth 또는 기타 네트워크 연결을 통해 서로 통신하고 데이터를 교환할 수 있습니다. 이를 통해 주변의 기기와 상호 작용하거나 공유할 수 있는 기능을 개발할 수 있습니다. 

 


Nearby Interaction

식별자, 거리, 방향을 사용하여 주변 장치를 찾고 상호 작용합니다.

iOS 14.0+, 아이패드OS 14.0+, 맥OS 11.0+, 맥 카탈리스트 14.0+, watchOS 8.0+

개요

앱에서 Nearby Interaction을 사용하여 iPhone 11 이상, Apple Watch 및 타사 액세서리와 같이 UWB(Ultra Wideband) 칩이 탑재된 기기의 위치를 획득합니다. 상호 작용에 참여하기 위해 물리적으로 근접한 장치는 앱을 실행하고 위치와 장치 토큰을 고유하게 식별합니다. 앱이 포그라운드에서 실행되면 Nearby Interaction은 피어의 방향과 거리를 미터 단위로 보고하여 피어의 위치를 상호작용 세션에 알립니다.

Apple 기기는 UWB 칩의 고주파 기능을 사용하여 물리적 환경에서 위치를 공유하고 유동적인 대화형 세션을 가능하게 합니다. 예를 들어:

  • 참가자의 손에 가상 물풍선을 쥐어주는 멀티유저 AR 경험
  • 동료 사용자의 지시를 실시간으로 활용하여 운전자와 고객의 상대적 위치를 식별하는 택시 또는 차량 공유 앱
  • 다음 그림과 같이 사용자가 장치로 패들을 제어하고 동료 사용자의 화면에서 움직이는 공에 반응할 있는 게임 앱입니다.

주요 기능

1. 디바이스 감지: 주변에 있는 다른 iOS기기 탐색하고 감지. 이를 통해 주변에 있는 기기 식별하고 선택 가능

2. 데이터 교환: 기기들 간의 데이터를 교환할 수 있음. 텍스트, 이미지, 파일 등을 주고 받을 수 있음. 이를 활용해 기기간 정보를 공유하거나 협업할 수 있음.

3. 상호 작용: 기기들은 서로 상호작용 할 수 있음. (멀티플레이어 게임, 협업 앱)

4. 위치 정보: 기기들은 상대 기기의 근접한 위치 정보를 얻을 수 있음.

 

 

Multipeer Connectivity

P2P 연결과 근처 장치 검색을 지원합니다.

iOS 7.0+, 맥OS 10.10+, 맥 카탈리스트 13.0+, tvOS 10.0+, 비전 OS 1.0+, 아이패드OS 7.0+

개요

멀티피어 연결 프레임워크는 근처 장치에서 제공하는 서비스 검색을 지원하고 메시지 기반 데이터, 스트리밍 데이터 및 리소스(예: 파일)를 통해 해당 서비스와의 통신을 지원합니다. iOS에서 프레임워크는 기본 전송을 위해 인프라 Wi-Fi 네트워크, P2P Wi-Fi 및 Bluetooth 개인 영역 네트워크를 사용합니다. macOS 및 tvOS에서는 인프라 Wi-Fi, P2P Wi-Fi 및 이더넷을 사용합니다.

important

로컬 네트워크를 사용하는 앱은 키와 함께 사용 문자열을 제공해야 합니다 .

Bonjour을 사용하는 앱들은 NSBonjourServices 키를 사용하여 찾는 서비스를 선언해야 합니다.

 


Apple에서 제공해주는 Nearby Interaction 샘플 코드 - NIPeekaboo

아래 링크를 통해 샘플 코드를 다운받을 수 있음

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

 

Implementing Interactions Between Users in Close Proximity | Apple Developer Documentation

Enable devices to access relative positioning information.

developer.apple.com

더보기

code

/*
See LICENSE folder for this sample’s licensing information.

Abstract:
A class that manages peer discovery-token exchange over the local network by using MultipeerConnectivity.
*/

import Foundation
import MultipeerConnectivity

// MultipeerConnectivity 프레임워크를 사용하여 로컬 네트워크에서 피어 디스커버리 및 데이터 교환을 관리하는 MPCSession 클래스를 정의하는 코드

// 상수를 정의하는 구조체
struct MPCSessionConstants {
    static let kKeyIdentity: String = "identity"
}


// MCSessionDelegate, MCNearbyServiceBrowserDelegate, MCNearbyServiceAdvertiserDelegate 프로토콜을 채택하여 MultipeerConnectivity 프레임워크의 세 가지 주요 구성요소에 대한 이벤트를 처리
class MPCSession: NSObject, MCSessionDelegate, MCNearbyServiceBrowserDelegate, MCNearbyServiceAdvertiserDelegate {
    // Handler: 이벤트 핸들러, 외부에서 설정 가능, MPCSession인스턴스에서 이벤트가 발생할 때 실행
    var peerDataHandler: ((Data, MCPeerID) -> Void)? // 연결된 피어에서 데이터를 수신하면 호출
    var peerConnectedHandler: ((MCPeerID) -> Void)? // 피어가 연결되면 호출
    var peerDisconnectedHandler: ((MCPeerID) -> Void)? // 피어가 연결 해체되면 호출
    
    private let serviceString: String
    private let mcSession: MCSession
    private let localPeerID = MCPeerID(displayName: UIDevice.current.name) // 로컬 피어 아이디 생성
    private let mcAdvertiser: MCNearbyServiceAdvertiser // 초대에 대해 알림
    private let mcBrowser: MCNearbyServiceBrowser
    private let identityString: String
    private let maxNumPeers: Int // 최대 연결 가능한 피어 수

    init(service: String, identity: String, maxPeers: Int) {
        serviceString = service
        identityString = identity
        mcSession = MCSession(peer: localPeerID, securityIdentity: nil, encryptionPreference: .required)
        mcAdvertiser = MCNearbyServiceAdvertiser(peer: localPeerID,
                                                 discoveryInfo: [MPCSessionConstants.kKeyIdentity: identityString],
                                                 serviceType: serviceString)
        mcBrowser = MCNearbyServiceBrowser(peer: localPeerID, serviceType: serviceString)
        maxNumPeers = maxPeers

        super.init()
        mcSession.delegate = self
        mcAdvertiser.delegate = self
        mcBrowser.delegate = self
    }

    
    
    // MARK: - `MPCSession` public methods.
    // Begins advertising the service provided by a local peer and starts the assistant.
    func start() {
        mcAdvertiser.startAdvertisingPeer()
        mcBrowser.startBrowsingForPeers()
    }

    func suspend() {
        mcAdvertiser.stopAdvertisingPeer()
        mcBrowser.stopBrowsingForPeers()
    }

    func invalidate() {
        suspend()
        mcSession.disconnect()
    }

    func sendDataToAllPeers(data: Data) {
        sendData(data: data, peers: mcSession.connectedPeers, mode: .reliable)
    }

    func sendData(data: Data, peers: [MCPeerID], mode: MCSessionSendDataMode) {
        do {
            try mcSession.send(data, toPeers: peers, with: mode)
        } catch let error {
            NSLog("Error sending data: \(error)")
        }
    }

    
    
    // MARK: - `MPCSession` private methods.
    private func peerConnected(peerID: MCPeerID) {
        if let handler = peerConnectedHandler {
            DispatchQueue.main.async {
                handler(peerID)
            }
        }
        
        // 연결 가능한 최대 피어 수를 초과하면 연결 요청 거부
        if mcSession.connectedPeers.count == maxNumPeers {
            self.suspend()
        }
    }

    private func peerDisconnected(peerID: MCPeerID) {
        if let handler = peerDisconnectedHandler {
            DispatchQueue.main.async {
                handler(peerID)
            }
        }
        
        // 연결 가능한 최대 피어수보다 작으면 start
        if mcSession.connectedPeers.count < maxNumPeers {
            self.start()
        }
    }

    
    // MARK: - Protocol: `MCSessionDelegate`. - 6개, 세션 관련 이벤트를 처리
    // The MCSessionDelegate protocol defines methods that a delegate of the MCSession class can implement to handle session-related events. For more information, see MCSession. - 세션 관련 이벤트를 처리하기 위해 구현할 수 있는 방법을 정의
    // Delegate calls occur on a private serial queue. If your app needs to perform an action on a particular run loop or operation queue, its delegate method should explicitly dispatch or schedule that work.
    
    // Called when the state of a nearby peer changes. - nearby peer의 상태가 바꼈을때 호출
    internal func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
        switch state {
        case .connected:
            peerConnected(peerID: peerID)
        case .notConnected:
            peerDisconnected(peerID: peerID)
        case .connecting:
            break
        @unknown default:
            fatalError("Unhandled MCSessionState")
        }
    }

    // Indicates that an NSData object has been received from a nearby peer. - nearby peer로 부터 NSData object를 받았을때
    internal func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
        if let handler = peerDataHandler {
            DispatchQueue.main.async {
                handler(data, peerID)
            }
        }
    }

    // Called when a nearby peer opens a byte stream connection to the local peer. - nearby peer가 local peer에 대한 바이트 스트림 연결을 열 때 호출됩니다.
    internal func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {
        // The sample app intentional omits this implementation. - 샘플 앱은 implement를 의도적으로 생략했음
    }

    // Indicates that the local peer began receiving a resource from a nearby peer. - local peer가 nearby peer에게 리소스를 받기 시작했을때
    internal func session(_ session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID,
                          with progress: Progress) {
        // progress: An NSProgress object that can be used to cancel the transfer or queried to determine how far the transfer has progressed. - 전송을 취소하는 데 사용하거나 전송이 얼마나 진행되었는지 확인하기 위해 쿼리할 수 있는 NSProgress 개체
        
        // The sample app intentional omits this implementation. - 샘플 앱은 implement를 의도적으로 생략했음
    }

    // Indicates that the local peer finished receiving a resource from a nearby peer. - local peer가 nearby peer로 부터 리소스를 받는 것을 끝냈다는 것을 가르킴
    internal func session(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String,
                          fromPeer peerID: MCPeerID,
                          at localURL: URL?,
                          withError error: Error?) {
        // localURL: An NSURL object that provides the location of a temporary file containing the received data. - 수신된 데이터가 포함된 임시 파일의 위치를 제공하는 NSURL 개체
        // withError: An error object indicating what went wrong if the file was not received successfully, or nil. - 파일을 성공적으로 수신하지 못한 경우 무엇이 잘못되었는지 나타내는 오류 개체 또는 0
        
        // The sample app intentional omits this implementation. - 샘플 앱은 implement를 의도적으로 생략했음
    }

    
    
    // MARK: - Protocol: `MCNearbyServiceBrowserDelegate`. - Error Handling Delegate Methods, Peer Discovery Delegate Methods
    // The MCNearbyServiceBrowserDelegate protocol defines methods that a MCNearbyServiceBrowser object’s delegate can implement to handle browser-related events. - MCNearbyServiceBrowser 개체의 대리자가 브라우저 관련 이벤트를 처리하기 위해 구현할 수 있는 메서드를 정의
    
    // Called when a nearby peer is found. - nearby peer를 찾았을때
    internal func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String: String]?) {
        guard let identityValue = info?[MPCSessionConstants.kKeyIdentity] else {
            return
        }
        if identityValue == identityString && mcSession.connectedPeers.count < maxNumPeers {
            browser.invitePeer(peerID, to: mcSession, withContext: nil, timeout: 10)
        }
    }

    // Called when a nearby peer is found. - nearby peer를 잃었을때
    internal func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) {
        // The sample app intentional omits this implementation. - 샘플 앱은 implement를 의도적으로 생략했음
    }

    
    
    // MARK: - Protocol: `MCNearbyServiceAdvertiserDelegate`. - Error Handling Methods, Invitation Handling Delegate Methods
    // The MCNearbyServiceAdvertiserDelegate protocol describes the methods that the delegate object for an MCNearbyServiceAdvertiser instance can implement for handling events from the MCNearbyServiceAdvertiser class. - MCNearbyServiceAdvertiser 인스턴스에 대한 위임 개체가 MCNearbyServiceAdvertiser 클래스의 이벤트를 처리하기 위해 구현할 수 있는 방법을 설명합니다.
    
    // Called when an invitation to join a session is received from a nearby peer. - nearby peer로부터 session 초대를 받으면 호출됨
    internal func advertiser(_ advertiser: MCNearbyServiceAdvertiser,
                             didReceiveInvitationFromPeer peerID: MCPeerID,
                             withContext context: Data?,
                             invitationHandler: @escaping (Bool, MCSession?) -> Void) {
        // Accept the invitation only if the number of peers is less than the maximum.
        if self.mcSession.connectedPeers.count < maxNumPeers {
            invitationHandler(true, mcSession)
        }
    }
    
}

👀 NIPeekaboo 코드 리뷰 👀

NISessionManager

이 코드는 Nearby Interaction 세션을 관리하는 Swift 코드입니다. 이를 통해 사용자는 Bluetooth를 통해 근처의 디바이스를 발견하고 상호작용할 수 있습니다. TranData와 NISessionManager 두 개의 클래스를 정의합니다.

TranData는 NSCoding 프로토콜을 준수하는 간단한 데이터 모델로, 데이터를 저장하고 검색하기 위해 인코딩 및 디코딩 할 수 있습니다. 이 클래스에는 발견된 근처 디바이스의 검색 토큰, 충돌 여부, 디바이스와 관련된 키워드 목록, 디바이스 소유자의 별명 및 디바이스를 나타내는 이미지 정보가 포함됩니다.

NISessionManager는 Nearby Interaction 세션을 관리하는 클래스입니다. 이는 ObservableObject 프로토콜을 준수하며, 속성에 대한 변경 사항을 게시하여 다른 객체가 해당 변경 사항을 관찰하고 대응할 수 있도록 합니다.

NISessionManager의 속성은 다음과 같습니다.

  • connectedPeers: 현재 연결된 근처 디바이스를 나타내는 MCPeerID 객체의 배열.
  • matchedObject: 충돌한 디바이스를 나타내는 TranData 객체(있을 경우).
  • peersCnt: 현재 연결된 근처 디바이스 수를 나타내는 정수.
  • gameState: 게임의 현재 상태를 나타내는 열거형.
  • isBumped: 디바이스가 충돌되었는지 여부를 나타내는 부울 값.
  • isPermissionDenied: 사용자가 근처 상호작용 사용 권한을 거부했는지 여부를 나타내는 부울 값.
  • myNickname: 디바이스 소유자의 별명을 나타내는 문자열.
  • myKeywords: 디바이스 소유자와 관련된 키워드를 나타내는 정수 배열.
  • myPicture: 디바이스 소유자를 나타내는 이미지.
  • bumpedName: 충돌한 디바이스 소유자의 별명을 나타내는 문자열.
  • bumpedKeywords: 충돌한 디바이스와 관련된 키워드를 나타내는 정수 배열.
  • bumpedImage: 충돌한 디바이스를 나타내는 이미지.

NISessionManager의 메서드는 다음과 같습니다.

  • start(): Nearby Interaction 세션을 시작합니다.
  • stop(): Nearby Interaction 세션을 중지합니다.
  • startup(): 주변 기기와의 디스커버리 토큰을 공유하기 위해 MPC(Multipeer Connectivity) 세션을 시작합니다.
  • startupMPC(): MPC 세션을 시작하고, 세션의 델리게이트, 피어 연결 핸들러, 피어 데이터 핸들러, 피어 연결 끊김 핸들러를 설정합니다.
  • connectedToPeer(peer: MCPeerID): 연결된 피어를 추가하고, 해당 피어에 대한 NI(Nearby Interaction) 세션을 생성합니다.
  • shareMyDiscoveryToken(to: MCPeerID): 주변 기기와의 디스커버리 토큰을 공유합니다.
  • shareMyInfo(to: MCPeerID): 닉네임, 키워드, 프로필 사진 등 사용자 정보를 주변 기기와 공유합니다.
  • sendData(to: MCPeerID, data: TranData): TranData 객체를 주변 기기로 전송합니다.
  • sendPermissionDenied(to: MCPeerID): 사용자가 Nearby Interaction 사용 권한을 거부했음을 알리는 메시지를 주변 기기로 전송합니다.
  • dataReceivedHandler(peer: MCPeerID, data: Data): 주변 기기로부터 수신된 데이터를 처리합니다.
  • disconnectedFromPeer(peer: MCPeerID): 연결이 끊긴 피어를 처리하고, 해당 피어의 NI 세션을 제거하고, 연결된 피어 목록을 업데이트합니다.
  • updateMatchedObject(discoveryToken: NIDiscoveryToken, isBumped: Bool, keywords: [Int], nickname: String, image: UIImage): 충돌한 기기에 대한 정보를 포함하는 TranData 객체를 생성하고, 이를 matchedObject 프로퍼티에 업데이트합니다.

MPCSession

Multipeer Connectivity

이 코드 파일은 MPCSession이라는 클래스를 정의하는 스위프트 코드입니다. 이 클래스는 Apple의 Multipeer Connectivity 프레임워크를 사용하여 로컬 네트워크에서 피어 검색 및 토큰 교환을 관리합니다. 이 클래스는 연결 상태 변경, 데이터 수신 및 리소스 전송과 같은 이벤트를 처리하기 위해 MCSessionDelegate, MCNearbyServiceBrowserDelegate 및 MCNearbyServiceAdvertiserDelegate와 같은 여러 프로토콜을 준수합니다.

MPCSession 클래스에는 여러 public 메서드가 있습니다:

start(): 디바이스를 피어에게 advertising하고 로컬 네트워크에서 사용 가능한 피어를 검색합니다. suspend(): advertising 중지 및 피어 검색 중지. invalidate(): 현재 세션에서 연결을 끊고 advertising 중지 및 피어 검색 중지. sendDataToAllPeers(data: Data): 모든 연결된 피어에 데이터를 보냅니다. sendData(data: Data, peers: [MCPeerID], mode: MCSessionSendDataMode): 지정된 데이터 전송 모드로 특정 피어에 데이터를 보냅니다.

이 클래스에는 또한 피어 연결 및 연결 해제와 같은 이벤트를 처리하는 여러 개인 메서드가 있습니다.

마지막으로, MPCSession 클래스에는 델리게이트 속성(delegate: MultipeerConnectivityManagerDelegate?)이 있어 다른 객체가 연결된 기기 목록이 변경될 때 업데이트를 받을 수 있습니다.

 


테스트 코드

/*
See LICENSE folder for this sample’s licensing information.

Abstract:
A class that manages peer discovery-token exchange over the local network by using MultipeerConnectivity.
*/

import Foundation
import MultipeerConnectivity

// MultipeerConnectivity 프레임워크를 사용하여 로컬 네트워크에서 피어 디스커버리 및 데이터 교환을 관리하는 MPCSession 클래스를 정의하는 코드

// 상수를 정의하는 구조체
struct MPCSessionConstants {
    static let kKeyIdentity: String = "identity"
}


// MCSessionDelegate, MCNearbyServiceBrowserDelegate, MCNearbyServiceAdvertiserDelegate 프로토콜을 채택하여 MultipeerConnectivity 프레임워크의 세 가지 주요 구성요소에 대한 이벤트를 처리
class MPCSession: NSObject, MCSessionDelegate, MCNearbyServiceBrowserDelegate, MCNearbyServiceAdvertiserDelegate {
    // Handler: 이벤트 핸들러, 외부에서 설정 가능, MPCSession인스턴스에서 이벤트가 발생할 때 실행
    var peerDataHandler: ((Data, MCPeerID) -> Void)? // 연결된 피어에서 데이터를 수신하면 호출
    var peerConnectedHandler: ((MCPeerID) -> Void)? // 피어가 연결되면 호출
    var peerDisconnectedHandler: ((MCPeerID) -> Void)? // 피어가 연결 해체되면 호출
    
    private let serviceString: String
    private let mcSession: MCSession
    private let localPeerID = MCPeerID(displayName: UIDevice.current.name) // 로컬 피어 아이디 생성
    private let mcAdvertiser: MCNearbyServiceAdvertiser // 초대에 대해 알림
    private let mcBrowser: MCNearbyServiceBrowser
    private let identityString: String
    private let maxNumPeers: Int // 최대 연결 가능한 피어 수

    init(service: String, identity: String, maxPeers: Int) {
        serviceString = service
        identityString = identity
        mcSession = MCSession(peer: localPeerID, securityIdentity: nil, encryptionPreference: .required)
        mcAdvertiser = MCNearbyServiceAdvertiser(peer: localPeerID,
                                                 discoveryInfo: [MPCSessionConstants.kKeyIdentity: identityString],
                                                 serviceType: serviceString)
        mcBrowser = MCNearbyServiceBrowser(peer: localPeerID, serviceType: serviceString)
        maxNumPeers = maxPeers

        super.init()
        mcSession.delegate = self
        mcAdvertiser.delegate = self
        mcBrowser.delegate = self
    }

    
    
    // MARK: - `MPCSession` public methods.
    // Begins advertising the service provided by a local peer and starts the assistant. - 서비스를 advertising하기 시작하고, assistant시작
    func start() {
        mcAdvertiser.startAdvertisingPeer()
        mcBrowser.startBrowsingForPeers()
    }

    func suspend() {
        mcAdvertiser.stopAdvertisingPeer()
        mcBrowser.stopBrowsingForPeers()
    }

    func invalidate() {
        suspend()
        mcSession.disconnect()
    }

    func sendDataToAllPeers(data: Data) {
        sendData(data: data, peers: mcSession.connectedPeers, mode: .reliable)
    }

    func sendData(data: Data, peers: [MCPeerID], mode: MCSessionSendDataMode) {
        do {
            try mcSession.send(data, toPeers: peers, with: mode)
        } catch let error {
            NSLog("Error sending data: \(error)")
        }
    }

    
    
    // MARK: - `MPCSession` private methods.
    private func peerConnected(peerID: MCPeerID) {
        if let handler = peerConnectedHandler {
            DispatchQueue.main.async {
                handler(peerID)
            }
        }
        
        // 연결 가능한 최대 피어 수를 초과하면 연결 요청 거부
        if mcSession.connectedPeers.count == maxNumPeers {
            self.suspend()
        }
    }

    private func peerDisconnected(peerID: MCPeerID) {
        if let handler = peerDisconnectedHandler {
            DispatchQueue.main.async {
                handler(peerID)
            }
        }
        
        // 연결 가능한 최대 피어수보다 작으면 start
        if mcSession.connectedPeers.count < maxNumPeers {
            self.start()
        }
    }

    
    // MARK: - Protocol: `MCSessionDelegate`. - 6개, 세션 관련 이벤트를 처리
    // The MCSessionDelegate protocol defines methods that a delegate of the MCSession class can implement to handle session-related events. For more information, see MCSession. - 세션 관련 이벤트를 처리하기 위해 구현할 수 있는 방법을 정의
    // Delegate calls occur on a private serial queue. If your app needs to perform an action on a particular run loop or operation queue, its delegate method should explicitly dispatch or schedule that work.
    
    // Called when the state of a nearby peer changes. - nearby peer의 상태가 바꼈을때 호출
    internal func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
        switch state {
        case .connected:
            peerConnected(peerID: peerID)
        case .notConnected:
            peerDisconnected(peerID: peerID)
        case .connecting:
            break
        @unknown default:
            fatalError("Unhandled MCSessionState")
        }
    }

    // Indicates that an NSData object has been received from a nearby peer. - nearby peer로 부터 NSData object를 받았을때
    internal func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
        if let handler = peerDataHandler {
            DispatchQueue.main.async {
                handler(data, peerID)
            }
        }
    }

    // Called when a nearby peer opens a byte stream connection to the local peer. - nearby peer가 local peer에 대한 바이트 스트림 연결을 열 때 호출됩니다.
    internal func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {
        // The sample app intentional omits this implementation. - 샘플 앱은 implement를 의도적으로 생략했음
    }

    // Indicates that the local peer began receiving a resource from a nearby peer. - local peer가 nearby peer에게 리소스를 받기 시작했을때
    internal func session(_ session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID,
                          with progress: Progress) {
        // progress: An NSProgress object that can be used to cancel the transfer or queried to determine how far the transfer has progressed. - 전송을 취소하는 데 사용하거나 전송이 얼마나 진행되었는지 확인하기 위해 쿼리할 수 있는 NSProgress 개체
        
        // The sample app intentional omits this implementation. - 샘플 앱은 implement를 의도적으로 생략했음
    }

    // Indicates that the local peer finished receiving a resource from a nearby peer. - local peer가 nearby peer로 부터 리소스를 받는 것을 끝냈다는 것을 가르킴
    internal func session(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String,
                          fromPeer peerID: MCPeerID,
                          at localURL: URL?,
                          withError error: Error?) {
        // localURL: An NSURL object that provides the location of a temporary file containing the received data. - 수신된 데이터가 포함된 임시 파일의 위치를 제공하는 NSURL 개체
        // withError: An error object indicating what went wrong if the file was not received successfully, or nil. - 파일을 성공적으로 수신하지 못한 경우 무엇이 잘못되었는지 나타내는 오류 개체 또는 0
        
        // The sample app intentional omits this implementation. - 샘플 앱은 implement를 의도적으로 생략했음
    }

    
    
    // MARK: - Protocol: `MCNearbyServiceBrowserDelegate`. - Error Handling Delegate Methods, Peer Discovery Delegate Methods
    // The MCNearbyServiceBrowserDelegate protocol defines methods that a MCNearbyServiceBrowser object’s delegate can implement to handle browser-related events. - MCNearbyServiceBrowser 개체의 대리자가 브라우저 관련 이벤트를 처리하기 위해 구현할 수 있는 메서드를 정의
    
    // Called when a nearby peer is found. - nearby peer를 찾았을때
    internal func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String: String]?) {
        guard let identityValue = info?[MPCSessionConstants.kKeyIdentity] else {
            return
        }
        if identityValue == identityString && mcSession.connectedPeers.count < maxNumPeers {
            browser.invitePeer(peerID, to: mcSession, withContext: nil, timeout: 10)
        }
    }

    // Called when a nearby peer is found. - nearby peer를 잃었을때
    internal func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) {
        // The sample app intentional omits this implementation. - 샘플 앱은 implement를 의도적으로 생략했음
    }

    
    
    // MARK: - Protocol: `MCNearbyServiceAdvertiserDelegate`. - Error Handling Methods, Invitation Handling Delegate Methods
    // The MCNearbyServiceAdvertiserDelegate protocol describes the methods that the delegate object for an MCNearbyServiceAdvertiser instance can implement for handling events from the MCNearbyServiceAdvertiser class. - MCNearbyServiceAdvertiser 인스턴스에 대한 위임 개체가 MCNearbyServiceAdvertiser 클래스의 이벤트를 처리하기 위해 구현할 수 있는 방법을 설명합니다.
    
    // Called when an invitation to join a session is received from a nearby peer. - nearby peer로부터 session 초대를 받으면 호출됨
    internal func advertiser(_ advertiser: MCNearbyServiceAdvertiser,
                             didReceiveInvitationFromPeer peerID: MCPeerID,
                             withContext context: Data?,
                             invitationHandler: @escaping (Bool, MCSession?) -> Void) {
        // Accept the invitation only if the number of peers is less than the maximum.
        if self.mcSession.connectedPeers.count < maxNumPeers {
            invitationHandler(true, mcSession)
        }
    }
    
}

 

  • MPC를 이용하는 이유는? -> discoveryToken을 교환하기 위함이다.
  • discoveryToken을 공유하는 이유는? -> peerToken인지를 확인하기 위함이다.
  • peerToken은 어디서 정해져있는거지? 원래부터 생성되어있는건가? -> dataReceivedHandler 함수에서 peer에게서 데이터를 뽑아와 그 데이터 중 token을 뽑아서 전달한다.