SwApp para Compartir Datos

TODO: collapasable, copyable, download, etc

Can you output a SwiftUI app that uses the Multipeer Connectivity Framework to allow to iOS applications to connect? In order to test this, we will display some basic accelarameter information for the other connected device.Sure, here is a simple SwiftUI app that uses the Multipeer Connectivity framework to connect two iOS devices and share accelerometer data between them. This example includes basic accelerometer data sharing and display.

1. Create a new SwiftUI project

Open Xcode and create a new SwiftUI project.

2. Add necessary frameworks

In your Info.plist, add the required keys for accessing the accelerometer:

<key>NSMotionUsageDescription</key>
<string>We need access to your accelerometer to share data with connected devices.</string>

3. Create the Multipeer Connectivity Manager

Create a new Swift file named MultipeerManager.swift:

import Foundation
import MultipeerConnectivity

class MultipeerManager: NSObject, ObservableObject {
    private let serviceType = "accel-share"
    
    private let myPeerId = MCPeerID(displayName: UIDevice.current.name)
    private let serviceAdvertiser: MCNearbyServiceAdvertiser
    private let serviceBrowser: MCNearbyServiceBrowser
    
    @Published var receivedData: String = ""
    
    override init() {
        self.serviceAdvertiser = MCNearbyServiceAdvertiser(peer: myPeerId, discoveryInfo: nil, serviceType: serviceType)
        self.serviceBrowser = MCNearbyServiceBrowser(peer: myPeerId, serviceType: serviceType)
        
        super.init()
        
        self.serviceAdvertiser.delegate = self
        self.serviceBrowser.delegate = self
    }
    
    func start() {
        serviceAdvertiser.startAdvertisingPeer()
        serviceBrowser.startBrowsingForPeers()
    }
    
    func stop() {
        serviceAdvertiser.stopAdvertisingPeer()
        serviceBrowser.stopBrowsingForPeers()
    }
    
    var session: MCSession = MCSession(peer: MCPeerID(displayName: UIDevice.current.name), securityIdentity: nil, encryptionPreference: .required)
    
    func send(data: Data) {
        if !session.connectedPeers.isEmpty {
            do {
                try session.send(data, toPeers: session.connectedPeers, with: .reliable)
            } catch let error {
                print("Error sending data: \(error.localizedDescription)")
            }
        }
    }
}

extension MultipeerManager: MCNearbyServiceAdvertiserDelegate, MCNearbyServiceBrowserDelegate {
    func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: Data?, invitationHandler: @escaping (Bool, MCSession?) -> Void) {
        invitationHandler(true, self.session)
    }
    
    func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) {
        browser.invitePeer(peerID, to: self.session, withContext: nil, timeout: 10)
    }
    
    func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) {
        // Handle lost peer
    }
}

extension MultipeerManager: MCSessionDelegate {
    func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
        // Handle peer connection state changes
    }
    
    func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
        DispatchQueue.main.async {
            self.receivedData = String(data: data, encoding: .utf8) ?? ""
        }
    }
    
    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?) {}
}

4. Create the MotionManager

Create a new Swift file named MotionManager.swift:

import Foundation
import CoreMotion

class MotionManager: ObservableObject {
    private var motionManager: CMMotionManager
    
    @Published var accelerometerData: String = ""
    
    init() {
        self.motionManager = CMMotionManager()
        self.motionManager.accelerometerUpdateInterval = 0.1
    }
    
    func startUpdates() {
        if self.motionManager.isAccelerometerAvailable {
            self.motionManager.startAccelerometerUpdates(to: .main) { data, error in
                guard let data = data else { return }
                self.accelerometerData = "x: \(data.acceleration.x), y: \(data.acceleration.y), z: \(data.acceleration.z)"
            }
        }
    }
    
    func stopUpdates() {
        self.motionManager.stopAccelerometerUpdates()
    }
}

5. Create the ContentView

Update ContentView.swift to use MultipeerManager and MotionManager:

