paint-brush
Làm chủ kết nối đa cấp iOS và chia sẻ dữ liệu trên nhiều thiết bị mà không cần truy cập Internettừ tác giả@bugorbn
251 lượt đọc

Làm chủ kết nối đa cấp iOS và chia sẻ dữ liệu trên nhiều thiết bị mà không cần truy cập Internet

từ tác giả Boris Bugor12m2024/08/19
Read on Terminal Reader

dài quá đọc không nổi

Kết nối đa cấp cho phép trao đổi dữ liệu trực tiếp giữa các thiết bị Apple bằng Wi-Fi, Bluetooth và Ethernet, bỏ qua các máy chủ truyền thống. Bài viết nêu ra những lợi ích, hạn chế và các bước để tích hợp công nghệ này vào các dự án của bạn.
featured image - Làm chủ kết nối đa cấp iOS và chia sẻ dữ liệu trên nhiều thiết bị mà không cần truy cập Internet
Boris Bugor HackerNoon profile picture
0-item


Kết nối đa ngang hàng là một giải pháp thay thế cho định dạng trao đổi dữ liệu thông thường. Thay vì trao đổi dữ liệu qua Wi-Fi hoặc Mạng di động thông qua một môi giới trung gian, thường là máy chủ phụ trợ, Kết nối đa ngang hàng cung cấp khả năng trao đổi thông tin giữa nhiều thiết bị gần nhau mà không cần trung gian.


iPhone và iPad sử dụng công nghệ Wi-Fi và Bluetooth, trong khi MacBook và Apple TV sử dụng Wi-Fi và Ethernet.


Từ đây, ưu và nhược điểm của công nghệ này sẽ xuất hiện ngay sau đó. Ưu điểm bao gồm tính phi tập trung và theo đó là khả năng trao đổi thông tin mà không cần trung gian.


Nhược điểm — chia sẻ bị giới hạn ở phạm vi phủ sóng Wi-Fi và Bluetooth cho iPhone và iPad hoặc Wi-Fi và Ethernet cho MacBook và Apple TV. Nói cách khác, việc trao đổi thông tin có thể được thực hiện ngay tại vị trí gần các thiết bị.


Việc tích hợp kết nối đa ngang hàng không phức tạp và bao gồm các bước sau:

  1. Dự án cài đặt trước

  2. Thiết lập khả năng hiển thị cho các thiết bị khác

  3. Quét các thiết bị có thể nhìn thấy trong phạm vi

  4. Tạo một cặp thiết bị để trao đổi dữ liệu

  5. Trao đổi dữ liệu


Chúng ta hãy xem xét kỹ hơn từng bước trên.


1. Dự án cài đặt trước

Ở giai đoạn này, dự án phải được chuẩn bị để triển khai Kết nối đa cấp. Để thực hiện việc này, bạn cần có thêm quyền từ người dùng để có thể quét:

  • thêm Quyền riêng tư — Mô tả sử dụng mạng cục bộ vào tệp Info.plist với mô tả về mục đích sử dụng;
  • Ngoài ra, để có thể trao đổi thông tin, Info.plist cũng cần được bổ sung thêm các dòng sau:


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


Điều quan trọng cần lưu ý là chuỗi con nearby-devices được sử dụng làm ví dụ trong ngữ cảnh này. Trong dự án của bạn, khóa này phải đáp ứng các yêu cầu sau:

Các ký tự hợp lệ dài từ 1–15 ký tự bao gồm các chữ cái thường ASCII, số và dấu gạch nối, chứa ít nhất một chữ cái và không có dấu gạch nối liền kề.

Bạn có thể đọc thêm về các yêu cầu__ tại đây__ .

Đối với giao thức truyền thông, ví dụ sử dụng tcpupd (giao thức đáng tin cậy hơn và kém tin cậy hơn). Nếu bạn không biết mình cần giao thức nào, bạn nên nhập cả hai.

2. Thiết lập khả năng hiển thị cho các thiết bị khác

