paint-brush
Maîtrisez la connectivité multi-homologues iOS et partagez des données sur plusieurs appareils sans accès à Internetpar@bugorbn
235 lectures

Maîtrisez la connectivité multi-homologues iOS et partagez des données sur plusieurs appareils sans accès à Internet

par Boris Bugor12m2024/08/19
Read on Terminal Reader

Trop long; Pour lire

La connectivité multipeer permet l'échange direct de données entre les appareils Apple via Wi-Fi, Bluetooth et Ethernet, en contournant les serveurs traditionnels. L'article décrit les avantages, les limites et les étapes à suivre pour intégrer cette technologie dans vos projets.
featured image - Maîtrisez la connectivité multi-homologues iOS et partagez des données sur plusieurs appareils sans accès à Internet
Boris Bugor HackerNoon profile picture
0-item


La connectivité multipeer est une alternative au format d'échange de données habituel. Au lieu d'échanger des données via Wi-Fi ou réseau cellulaire via un intermédiaire, qui est généralement un serveur back-end, la connectivité multipeer offre la possibilité d'échanger des informations entre plusieurs appareils à proximité sans intermédiaire.


L'iPhone et l'iPad utilisent les technologies Wi-Fi et Bluetooth, tandis que le MacBook et l'Apple TV s'appuient sur le Wi-Fi et l'Ethernet.


Les avantages et les inconvénients de cette technologie découlent immédiatement de cela. Parmi les avantages, on peut citer la décentralisation et, par conséquent, la possibilité d'échanger des informations sans intermédiaires.


Inconvénients : le partage est limité à la couverture Wi-Fi et Bluetooth pour iPhone et iPad, ou Wi-Fi et Ethernet pour MacBook et Apple TV. En d'autres termes, l'échange d'informations peut être effectué à proximité immédiate des appareils.


L'intégration de la connectivité multi-pairs n'est pas compliquée et comprend les étapes suivantes :

  1. Préréglage du projet

  2. Configurer la visibilité pour d’autres appareils

  3. Rechercher les appareils visibles à portée

  4. Création d'une paire d'appareils pour l'échange de données

  5. Échange de données


Examinons de plus près chacune des étapes ci-dessus.


1. Préréglage du projet

À ce stade, le projet doit être préparé pour la mise en œuvre de la connectivité multipeer. Pour ce faire, vous devez obtenir des autorisations supplémentaires de la part de l'utilisateur pour pouvoir scanner :

  • ajoutez Confidentialité — Description de l’utilisation du réseau local au fichier Info.plist avec une description de l’objectif d’utilisation ;
  • De plus, pour la possibilité d'échange d'informations, Info.plist doit également être complété par les lignes suivantes :


 <key>NSBonjourServices</key> <array> <string>_nearby-devices._tcp</string> <string>_nearby-devices._upd</string> </array>


Il est important de noter que la sous-chaîne nearby-devices est utilisée comme exemple dans ce contexte. Dans votre projet, cette clé doit répondre aux exigences suivantes :

1 à 15 caractères de long et les caractères valides incluent les lettres minuscules ASCII, les chiffres et le trait d'union contenant au moins une lettre et aucun trait d'union adjacent.

Vous pouvez en savoir plus sur les exigences__ ici __.

En ce qui concerne les protocoles de communication, l'exemple utilise tcp et upd (le plus fiable et l'autre moins fiable). Si vous ne savez pas quel protocole vous avez besoin, vous devez saisir les deux.

2. Configurer la visibilité pour d’autres appareils

L'organisation de la visibilité des appareils pour les connexions multi-homologues est implémentée par MCNearbyServiceAdvertiser . Créons une classe qui sera responsable de la détection, de l'affichage et du partage des informations entre les appareils.


 import MultipeerConnectivity import SwiftUI class DeviceFinderViewModel: ObservableObject { private let advertiser: MCNearbyServiceAdvertiser private let session: MCSession private let serviceType = "nearby-devices" @Published var isAdvertised: Bool = false { didSet { isAdvertised ? advertiser.startAdvertisingPeer() : advertiser.stopAdvertisingPeer() } } init() { let peer = MCPeerID(displayName: UIDevice.current.name) session = MCSession(peer: peer) advertiser = MCNearbyServiceAdvertiser( peer: peer, discoveryInfo: nil, serviceType: serviceType ) } }


Le cœur du multipeer est une MCSession , qui vous permettra de vous connecter et d'échanger des données entre les appareils.

Le serviceType est la clé mentionnée ci-dessus, qui a été ajoutée au fichier Info.plist avec les protocoles d'échange.

La propriété isAdvertised vous permettra de changer la visibilité de l'appareil à l'aide Toggle .

3. Recherchez les appareils visibles à portée

L'analyse de la visibilité des appareils pour une connexion multi-homologues est effectuée par MCNearbyServiceBrowser :


 class DeviceFinderViewModel: NSObject, ObservableObject { ... private let browser: MCNearbyServiceBrowser ... @Published var peers: [PeerDevice] = [] ... override init() { ... browser = MCNearbyServiceBrowser(peer: peer, serviceType: serviceType) super.init() browser.delegate = self } func startBrowsing() { browser.startBrowsingForPeers() } func finishBrowsing() { browser.stopBrowsingForPeers() } } extension DeviceFinderViewModel: MCNearbyServiceBrowserDelegate { func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) { peers.append(PeerDevice(peerId: peerID)) } func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) { peers.removeAll(where: { $0.peerId == peerID }) } } struct PeerDevice: Identifiable, Hashable { let id = UUID() let peerId: MCPeerID }