import SwiftUI

struct ContentView: View {
    @ObservedObject var multipeerManager = MultipeerManager()
    @ObservedObject var motionManager = MotionManager()
    
    var body: some View {
        VStack {
            Text("My Accelerometer Data")
                .font(.headline)
            Text(motionManager.accelerometerData)
                .padding()
            
            Text("Received Accelerometer Data")
                .font(.headline)
            Text(multipeerManager.receivedData)
                .padding()
        }
        .onAppear {
            self.motionManager.startUpdates()
            self.multipeerManager.start()
            
            Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
                let data = self.motionManager.accelerometerData.data(using: .utf8)
                self.multipeerManager.send(data: data!)
            }
        }
        .onDisappear {
            self.motionManager.stopUpdates()
            self.multipeerManager.stop()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

6. Run the app on two devices

To test this app, run it on two iOS devices. The accelerometer data from each device will be sent to the other and displayed on the screen.

Summary

This basic example shows how to set up Multipeer Connectivity to share accelerometer data between two devices. You can expand on this to handle more complex data or interactions as needed.Unsupported multimodal_textThis error typically occurs when there are multiple Info.plist files in your project or when the Info.plist file is included in the build phase multiple times. Here's how to resolve this issue:

  1. Check Build Phases:

    • Go to your project settings in Xcode.
    • Select your target.
    • Navigate to the "Build Phases" tab.
    • Look for the "Copy Bundle Resources" section.
    • Ensure that there is only one Info.plist file listed here. If there are duplicates, remove the extra entries.
  2. Check File Locations:

    • Ensure that there is only one Info.plist file in your project directory structure.
  3. Remove and Re-add the Info.plist:

    • Remove the Info.plist file from the project navigator.
    • Delete any duplicate Info.plist files if they exist in the project directory.
    • Re-add the Info.plist file to your project.

Here are the detailed steps:

1. Check Build Phases

  1. Open your project in Xcode.
  2. Select your target from the list of targets in the project navigator.
  3. Click on the "Build Phases" tab.
  4. Expand the "Copy Bundle Resources" section.
  5. Look for multiple entries of Info.plist. If you see more than one, remove the duplicates by clicking the minus (-) button next to them.

2. Check File Locations

  1. In the Finder, navigate to your project directory.
  2. Check if there are multiple Info.plist files in your project directory. If there are, remove the unnecessary ones.

3. Remove and Re-add the Info.plist

  1. In Xcode, select the Info.plist file in the project navigator and press the delete key.
  2. Choose "Remove References" (not "Move to Trash").
  3. In the Finder, ensure there is only one Info.plist file in your project directory.
  4. Drag and drop the Info.plist file back into the Xcode project navigator.

After performing these steps, try building your project again. This should resolve the issue. If you still encounter the error, please let me know.Unsupported multimodal_textThe errors you're encountering, with NSNetServicesErrorCode = "-72008" and NSNetServicesErrorDomain = 10, are related to the NSNetService class in iOS, which is used for network services discovery and publication. These errors usually indicate an issue with the network configuration or permissions.

Here are some common causes and solutions for these errors:

1. Network Permissions

Make sure your app has the appropriate permissions to use network services. Since iOS 14, you need to declare and request local network privacy permissions.

Add the following to your Info.plist:

<key>NSLocalNetworkUsageDescription</key>
<string>We need access to the local network to connect with other devices.</string>
<key>NSBonjourServices</key>
<array>
    <string>_accel-share._tcp</string>
</array>

2. Network Configuration

Ensure your network settings allow Bonjour services and that your devices are on the same network.

3. Code Review

Double-check your MultipeerManager code for any misconfigurations. Here is a review of the critical parts:

Advertiser Configuration

Make sure the serviceType you are using is correct and matches between the advertiser and the browser.

Example Code Adjustment

Here's a concise check to ensure everything is set up correctly:

import Foundation
import MultipeerConnectivity

class MultipeerManager: NSObject, ObservableObject {
    private let serviceType = "accel-share"
    
    private let myPeerId = MCPeerID(displayName: UIDevice.current.name)
    private let serviceAdvertiser: MCNearbyServiceAdvertiser
    private let serviceBrowser: MCNearbyServiceBrowser
    
    @Published var receivedData: String = ""
    
    override init() {
        self.serviceAdvertiser = MCNearbyServiceAdvertiser(peer: myPeerId, discoveryInfo: nil, serviceType: serviceType)
        self.serviceBrowser = MCNearbyServiceBrowser(peer: myPeerId, serviceType: serviceType)
        
        super.init()
        
        self.serviceAdvertiser.delegate = self
        self.serviceBrowser.delegate = self
        
        self.session.delegate = self // Ensure session delegate is set
    }
    
    func start() {
        serviceAdvertiser.startAdvertisingPeer()
        serviceBrowser.startBrowsingForPeers()
    }
    
    func stop() {
        serviceAdvertiser.stopAdvertisingPeer()
        serviceBrowser.stopBrowsingForPeers()
    }
    
    var session: MCSession = MCSession(peer: MCPeerID(displayName: UIDevice.current.name), securityIdentity: nil, encryptionPreference: .required)
    
    func send(data: Data) {
        if !session.connectedPeers.isEmpty {
            do {
                try session.send(data, toPeers: session.connectedPeers, with: .reliable)
            } catch let error {
                print("Error sending data: \(error.localizedDescription)")
            }
        }
    }
}

extension MultipeerManager: MCNearbyServiceAdvertiserDelegate, MCNearbyServiceBrowserDelegate, MCSessionDelegate {
    func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: Data?, invitationHandler: @escaping (Bool, MCSession?) -> Void) {
        invitationHandler(true, self.session)
    }
    
    func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) {
        browser.invitePeer(peerID, to: self.session, withContext: nil, timeout: 10)
    }
    