Tổ chức khả năng hiển thị thiết bị cho kết nối nhiều đối tác được triển khai bởi MCNearbyServiceAdvertiser . Hãy tạo một lớp chịu trách nhiệm phát hiện, hiển thị và chia sẻ thông tin giữa các thiết bị.


 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 ) } }


Cốt lõi của multipeer là MCSession , cho phép bạn kết nối và trao đổi dữ liệu giữa các thiết bị.

serviceType là khóa được đề cập ở trên, được thêm vào tệp Info.plist cùng với các giao thức trao đổi.

Thuộc tính isAdvertised sẽ cho phép bạn chuyển đổi chế độ hiển thị của thiết bị bằng cách sử dụng Toggle .

3. Quét các thiết bị có thể nhìn thấy trong phạm vi

Quét khả năng hiển thị thiết bị cho kết nối nhiều đối tác được thực hiện bởi 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 }


Danh sách tất cả các thiết bị có thể nhìn thấy sẽ được lưu trữ trong peers . Các phương thức ủy nhiệm MCNearbyServiceBrowser sẽ thêm hoặc xóa MCPeerID khi tìm thấy hoặc mất đối tác.


Phương thức startBrowsingfinishBrowsing sẽ được sử dụng để bắt đầu phát hiện các thiết bị có thể nhìn thấy khi màn hình xuất hiện hoặc dừng tìm kiếm sau khi màn hình biến mất.


View sau đây sẽ được sử dụng làm UI:


 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) } } } } }


Khả năng hiển thị của thiết bị sẽ được bật/tắt bằng Toggle .
Do đó, ở giai đoạn này, việc phát hiện và hiển thị thiết bị sẽ hoạt động chính xác.


4. Tạo một cặp thiết bị để trao đổi dữ liệu

Phương thức ủy nhiệm MCNearbyServiceAdvertiserdidReceiveInvitationFromPeer chịu trách nhiệm gửi lời mời giữa một cặp thiết bị. Cả hai thiết bị đều phải có khả năng xử lý yêu cầu này.


 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 }


Khi selectedPeer được thiết lập, phương thức connect sẽ kích hoạt. Nếu peer này nằm trong danh sách peers hiện có, nó sẽ được thêm vào mảng joinedPeer . Trong tương lai, thuộc tính này sẽ được xử lý bởi UI.


Nếu không có thiết bị này trong phiên, browser sẽ mời thiết bị này tạo một cặp.


Sau đó, phương thức didReceiveInvitationFromPeer sẽ được xử lý cho thiết bị được mời. Trong trường hợp của chúng tôi, sau khi didReceiveInvitationFromPeer bắt đầu, một permissionRequest được tạo với lệnh gọi lại bị trì hoãn, sẽ được hiển thị dưới dạng cảnh báo trên thiết bị được mời:


 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) }) ) }) ... } } }


Trong trường hợp phê duyệt, didReceiveInvitationFromPeer sẽ trả về thiết bị gửi lời mời, quyền và phiên nếu quyền được cấp thành công.


Kết quả là sau khi chấp nhận lời mời thành công, một cặp sẽ được tạo:


5. Trao đổi dữ liệu

Sau khi tạo cặp, MCSession chịu trách nhiệm trao đổi dữ liệu:


 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) } }


Phương thức func send(_ data: Data, toPeers peerIDs: [MCPeerID], with mode: MCSessionSendDataMode) throws giúp gửi dữ liệu giữa các đối tác.


Phương thức ủy nhiệm func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) được kích hoạt trên thiết bị đã nhận được tin nhắn.


Ngoài ra, một nhà xuất bản trung gian messagePublisher được sử dụng để nhận tin nhắn, vì các phương thức ủy nhiệm MCSession được kích hoạt trong DispatchQueue global() .


Có thể tìm thấy thêm thông tin chi tiết về nguyên mẫu tích hợp Multipeer Connectivity trong kho lưu trữ Ví dụ, công nghệ này cung cấp khả năng trao đổi tin nhắn giữa các thiết bị.



Đừng ngần ngại liên hệ với tôi qua Twitter nếu bạn có bất kỳ câu hỏi nào. Ngoài ra, bạn luôn có thể mua cho tôi một cốc cà phê .