Search code examples
iosswiftmacosmultipeer-connectivity

Multipeer connectivity always fail to connect


I'm trying to make 2 applications: the macOS app should send data to the iOS app. They both see each other, they start to connect but each time after few seconds they disconnect. As I'm making the SwiftUI app I created the MultipeerManager:

final class MultipeerManager: NSObject, ObservableObject {
    private let serviceType = "desview"
    let localPeerID: MCPeerID
    private(set) var session: MCSession
#if os(macOS)
    private(set) var advertiser: MCNearbyServiceAdvertiser
#elseif os(iOS)
    private(set) var browser: MCNearbyServiceBrowser
#endif

#if os(macOS)
    override init() {
        self.localPeerID = MCPeerID(displayName: "DC - \(UUID().uuidString.prefix(4))")
        self.advertiser = MCNearbyServiceAdvertiser(peer: localPeerID, discoveryInfo: ["name": "macOS design capturer"], serviceType: serviceType)
        self.session = MCSession(peer: localPeerID, securityIdentity: nil, encryptionPreference: .optional)
        super.init()
        advertiser.delegate = self
        session.delegate = self
    }
#elseif os(iOS)
    override init() {
        self.localPeerID = MCPeerID(displayName: "DV - \(UUID().uuidString.prefix(4))")
        self.browser = MCNearbyServiceBrowser(peer: localPeerID, serviceType: serviceType)
        self.session = MCSession(peer: localPeerID, securityIdentity: nil, encryptionPreference: .optional)
        super.init()
        browser.delegate = self
        session.delegate = self
    }
#endif
}

For the row where I setup the session I tried all three options: .none, .optional, .required (and this changed nothing)

On the macOS application it simply starts to advertise: advertiser.startAdvertisingPeer()

On the iPad it starts to browse: browser.startBrowsingForPeers()

... and when the macOS host is found it tries to connect (I store peers and select on the UI the needed one):

func connect(to peer: MCPeerID) { // where peer is the macOS peerID
     connectionStatus = "Connecting to \(peer.displayName)"
     browser.invitePeer(peer, to: session, withContext: nil, timeout: 10)
     browser.stopBrowsingForPeers()
}

after that the advertiser accepts the invite (I can reach this via debug):

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

I can see the session state changes, but it never reach .connected state:

func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
    switch state {
    case .notConnected:
        self.connectionStatus = "Disconnected from \(peerID.displayName)"
    case .connecting:
        self.connectionStatus = "Connecting to \(peerID.displayName)"
    case .connected:
        self.connectionStatus = "IT'S CONNECTED TO: \(peerID.displayName)!!!!"
    @unknown default:
        assertionFailure("Unhandled connection state")
    }
}

I even tried to always allow handshaking (but it never reaches this line of the code):

func session(_ session: MCSession, didReceiveCertificate certificate: [Any]?, fromPeer peerID: MCPeerID, certificateHandler: @escaping (Bool) -> Void) {
    certificateHandler(true)
}

here's the Info.plist file (those lines repeats in those 2 apps):

<dict>
    <key>NSBonjourServices</key>
    <array>
        <string>_desview._tcp</string>
        <string>_desview._udp</string>
    </array>
</dict>

My another attempt was to make 2 separate projects in Xcode but it behaves the same. I updated the macOS and iPadOS (+iOS) systems, nothing changed. I tried on Xcode 15 and Xcode 15.3 - the result is also the same. What else can I try? Is it possible to connect macOS and iOS applications via this framework?


Solution

  • Ok, after hours of investigation it turned that the solution is quite simple: I added only "Incoming Connections (Server)" capability for the App Sandbox, needed to also checkmark for Outgoing Connections: enter image description here