    func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) {
        // Handle lost peer
    }
    
    func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
        // Handle peer connection state changes
    }
    
    func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
        DispatchQueue.main.async {
            self.receivedData = String(data: data, encoding: .utf8) ?? ""
        }
    }
    
    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?) {}
}

4. Check Bonjour Service Configuration

Ensure that the _accel-share._tcp service type is correctly set up and that it matches the service type used in the MultipeerManager.

By following these steps, you should be able to resolve the errors and successfully run your app. If the problem persists, double-check your network environment to ensure that Bonjour services are not being blocked.Unsupported multimodal_textThe errors you are encountering, such as Wrong connection data. Participant ID from remote connection data = ..., indicate that there is a mismatch or conflict in the session data between the peers. This usually happens due to misconfiguration or issues in the connection establishment phase.

Here are some steps to help diagnose and resolve these issues:

1. Ensure Unique Peer IDs

Make sure each device has a unique MCPeerID. Using the device name as the display name for MCPeerID can help ensure uniqueness.

2. Check Session State

Ensure that both devices are in a proper state to establish a connection. Make sure the session's delegate methods are correctly implemented to handle state changes and errors.

3. Review Code Implementation

Here is a more refined implementation of the MultipeerManager with additional logging to help diagnose issues:

import Foundation
import MultipeerConnectivity

class MultipeerManager: NSObject, ObservableObject {
    private let serviceType = "accel-share"
    private let myPeerId = MCPeerID(displayName: UIDevice.current.name)
    private let serviceAdvertiser: MCNearbyServiceAdvertiser
    private let serviceBrowser: MCNearbyServiceBrowser
    
    @Published var receivedData: String = ""
    
    override init() {
        self.serviceAdvertiser = MCNearbyServiceAdvertiser(peer: myPeerId, discoveryInfo: nil, serviceType: serviceType)
        self.serviceBrowser = MCNearbyServiceBrowser(peer: myPeerId, serviceType: serviceType)
        
        super.init()
        
        self.serviceAdvertiser.delegate = self
        self.serviceBrowser.delegate = self
        self.session.delegate = self // Ensure session delegate is set
    }
    