Une liste de tous les périphériques visibles sera stockée dans peers . Les méthodes déléguées MCNearbyServiceBrowser ajouteront ou supprimeront un MCPeerID lorsqu'un pair est trouvé ou perdu.


Les méthodes startBrowsing et finishBrowsing seront utilisées pour démarrer la découverte des périphériques visibles lorsque l'écran apparaît, ou arrêter la recherche après la disparition de l'écran.


La View suivante sera utilisée comme interface utilisateur :


 struct ContentView: View { @StateObject var model = DeviceFinderViewModel() var body: some View { NavigationStack { List(model.peers) { peer in HStack { Image(systemName: "iphone.gen1") .imageScale(.large) .foregroundColor(.accentColor) Text(peer.peerId.displayName) .frame(maxWidth: .infinity, alignment: .leading) } .padding(.vertical, 5) } .onAppear { model.startBrowsing() } .onDisappear { model.finishBrowsing() } .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Toggle("Press to be discoverable", isOn: $model.isAdvertised) .toggleStyle(.switch) } } } } }


La visibilité de l'appareil sera activée/désactivée par la Toggle .
Par conséquent, à ce stade, la détection et l’affichage des appareils devraient fonctionner correctement.


4. Création d'une paire d'appareils pour l'échange de données

La méthode déléguée MCNearbyServiceAdvertiserdidReceiveInvitationFromPeer est responsable de l'envoi d'une invitation entre une paire d'appareils. Les deux doivent être capables de gérer cette demande.


 class DeviceFinderViewModel: NSObject, ObservableObject { ... @Published var permissionRequest: PermitionRequest? @Published var selectedPeer: PeerDevice? { didSet { connect() } } ... @Published var joinedPeer: [PeerDevice] = [] override init() { ... advertiser.delegate = self } func startBrowsing() { browser.startBrowsingForPeers() } func finishBrowsing() { browser.stopBrowsingForPeers() } func show(peerId: MCPeerID) { guard let first = peers.first(where: { $0.peerId == peerId }) else { return } joinedPeer.append(first) } private func connect() { guard let selectedPeer else { return } if session.connectedPeers.contains(selectedPeer.peerId) { joinedPeer.append(selectedPeer) } else { browser.invitePeer(selectedPeer.peerId, to: session, withContext: nil, timeout: 60) } } } extension DeviceFinderViewModel: MCNearbyServiceAdvertiserDelegate { func advertiser( _ advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: Data?, invitationHandler: @escaping (Bool, MCSession?) -> Void ) { permissionRequest = PermitionRequest( peerId: peerID, onRequest: { [weak self] permission in invitationHandler(permission, permission ? self?.session : nil) } ) } } struct PermitionRequest: Identifiable { let id = UUID() let peerId: MCPeerID let onRequest: (Bool) -> Void }


Lorsque le selectedPeer est défini, la méthode connect se déclenche. Si ce peer figure dans la liste des peers existants, il sera ajouté au tableau joinedPeer . À l'avenir, cette propriété sera traitée par l'interface utilisateur.


En l’absence de ce pair dans la session, le browser invitera cet appareil à créer une paire.


Après cela, la méthode didReceiveInvitationFromPeer sera traitée pour l'appareil invité. Dans notre cas, après le démarrage de didReceiveInvitationFromPeer , une permissionRequest est créée avec un rappel différé, qui sera affiché sous forme d'alerte sur l'appareil invité :


 struct ContentView: View { @StateObject var model = DeviceFinderViewModel() var body: some View { NavigationStack { ... .alert(item: $model.permissionRequest, content: { request in Alert( title: Text("Do you want to join \(request.peerId.displayName)"), primaryButton: .default(Text("Yes"), action: { request.onRequest(true) model.show(peerId: request.peerId) }), secondaryButton: .cancel(Text("No"), action: { request.onRequest(false) }) ) }) ... } } }


En cas d'approbation, didReceiveInvitationFromPeer renverra l'appareil envoyant l'invitation, l'autorisation et la session si l'autorisation a réussi.


En conséquence, après avoir accepté avec succès l'invitation, une paire sera créée :


5. Échange de données

Après avoir créé une paire, MCSession est responsable de l'échange de données :


 import MultipeerConnectivity import Combine class DeviceFinderViewModel: NSObject, ObservableObject { ... @Published var messages: [String] = [] let messagePublisher = PassthroughSubject<String, Never>() var subscriptions = Set<AnyCancellable>() func send(string: String) { guard let data = string.data(using: .utf8) else { return } try? session.send(data, toPeers: [joinedPeer.last!.peerId], with: .reliable) messagePublisher.send(string) } override init() { ... session.delegate = self messagePublisher .receive(on: DispatchQueue.main) .sink { [weak self] in self?.messages.append($0) } .store(in: &subscriptions) } } extension DeviceFinderViewModel: MCSessionDelegate { func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) { guard let last = joinedPeer.last, last.peerId == peerID, let message = String(data: data, encoding: .utf8) else { return } messagePublisher.send(message) } }


La méthode func send(_ data: Data, toPeers peerIDs: [MCPeerID], with mode: MCSessionSendDataMode) throws d'envoyer des données entre pairs.


La méthode déléguée func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) est déclenchée sur l'appareil qui a reçu le message.


De plus, un éditeur intermédiaire messagePublisher est utilisé pour recevoir des messages, puisque les méthodes déléguées MCSession se déclenchent dans DispatchQueue global() .


Vous trouverez plus de détails sur le prototype d'intégration de connectivité multipeer dans ce dépôt À titre d’exemple, cette technologie a permis d’échanger des messages entre appareils.



N'hésitez pas à me contacter sur Gazouillement si vous avez des questions. De plus, vous pouvez toujours achète-moi un café .