Lourenço Silva
Lourenço Silva

Reputation: 23

XCode Swift - MultiPeerConnectivity / MCAdvertiserAssistant not presenting accept / deny dialogue for connections

Currently trying to get MultiPeerConnectivity to work. The current problem is with the session host. The view controller that joins the session works correctly, as in it shows the name of the host and lets me try to connect, however instead of appearing a dialogue to accept or deny on the host device, nothing happens, and after a few seconds of waiting, the device trying to join the session times out and shows that the host declined. I don't get what I might be doing wrong, the relevant part of the code below.

View Controller joining the session:

import MultipeerConnectivity

class DisplayActualViewController: UIViewController, MCSessionDelegate, MCBrowserViewControllerDelegate {
    
    var peerID: MCPeerID!
    var mcSession: MCSession!
    var mcAdvertiserAssistant: MCAdvertiserAssistant!

    override func viewDidLoad() {
        super.viewDidLoad()
        peerID = MCPeerID(displayName: UIDevice.current.name)
        mcSession = MCSession(peer: peerID, securityIdentity: nil, encryptionPreference: .required)
        mcSession.delegate = self
    }

    func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {

    }

    func session(_ session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, with progress: Progress) {

    }

    func session(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL?, withError error: Error?) {

    }

    func browserViewControllerDidFinish(_ browserViewController: MCBrowserViewController) {
        dismiss(animated: true)
    }

    func browserViewControllerWasCancelled(_ browserViewController: MCBrowserViewController) {
        dismiss(animated: true)
    }
    
    func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
        switch state {
        case MCSessionState.connected:
            print("Connected: \(peerID.displayName)")

        case MCSessionState.connecting:
            print("Connecting: \(peerID.displayName)")

        case MCSessionState.notConnected:
            print("Not Connected: \(peerID.displayName)")
        }
    }

    func joinSession() {
        let mcBrowser = MCBrowserViewController(serviceType: "hws-testing", session: mcSession)
        mcBrowser.delegate = self
        present(mcBrowser, animated: true)
    }

View Controller hosting the session:

import MultipeerConnectivity

class CounterViewController: UIViewController, MCSessionDelegate, MCBrowserViewControllerDelegate {
    var peerID = MCPeerID(displayName: UIDevice.current.name)
    var mcSession: MCSession!
    var mcAdvertiserAssistant: MCAdvertiserAssistant!

    override func viewDidLoad() {
        super.viewDidLoad()
        mcSession = MCSession(peer: peerID, securityIdentity: nil, encryptionPreference: .required)
        mcSession.delegate = self
        startHosting()
    }

    func startHosting() {
        mcAdvertiserAssistant = MCAdvertiserAssistant(serviceType: "hws-testing", discoveryInfo: nil, session: mcSession)
        mcAdvertiserAssistant.start()
    }

    func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {

    }

    func session(_ session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, with progress: Progress) {

    }

    func session(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL?, withError error: Error?) {

    }
    
    func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
        
    }

    func browserViewControllerDidFinish(_ browserViewController: MCBrowserViewController) {
        dismiss(animated: true)
    }

    func browserViewControllerWasCancelled(_ browserViewController: MCBrowserViewController) {
        dismiss(animated: true)
    }
    func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
        switch state {
        case MCSessionState.connected:
            print("Connected: \(peerID.displayName)")

        case MCSessionState.connecting:
            print("Connecting: \(peerID.displayName)")

        case MCSessionState.notConnected:
            print("Not Connected: \(peerID.displayName)")
        }
    }

Upvotes: 2

Views: 435

Answers (2)

alex oliveira
alex oliveira

Reputation: 561

The MCAdvertiserAssistant alert for accepting invitations is not presented. So the invitation times out and you get a declined response.

You can solve this by replacing MCAdvertiserAssistant with MCNearbyServiceAdvertiser.

Here's a way of doing that in 3 steps:

  1. Replace your "mcAdvertiserAssistant" property with:
var mcNearbyServiceAdvertiser: MCNearbyServiceAdvertiser!
  1. Change your "startHosting()" method to:
func startHosting() {
    mcNearbyServiceAdvertiser = MCNearbyServiceAdvertiser(peer: peerID, discoveryInfo: nil, serviceType: "hws-testing")
    mcNearbyServiceAdvertiser.delegate = self
    mcNearbyServiceAdvertiser.startAdvertisingPeer()
}
  1. Make your "CounterViewController" class conform to MCNearbyServiceAdvertiserDelegate with the following method:
func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: Data?, invitationHandler: @escaping (Bool, MCSession?) -> Void) {
    let appName = Bundle.main.infoDictionary?["CFBundleName"] as? String ?? "Invitation Received"

    let ac = UIAlertController(title: appName, message: "'\(peerID.displayName)' wants to connect.", preferredStyle: .alert)
    let declineAction = UIAlertAction(title: "Decline", style: .cancel) { [weak self] _ in invitationHandler(false, self?.mcSession) }
    let acceptAction = UIAlertAction(title: "Accept", style: .default) { [weak self] _ in invitationHandler(true, self?.mcSession) }
    
    ac.addAction(declineAction)
    ac.addAction(acceptAction)
    
    present(ac, animated: true)
}

Upvotes: 2

Michael
Michael

Reputation: 36

This worked for me:

Downgrade from using SceneDelegate and don't use UIScene.

  • Completely remove the “Application Scene Manifest” entry from Info.plist

  • Remove the SceneDelegate class, and remove the scene-related methods in AppDelegate

  • Add 'var window: UIWindow?' to your AppDelegate class.

Your app under iOS 13 it will have the same life cycle as iOS 12. And Multipeer connectivity should work as it is originally designed.

Upvotes: 1

Related Questions