    func start() {
        serviceAdvertiser.startAdvertisingPeer()
        serviceBrowser.startBrowsingForPeers()
    }
    
    func stop() {
        serviceAdvertiser.stopAdvertisingPeer()
        serviceBrowser.stopBrowsingForPeers()
    }
    
    var session: MCSession = MCSession(peer: MCPeerID(displayName: UIDevice.current.name), securityIdentity: nil, encryptionPreference: .required)
    
    func send(data: Data) {
        if !session.connectedPeers.isEmpty {
            do {
                try session.send(data, toPeers: session.connectedPeers, with: .reliable)
            } catch let error {
                print("Error sending data: \(error.localizedDescription)")
            }
        }
    }
}

extension MultipeerManager: MCNearbyServiceAdvertiserDelegate, MCNearbyServiceBrowserDelegate, MCSessionDelegate {
    func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: Data?, invitationHandler: @escaping (Bool, MCSession?) -> Void) {
        print("Received invitation from \(peerID.displayName)")
        invitationHandler(true, self.session)
    }
    
    func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) {
        print("Found peer: \(peerID.displayName)")
        browser.invitePeer(peerID, to: self.session, withContext: nil, timeout: 10)
    }
    
    func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) {
        print("Lost peer: \(peerID.displayName)")
    }
    
    func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
        switch state {
        case .connected:
            print("Connected to peer: \(peerID.displayName)")
        case .connecting:
            print("Connecting to peer: \(peerID.displayName)")
        case .notConnected:
            print("Not connected to peer: \(peerID.displayName)")
        @unknown default:
            fatalError()
        }
    }
    
    func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
        DispatchQueue.main.async {
            self.receivedData = String(data: data, encoding: .utf8) ?? ""
        }
    }
    
    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?) {}
}

4. Ensure Both Devices Are Discoverable

Make sure both devices are advertising and browsing for peers simultaneously to ensure they can discover each other.

5. Network Environment

Ensure that both devices are on the same network and that there are no network restrictions or firewalls blocking the connection.

6. Additional Debugging

Add more logging to track the states and data being sent/received. This can help identify where the connection is failing or what data might be causing issues.

By following these steps and ensuring your implementation is correct, you should be able to resolve the connection issues between your devices. If the problem persists, you may want to verify your network environment or look for any underlying issues with the Multipeer Connectivity framework in your specific iOS version.The Simulator doesn't ask me for permission to use the network, is that expected?When running your app on the iOS Simulator, it should typically ask for permissions just like it would on a real device. If you are not being prompted for network permissions, there might be a few reasons why this is happening. Here are some steps you can take to troubleshoot and ensure that permissions are requested correctly:

1. Verify Info.plist Configuration

Make sure your Info.plist is correctly configured to request local network permissions. You should have the following keys in your Info.plist:

<key>NSLocalNetworkUsageDescription</key>
<string>We need access to the local network to connect with other devices.</string>
<key>NSBonjourServices</key>
<array>
    <string>_accel-share._tcp</string>
</array>

2. Reset Location and Privacy Settings in the Simulator

Sometimes the Simulator's privacy settings can get out of sync. Resetting them can help:

  1. Open the iOS Simulator.
  2. Go to the menu Device -> Erase All Content and Settings....
  3. Confirm to reset the Simulator.

This will reset all permissions and settings, so the next time your app runs, it should request permissions again.

3. Check Privacy Settings in the Simulator

Ensure that the app is allowed to access the local network:

  1. Open the Settings app on the iOS Simulator.
  2. Navigate to Privacy -> Local Network.
  3. Check if your app is listed and ensure it has permission to access the local network.

4. Ensure the App Requests Permission at Runtime

Double-check your code to ensure that it triggers the network access that would prompt for permissions. The following code snippet shows how to access the network in a way that should trigger the permission prompt:

