Search code examples
swift3multipeer-connectivityios10macos-sierraxcode8-beta4

Multipeer Connectivity Not Connecting Programmatically


I am creating an iOS/macOS app that uses remote control functionality via the Multipeer Connectivity Framework. Since the device to be remotely monitored and controlled will run over an extended period of time, it's not viable to use the automatic view controller methods since the monitoring device may be locked or go to sleep and then disconnect the connection. So I'm using the programatic approach so that when the monitoring devices lose connection, they will automatically pair up when they are unlocked/woken up and the app is started again. My connection works fine using the ViewController method but not the programatic delegate approach. The advertising, browsing and inviting works fine, but when the invitation is accepted on the remote side I get several errors and then a failed connection. What's weird is that several of the errors are GCKSession errors.

So why is it trying to use the GameCenter framework? And why is it failing after accepting the invitation? Could it just be a bug in the Xcode 8 / Swift 3 /iOS 10 / macOS Sierra Beta SDKs?

[ViceroyTrace] [ICE][ERROR] ICEStopConnectivityCheck() found no ICE check with call id (2008493930)
[GCKSession] Wrong connection data. Participant ID from remote connection data = 6FBBAE66, local participant ID = 3A4C626C
[MCSession] GCKSessionEstablishConnection failed (FFFFFFFF801A0020)
Peer Changing
Failed
[GCKSession] Not in connected state, so giving up for participant [77B72F6A] on channel [0]

Here is the code from my connection class

func startAdvertisingWithoutUI () {

    if advertiserService == nil {
        advertiserService = MCNearbyServiceAdvertiser (peer: LMConnectivity.peerID, discoveryInfo: nil, serviceType: "mlm-timers")
        advertiserService?.delegate = self
        session.delegate = self
    }

    advertiserService?.startAdvertisingPeer()

}

func browserForNearbyDevices () {

    if browserService == nil {
        browserService = MCNearbyServiceBrowser (peer: LMConnectivity.peerID, serviceType: "mlm-timers")
        browserService?.delegate = self
        session.delegate = self
    }

    browserService?.startBrowsingForPeers()
}

func sendInvitation(to peer: MCPeerID) {

    browserService?.invitePeer(peer, to: session, withContext: nil, timeout: 60)

}

func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: Data?, invitationHandler: (Bool, MCSession?) -> Void) {

    let trustedNames = GetPreferences.trustedRemoteDevices

    for name in trustedNames {

        if name == peerID.displayName {
            invitationHandler(true,session)
            return
        }
    }

    invitationHandler (false, session)
}

Solution

  • I found out what was wrong. The MCPeerID object that I was passing into the MCSession instances, I was vending it as a Computed Class Property instead of storing it as a Stored Property. So I changed it to a Stored Instance Property and everything started working! Thanks Tanya for pointing me in the direction of the MCPeerID object.

    Old Code

    // Class Properties
    
    static var localPeer : MCPeerID { return MCPeerID(displayName: GetPreferences.deviceName!) }
    

    New Code

    // Instance Properties
    let localPeer = MCPeerID (displayName: GetPreferences.deviceName!)