import Foundation
import MultipeerConnectivity

class MultipeerManager: NSObject, ObservableObject {
    private let serviceType = "accel-share"
    private let myPeerId = MCPeerID(displayName: UIDevice.current.name)
    private let serviceAdvertiser: MCNearbyServiceAdvertiser
    private let serviceBrowser: MCNearbyServiceBrowser
    
    @Published var receivedData: String = ""
    
    override init() {
        self.serviceAdvertiser = MCNearbyServiceAdvertiser(peer: myPeerId, discoveryInfo: nil, serviceType: serviceType)
        self.serviceBrowser = MCNearbyServiceBrowser(peer: myPeerId, serviceType: serviceType)
        
        super.init()
        
        self.serviceAdvertiser.delegate = self
        self.serviceBrowser.delegate = self
        self.session.delegate = self // Ensure session delegate is set
    }
    
    func start() {
        serviceAdvertiser.startAdvertisingPeer()
        serviceBrowser.startBrowsingForPeers()
    }
    
    func stop() {
        serviceAdvertiser.stopAdvertisingPeer()
        serviceBrowser.stopBrowsingForPeers()
    }
    
    var session: MCSession = MCSession(peer: MCPeerID(displayName: UIDevice.current.name), securityIdentity: nil, encryptionPreference: .required)
    
    func send(data: Data) {
        if !session.connectedPeers.isEmpty {
            do {
                try session.send(data, toPeers: session.connectedPeers, with: .reliable)
            } catch let error {
                print("Error sending data: \(error.localizedDescription)")
            }
        }
    }
}

extension MultipeerManager: MCNearbyServiceAdvertiserDelegate, MCNearbyServiceBrowserDelegate, MCSessionDelegate {
    func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: Data?, invitationHandler: @escaping (Bool, MCSession?) -> Void) {
        print("Received invitation from \(peerID.displayName)")
        invitationHandler(true, self.session)
    }
    
    func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) {
        print("Found peer: \(peerID.displayName)")
        browser.invitePeer(peerID, to: self.session, withContext: nil, timeout: 10)
    }
    
    func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) {
        print("Lost peer: \(peerID.displayName)")
    }
    
    func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
        switch state {
        case .connected:
            print("Connected to peer: \(peerID.displayName)")
        case .connecting:
            print("Connecting to peer: \(peerID.displayName)")
        case .notConnected:
            print("Not connected to peer: \(peerID.displayName)")
        @unknown default:
            fatalError()
        }
    }
    
    func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
        DispatchQueue.main.async {
            self.receivedData = String(data: data, encoding: .utf8) ?? ""
        }
    }
    
    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?) {}
}

5. Verify App Build and Run

Ensure you are running the correct build of your app:

  1. Clean the build folder in Xcode (Shift + Command + K).
  2. Rebuild the app (Command + B).
  3. Run the app on the Simulator.

By following these steps, your app should request the necessary network permissions. If you continue to experience issues, it might be helpful to run the app on a physical device to see if the behavior is consistent.Unsupported multimodal_textThe logs indicate that the connection is being attempted but failing due to mismatched connection data or incorrect session state. Here are some steps to diagnose and resolve these issues:

1. Ensure Unique MCPeerID

Make sure that each device has a unique MCPeerID. The MCPeerID should be based on the device name or some other unique identifier.

2. Check Session State

Make sure the session state is correctly managed and logged. This will help identify if there are any issues during the connection phase.

3. Update MultipeerManager Code

Here's an updated version of the MultipeerManager with enhanced logging to help debug the issue:

import Foundation
import MultipeerConnectivity

class MultipeerManager: NSObject, ObservableObject {
    private let serviceType = "accel-share"
    private let myPeerId = MCPeerID(displayName: UIDevice.current.name)
    private let serviceAdvertiser: MCNearbyServiceAdvertiser
    private let serviceBrowser: MCNearbyServiceBrowser
    
    @Published var receivedData: String = ""
    
    override init() {
        self.serviceAdvertiser = MCNearbyServiceAdvertiser(peer: myPeerId, discoveryInfo: nil, serviceType: serviceType)
        self.serviceBrowser = MCNearbyServiceBrowser(peer: myPeerId, serviceType: serviceType)
        
        super.init()
        
        self.serviceAdvertiser.delegate = self
        self.serviceBrowser.delegate = self
        self.session.delegate = self // Ensure session delegate is set
        
        print("Initialized MultipeerManager with peerID: \(myPeerId.displayName)")
    }
    
    func start() {
        print("Starting advertiser and browser...")
        serviceAdvertiser.startAdvertisingPeer()
        serviceBrowser.startBrowsingForPeers()
    }
    
    func stop() {
        print("Stopping advertiser and browser...")
        serviceAdvertiser.stopAdvertisingPeer()
        serviceBrowser.stopBrowsingForPeers()
    }
    
    var session: MCSession = MCSession(peer: MCPeerID(displayName: UIDevice.current.name), securityIdentity: nil, encryptionPreference: .required)
    
    func send(data: Data) {
        if !session.connectedPeers.isEmpty {
            do {
                try session.send(data, toPeers: session.connectedPeers, with: .reliable)
                print("Sent data: \(String(data: data, encoding: .utf8) ?? "")")
            } catch let error {
                print("Error sending data: \(error.localizedDescription)")
            }
        } else {
            print("No connected peers to send data to.")
        }
    }
}

extension MultipeerManager: MCNearbyServiceAdvertiserDelegate, MCNearbyServiceBrowserDelegate, MCSessionDelegate {
    func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: Data?, invitationHandler: @escaping (Bool, MCSession?) -> Void) {
        print("Received invitation from \(peerID.displayName)")
        invitationHandler(true, self.session)
    }
    
    func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) {
        print("Found peer: \(peerID.displayName)")
        browser.invitePeer(peerID, to: self.session, withContext: nil, timeout: 10)
    }
    
    func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) {
        print("Lost peer: \(peerID.displayName)")
    }
    
    func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
        switch state {
        case .connected:
            print("Connected to peer: \(peerID.displayName)")
        case .connecting:
            print("Connecting to peer: \(peerID.displayName)")
        case .notConnected:
            print("Not connected to peer: \(peerID.displayName)")
        @unknown default:
            fatalError()
        }
    }
    
    func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
        DispatchQueue.main.async {
            self.receivedData = String(data: data, encoding: .utf8) ?? ""
            print("Received data: \(self.receivedData) from \(peerID.displayName)")
        }
    }
    
    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?) {}
}

4. Verify Networking Permissions

Ensure your app has the necessary permissions for local network access:

<key>NSLocalNetworkUsageDescription</key>
<string>We need access to the local network to connect with other devices.</string>
<key>NSBonjourServices</key>
<array>
    <string>_accel-share._tcp</string>
</array>

5. Test on Real Devices

Testing on real devices is crucial as the Simulator might not behave exactly like a real device, especially with network permissions and connectivity.

6. Additional Debugging

Add more logging to track the states and data being sent/received. This can help identify where the connection is failing or what data might be causing issues.

By following these steps, you should be able to identify and resolve the connection issues between your devices. If the problem persists, you may want to verify your network environment or look for any underlying issues with the Multipeer Connectivity framework in your specific iOS version.The main problem with your code, was that you instantiated MCPeerID twice... so it wasn't stable. I fixed it.Thank you for pointing that out. Ensuring that MCPeerID is instantiated once and reused is critical for maintaining a stable peer identity throughout the app's lifecycle. Here’s the corrected and optimized version of the MultipeerManager to ensure the stability of MCPeerID:

MultipeerManager.swift

import Foundation
import MultipeerConnectivity

class MultipeerManager: NSObject, ObservableObject {
    private let serviceType = "accel-share"
    
    private let myPeerId: MCPeerID
    private let serviceAdvertiser: MCNearbyServiceAdvertiser
    private let serviceBrowser: MCNearbyServiceBrowser
    
    @Published var receivedData: String = ""
    private var session: MCSession
    
    override init() {
        // Ensure MCPeerID is instantiated once
        self.myPeerId = MCPeerID(displayName: UIDevice.current.name)
        self.session = MCSession(peer: self.myPeerId, securityIdentity: nil, encryptionPreference: .required)
        self.serviceAdvertiser = MCNearbyServiceAdvertiser(peer: self.myPeerId, discoveryInfo: nil, serviceType: serviceType)
        self.serviceBrowser = MCNearbyServiceBrowser(peer: self.myPeerId, serviceType: serviceType)
        
        super.init()
        
        self.serviceAdvertiser.delegate = self
        self.serviceBrowser.delegate = self
        self.session.delegate = self
        
        print("Initialized MultipeerManager with peerID: \(self.myPeerId.displayName)")
    }
    
    func start() {
        print("Starting advertiser and browser...")
        serviceAdvertiser.startAdvertisingPeer()
        serviceBrowser.startBrowsingForPeers()
    }
    
    func stop() {
        print("Stopping advertiser and browser...")
        serviceAdvertiser.stopAdvertisingPeer()
        serviceBrowser.stopBrowsingForPeers()
    }
    
    func send(data: Data) {
        if !session.connectedPeers.isEmpty {
            do {
                try session.send(data, toPeers: session.connectedPeers, with: .reliable)
                print("Sent data: \(String(data: data, encoding: .utf8) ?? "")")
            } catch let error {
                print("Error sending data: \(error.localizedDescription)")
            }
        } else {
            print("No connected peers to send data to.")
        }
    }
}

extension MultipeerManager: MCNearbyServiceAdvertiserDelegate, MCNearbyServiceBrowserDelegate, MCSessionDelegate {
    func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: Data?, invitationHandler: @escaping (Bool, MCSession?) -> Void) {
        print("Received invitation from \(peerID.displayName)")
        invitationHandler(true, self.session)
    }
    
    func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) {
        print("Found peer: \(peerID.displayName)")
        browser.invitePeer(peerID, to: self.session, withContext: nil, timeout: 10)
    }
    
    func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) {
        print("Lost peer: \(peerID.displayName)")
    }
    
    func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
        switch state {
        case .connected:
            print("Connected to peer: \(peerID.displayName)")
        case .connecting:
            print("Connecting to peer: \(peerID.displayName)")
        case .notConnected:
            print("Not connected to peer: \(peerID.displayName)")
        @unknown default:
            fatalError()
        }
    }
    
    func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
        DispatchQueue.main.async {
            self.receivedData = String(data: data, encoding: .utf8) ?? ""
            print("Received data: \(self.receivedData) from \(peerID.displayName)")
        }
    }
    
    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?) {}
}

Explanation:

  1. Singleton MCPeerID: The MCPeerID is now instantiated once in the MultipeerManager initializer and reused throughout the class.
  2. Session Delegate: The session delegate is set in the initializer to ensure it handles all session events.
  3. Logging: Added detailed logging to track the state changes and data transfer between peers, which can help with debugging.

By ensuring MCPeerID is instantiated only once and reusing the same session, the peer identity remains stable, leading to a more consistent and reliable connection experience.

SwApp para Compartir Datos created at Tue Jan 20 1970 20:48:09 GMT+0000 (Coordinated Universal Time)

Related Chats

iOS Local Communication Options 0.479

Thread-Safe Multipeer Manager. 0.474

SwiftUI RealityKit Integration 0.459

Reusable SwiftUI custom view. 0.445

Provide EnvironmentObject TrainerView 0.443

SwiftUI iOS App: Features 0.423

Quit App Button Swift 0.401

Build Mac App in Xcode 0.396

Move Cube with Accelerometer 0.390