版本记录
版本号 | 时间 |
---|---|
V1.0 | 2020.12.01 星期二 |
前言
MultipeerConnectivity
框架支持点对点连接和附近设备的发现。是iOS 7 推出的众多新框架的一种,它拓宽了操作系统中应用的范围。其目的是使开发者可以创建通过Wi-Fi或蓝牙在近距离建立连接的应用。是在近距离设备间建立互动,交换数据和其他资源的很好的简单工具。接下来几篇我们就一起看一下这个框架。感兴趣的可以看下面几篇文章。
1. MultipeerConnectivity框架详细解析(一) —— 基本概览(一)
开始
首先看下主要内容:
在本教程中,您将学习如何在没有外部网络的设备之间传输数据。 您还将尝试创建聊天功能。内容来自翻译。
接着看下写作环境:
Swift 5, iOS 14, Xcode 12
下面就是正文啦。
当被问到如何在设备之间传输数据时,大多数人会想到互联网。随着当今现代设备的发展以及蜂窝和Wi-Fi覆盖范围的扩大,这似乎合乎逻辑。但是,在某些情况下,您的用户可能无法使用Internet
,他们仍然需要传输数据。想想一下您可能需要将照片发送给与您在一起的人的场景,也许是在国外旅行时。或者,您可能需要在拥挤的机场将文件发送给同事。这些是您的应用程序用户在现实世界中可能遇到的一些连接示例。
Apple
的Multipeer Connectivity
框架引入了一种在应用程序用户之间发送和接收数据的方法。 Multipeer Connectivity
使用设备的网络硬件(例如蓝牙和Wi-Fi),而无需互联网连接。想想您上次使用AirDrop
将照片或网页发送给某人的想法。两种设备可能不在同一网络上,但是它们仍然能够将信息从一个设备发送到另一设备。 Multipeer Connectivity
功能与支持AirDrop
的框架相同,可将其包含在您的应用中。
在本教程中,您将学习如何:
- Advertise your device to other users of your app.
- Browse for users that are advertising.
- Send custom data between devices.
- Host a session multiple users can join.
- Send data to multiple users at the same time.
- Send files stored on your device to another user.
注意:对于本教程,您需要在两个不同的设备上运行该项目。这可以是物理设备或模拟器的任意组合。
首先,在启动程序文件夹中打开启动程序项目。
您将使用的应用程序Job Manager
为经理和员工提供了一种相互创建和分配工作的方式。 它还允许员工与其他附近的员工托管或加入聊天室。
构建并运行,您将看到以下内容:
现在,您将继续为设备做广告。
Advertising Your Device
首先,打开Info.plist
并添加以下条目:
-
Key:
Privacy — Local Network Usage Description
-
Value:
Job Manager needs to use your phone’s data to discover devices nearby
Apple
需要此key
来告知用户为什么您的应用程序将使用本地网络。 在联网中,局域网是设备共享相同通信方式的局域网。 使用Multipeer Connectivity
时,您正在创建一个新的本地网络以供设备连接。
接下来,打开JobConnectionManager.swift
并添加以下内容:
import MultipeerConnectivity
这将确保您可以在此文件中使用Multipeer Connectivity
框架。
接下来,将以下内容添加到类声明中的JobConnectionManager.swift
中:
// 1
private let session: MCSession
// 2
private let myPeerId = MCPeerID(displayName: UIDevice.current.name)
private let jobReceivedHandler: JobReceivedHandler?
init(_ jobReceivedHandler: JobReceivedHandler? = nil) {
// 3
session = MCSession(
peer: myPeerId,
securityIdentity: nil,
encryptionPreference: .none)
// 4
self.jobReceivedHandler = jobReceivedHandler
}
以下是上述代码的细分:
- 1)
MCSession
是用于处理设备之间所有通信的类。 - 2)
MCPeerID
在本地网络上标识您的设备。 在此示例中,您使用的是您为手机设置的名称。 - 3) 使用您的
peer ID
初始化会话。 您可以选择是否要对消息使用加密。 这里没有使用。 - 4) 稍后您会在最后一行看到更多信息。
该应用程序使员工可以确定是否希望通过Advertising
将工作发送到手机。 要实施Advertising
,请将以下属性添加到JobConnectionManager
:
private static let service = "jobmanager-jobs"
private var nearbyServiceAdvertiser: MCNearbyServiceAdvertiser
MCNearbyServiceAdvertiser
是将处理使您的设备可通过MCSession
发现的类。 广告advertise
的要求之一是您必须提供服务(service)
。 下一步将涵盖这一点。
现在,将以下内容添加到JobConnectionManager
的初始化程序中:
nearbyServiceAdvertiser = MCNearbyServiceAdvertiser(
peer: myPeerId,
discoveryInfo: nil,
serviceType: JobConnectionManager.service)
在这里,您使用Service Type
初始化nearbyServiceAdvertiser
。 Multipeer Connectivity
使用service type
来限制其处理发现广告设备的方式。 在此项目中,JobConnectionManager
将仅能发现使用jobmanager-jobs
服务名称进行广告的设备。
接下来,将以下内容添加到 JobConnectionManager.swift
中,位于类声明下方文件的末尾:
extension JobConnectionManager: MCNearbyServiceAdvertiserDelegate {
func advertiser(
_ advertiser: MCNearbyServiceAdvertiser,
didReceiveInvitationFromPeer peerID: MCPeerID,
withContext context: Data?,
invitationHandler: @escaping (Bool, MCSession?) -> Void
) {
}
}
设备发布可用于工作的广告后,就需要一种方法来处理连接和接收工作的请求。 MCNearbyServiceAdvertiserDelegate
需要处理此请求。 在这里,您可以决定是否要让您的应用自动接受邀请,或者询问用户是否要允许连接。
要处理邀请,请将以下内容添加到Advertiser(_:didReceiveInvitationFromPeer:withContext:invitationHandler :)
:
guard
let window = UIApplication.shared.windows.first,
// 1
let context = context,
let jobName = String(data: context, encoding: .utf8)
else {
return
}
let title = "Accept \(peerID.displayName)'s Job"
let message = "Would you like to accept: \(jobName)"
let alertController = UIAlertController(
title: title,
message: message,
preferredStyle: .alert)
alertController.addAction(UIAlertAction(
title: "No",
style: .cancel
) { _ in
// 2
invitationHandler(false, nil)
})
alertController.addAction(UIAlertAction(
title: "Yes",
style: .default
) { _ in
// 3
invitationHandler(true, self.session)
})
window.rootViewController?.present(alertController, animated: true)
在上面的代码中,当应用收到邀请时,它会显示一条alert
,要求用户接受或拒绝该工作。 这里需要重点注意三件事:
- 1) 传入的上下文
context
将转换为字符串。 当您转到有关发送数据的部分时,您会看到这种情况。 目前,您需要了解可以根据需要在此处传递和转换任何类型的Data
。 - 2)
InvitationHandler
闭包表示广告设备是否要接受连接。 这是您取消邀请的方式。 - 3) 如果用户选择接受连接,则将当前的
MCSession
传递给InvitationHandler
。
现在,将以下内容添加到JobConnectionManager
的初始化程序的末尾:
super.init()
nearbyServiceAdvertiser.delegate = self
在这里,您为广告设置了delegate
,发送邀请时,它将显示alert
。
您几乎可以完成设备宣传的工作! 仅需几个步骤。
将以下属性添加到JobConnectionManager
:
var isReceivingJobs: Bool = false {
didSet {
if isReceivingJobs {
nearbyServiceAdvertiser.startAdvertisingPeer()
print("Started advertising")
} else {
nearbyServiceAdvertiser.stopAdvertisingPeer()
print("Stopped advertising")
}
}
}
您可能不希望自己的设备一直在宣传自己。 在这里,您可以根据isReceivingJobs
的值启动或停止广告自己。
1. Binding the UI
接下来,在JobListView.swift
中,添加以下属性:
@ObservedObject var jobConnectionManager: JobConnectionManager
然后用下面的初始化器替换下面的:
init(jobListStore: JobListStore = JobListStore()) {
self.jobListStore = jobListStore
jobConnectionManager = JobConnectionManager { job in
jobListStore.jobs.append(job)
}
}
在上面的代码中,您正在做两件事:
- 1) 添加观察到的属性来管理你的广告状态。
- 2) 初始化相同的属性。
JobConnectionManager
在收到作业时将通过此关闭发送作业。 此代码会将收到的作业追加到jobListStore
,稍后再使用。
最后,将JobListView.swift
中的headerView
替换为以下内容:
var headerView: some View {
Toggle("Receive Jobs", isOn: $jobConnectionManager.isReceivingJobs)
}
通过将Toggle
绑定到isReceivingJobs
,您的应用现在将打开和关闭广告。
现在,从JobListView.swift
中删除以下属性,因为该属性不再使用:
@State private var isReceivingJobs = false
构建并运行,然后打开和关闭RECEIVE JOBS
开关。 您将在Xcode控制台中看到以下内容:
Discovering Devices
现在您可以播发设备,下一步就是发现设备。 首先向JobConnectionManager.swift
添加以下属性:
@Published var employees: [MCPeerID] = []
private var nearbyServiceBrowser: MCNearbyServiceBrowser
第一个新属性,employees
,存储通过上一节中设置的服务发现的设备。
下一个属性是MCNearbyServiceBrowser
。 此类处理发现打开广告的设备的所有工作。
接下来,在JobConnectionManager
的初始化程序中,在对super
的调用之前初始化ServiceBrowser
:
nearbyServiceBrowser = MCNearbyServiceBrowser(
peer: myPeerId,
serviceType: JobConnectionManager.service)
MCNearbyServiceBrowser
看起来类似于MCNearbyServiceAdvertiser
。 它需要一个peer ID
和服务。 如果这两个属性都使用JobConnectionManager.service
,它们将能够发现彼此并进行通信。
将以下内容添加到JobConnectionManager.swift
的末尾:
extension JobConnectionManager: MCNearbyServiceBrowserDelegate {
func browser(
_ browser: MCNearbyServiceBrowser,
foundPeer peerID: MCPeerID,
withDiscoveryInfo info: [String: String]?
) {
// 1
if !employees.contains(peerID) {
employees.append(peerID)
}
}
func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) {
guard let index = employees.firstIndex(of: peerID) else { return }
// 2
employees.remove(at: index)
}
}
实施MCNearbyServiceBrowserDelegate
允许您在发现对等方或设备时响应事件。
这里发生两件事:
- 1) 当浏览发现对等方时,会将其添加到
employees
中。 - 2) 相反,当浏览放开
peer
时,会将其从列表中删除。
现在,将以下内容添加到JobConnectionManager
的初始化程序的末尾:
nearbyServiceBrowser.delegate = self
这样可以确保在发现或丢失设备时调用上一步中的代码。
在设置UI以显示设备之前,请添加以下方法以在JobConnectionManager
中启用和禁用浏览:
func startBrowsing() {
nearbyServiceBrowser.startBrowsingForPeers()
}
func stopBrowsing() {
nearbyServiceBrowser.stopBrowsingForPeers()
}
默认情况下,您的服务浏览器不会浏览同伴。 您可以通过启动和停止此服务来控制状态。
1. Rendering the List
要渲染该列表,请首先在JobView.swift
和JobListRowView.swift
中添加以下属性:
@EnvironmentObject var jobConnectionManager: JobConnectionManager
由于要在工作视图之间共享模型数据,因此请将属性设置为EnvironmentObject
。
接下来,在JobListView.swift
的body
中,将节的正文Section
替换为以下内容:
ForEach(jobListStore.jobs) { job in
JobListRowView(job: job)
.environmentObject(jobConnectionManager)
}
现在,这将与JobListRowView
共享您的jobConnectionManager
。
您需要在另一个视图上设置jobConnectionManager
。 在JobListRowView.swift
中,将NavigationLink
的destination
替换为以下内容:
JobView(job: job).environmentObject(jobConnectionManager)
与上一步一样,它与JobView
共享jobConnectionManager
。
同样,您快到了!
在JobView.swift
中,将在最后一节Section
中找到的EmptyView()
替换为以下内容:
ForEach(jobConnectionManager.employees, id: \.self) { employee in
HStack {
Text(employee.displayName)
.font(.headline)
Spacer()
Image(systemName: "arrowshape.turn.up.right.fill")
}
}
这将在浏览时找到的每个员工中填充该部分。 然后,当发现或丢失它们时,会将它们添加到此列表中或从中删除。
最后,在JobView.swift
中,在设置导航标题后,将以下内容添加到列表List
的末尾:
.onAppear {
jobConnectionManager.startBrowsing()
}
.onDisappear {
jobConnectionManager.stopBrowsing()
}
作业视图出现时,它将开始浏览同伴,而该视图消失时将停止。 你们都准备好了!
在两个不同的设备上构建并运行。 您会看到以下内容:
在一个设备上,添加一个作业,然后从主列表中选择该作业。
在另一台设备上,打开RECEIVE JOBS
。 现在,您将看到以下内容:
最后,关闭第二台设备的RECEIVE JOBS
,这会将对等方从第一台设备的列表中删除:
Inviting Peers
现在,大部分工作已经完成,您可以开始在设备之间发送作业了。 第一步是将邀请设备连接在一起。
打开JobConnectionManager.swift
并添加一个新属性:
private var jobToSend: JobModel?
当两个设备连接时,它异步发生并通过委托方法发生。 此属性将临时保存您要发送的作业。
接下来,将以下方法添加到类中:
func invitePeer(_ peerID: MCPeerID, to job: JobModel) {
// 1
jobToSend = job
// 2
let context = job.name.data(using: .utf8)
// 3
nearbyServiceBrowser.invitePeer(
peerID,
to: session,
withContext: context,
timeout: TimeInterval(120))
}
以下是逐步添加的内容的细分:
- 1) 保存工作,直到需要为止
- 2) 创建一个上下文
context
。 这会将工作名称序列化为Data
。 - 3) 要求您的服务浏览器使用其他设备的
peer ID
邀请对方,并传递序列化的作业名称作为context
从一台设备邀请对等方将提示另一台设备使用您之前添加的advertiser(_:didReceiveInvitationFromPeer:withContext:invitationHandler:)
进行连接。 浏览设备创建上下文,广告对等方接收该上下文以帮助其确定是否要接受作业。
在JobView.swift
中,通过将以下内容添加到组成该行的HStack
的末尾,向显示附近设备的行添加轻击手势:
.onTapGesture {
jobConnectionManager.invitePeer(employee, to: job)
}
从列表中点击附近的设备或对等方将触发邀请过程。
构建并运行。 同样,在一台设备上创建工作,然后在另一台设备上打开RECEIVE JOBS
。 从主列表中选择工作,然后选择附近的设备。 您会在第二台设备上看到邀请,如下所示:
Sending Data Between Devices
要开始在设备之间发送工作,请首先将以下方法添加到JobConnectionManager.swift
中:
private func send(_ job: JobModel, to peer: MCPeerID) {
do {
let data = try JSONEncoder().encode(job)
try session.send(data, toPeers: [peer], with: .reliable)
} catch {
print(error.localizedDescription)
}
}
在这里,您正在编码要发送的工作。 然后,您将使用MCSession
的send(_:toPeers:with :)
。 此方法需要三项:
- 1) 您要发送的
Data
对象。 在这种情况下,这是序列化的工作。 - 2) 您要将数据发送到的一组对等体。 由于您仅将工作发送到选定的设备,因此数组中只有一个对等体。
- 3) 发送数据的
mode
。 您不必在这里使用reliable
,因为您一次只发送一份工作。 如果您要发送多个工作并想保证顺序,这将变得尤为重要。
接下来,将以下代码块添加到JobConnectionManager.swift
的末尾:
extension JobConnectionManager: MCSessionDelegate {
func session(
_ session: MCSession,
peer peerID: MCPeerID,
didChange state: MCSessionState
) {
switch state {
case .connected:
print("Connected")
case .notConnected:
print("Not connected: \(peerID.displayName)")
case .connecting:
print("Connecting to: \(peerID.displayName)")
@unknown default:
print("Unknown state: \(state)")
}
}
func session(
_ session: MCSession,
didReceive data: Data,
fromPeer peerID: MCPeerID
) {
}
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?
) {}
}
这里似乎发生了很多事情,但是实际上很简单。 要发送和接收数据,您需要遵循MCSessionDelegate
。 这些方法都是required
的,但是本教程的这一部分将仅重点介绍其中的两种方法。
查看session(_:peer:didChange:)
。 每当与另一个对等方的连接状态更改时,都会调用此方法。 发送工作时,一台设备要求连接到另一台设备。 如果它授予许可并建立连接,则将在连接状态下调用此方法。
在session(_:peer:didChange :)
中,替换以下打印语句:
case .connected:
print("Connected")
替换为:
case .connected:
guard let jobToSend = jobToSend else { return }
send(jobToSend, to: peerID)
现在,一旦设备建立连接,尝试发送工作的设备将调用您上面添加的send(_:to :)
。
要处理接收工作,请在JobConnectionManager.swift
中将session(_:didReceive:fromPeer :)
替换为以下内容:
func session(
_ session: MCSession,
didReceive data: Data,
fromPeer peerID: MCPeerID
) {
guard let job = try? JSONDecoder()
.decode(JobModel.self, from: data) else { return }
DispatchQueue.main.async {
self.jobReceivedHandler?(job)
}
}
当工作发送到广告设备时,它将数据传递给此方法。 在这里,将数据解码为JobModel
。 在主线程上调用jobReceivedHandler
,因为它需要更新UI。
现在,将以下内容添加到JobConnectionManager
的初始化程序的末尾:
session.delegate = self
最后一步确保连接到设备将调用您的代码以发送工作。 它还处理解码并将工作添加到广告设备。
构建并运行。 遵循相同的步骤,在一个设备上添加工作,然后在另一设备上打开RECEIVE JOBS
。 在第一台设备上,选择在工作视图中找到的对等方。 在第二台设备上,接受邀请以接收工作。 现在,您将在两种设备上看到相同的工作:
Browsing for Sessions
在构建应用程序的聊天功能时,本教程的最后一部分将重点介绍几个不同的项目。 如果打开ChatConnectionManger.swift
,您会看到很多代码与JobConnectionManager.swift
中的代码相似。
构建并运行,然后选择Messages
选项卡。 您会看到以下内容:
Messages
的状态从您从本教程的第一部分开始的地方开始。 如果您选择Host a Chat Session
,它将开始使用MCNearbyServiceAdvertiser
广告您的设备。 但是,Messages
将使用不同的服务类型:jobmanager-chat
。
由于hosting a session
已经完成,因此您需要一种加入session
的方法。 处理工作时,您编写了自定义代码以使用MCNearbyServiceBrowser
查找会话。 对于这一部分,您将使用Apple
的默认UI浏览会话。
首先,在ChatConnectionManager.swift
中,将join()
替换为以下内容:
func join() {
// 1
peers.removeAll()
messages.removeAll()
session = MCSession(
peer: myPeerId,
securityIdentity: nil,
encryptionPreference: .required)
session?.delegate = self
guard
let window = UIApplication.shared.windows.first,
let session = session
else { return }
// 2
let mcBrowserViewController = MCBrowserViewController(
serviceType: ChatConnectionManager.service,
session: session)
window.rootViewController?.present(mcBrowserViewController, animated: true)
}
上面的代码是这样的:
- 1) 第一部分清理所有消息或
peers
并为您创建一个新会话。 - 2) 通过使用
MCBrowserViewController
,您可以访问内置UI,以显示正在发布服务的peers
。
接下来,将以下内容添加到ChatConnectionManager.swift
的末尾:
extension ChatConnectionManager: MCBrowserViewControllerDelegate {
func browserViewControllerDidFinish(
_ browserViewController: MCBrowserViewController
) {
browserViewController.dismiss(animated: true) {
self.connectedToChat = true
}
}
func browserViewControllerWasCancelled(
_ browserViewController: MCBrowserViewController
) {
session?.disconnect()
browserViewController.dismiss(animated: true)
}
}
此代码将处理出现MCBrowserViewController
时可能发生的两种情况:
- 1) 用户已选择要加入的会话。
- 2) 用户已取消浏览。
接下来,将以下代码行添加到join()
的末尾:
mcBrowserViewController.delegate = self
这将确保您上一步中的代码得以执行。
最后,在ChatConnectionManager.swift
中,将advertiser(_:didReceiveInvitationFromPeer:withContext:invitationHandler :)
替换为以下代码:
func advertiser(
_ advertiser: MCNearbyServiceAdvertiser,
didReceiveInvitationFromPeer peerID: MCPeerID,
withContext context: Data?,
invitationHandler: @escaping (Bool, MCSession?) -> Void
) {
invitationHandler(true, session)
}
在处理发送工作时,您使用此方法来显示alert
,以询问用户是否接受工作。 在这里,默认情况下,您允许连接到hosting session
。
在这两种设备上构建并运行,然后转到Messages
。 从一台设备托管一个会话。 在第二台设备上,选择Join a Chat Session
。 您会看到以下内容:
您可以在浏览器视图控制器中选择一个对等方。 看到Connected
后,选择Done
。 然后,您将看到以下内容:
1. Seeing Connected Peers
如果您看不到谁加入了,则聊天室没有帮助。 因此,在session(_:peer:didChange :)
中,发现以下cases
:
case .connected:
print("Connected")
case .notConnected:
print("Not Connected")
然后将它们替换为下面的代码:
case .connected:
if !peers.contains(peerID) {
// 1
DispatchQueue.main.async {
self.peers.insert(peerID, at: 0)
}
// 2
if isHosting {
sendHistory(to: peerID)
}
}
case .notConnected:
DispatchQueue.main.async {
// 3
if let index = self.peers.firstIndex(of: peerID) {
self.peers.remove(at: index)
}
// 4
if self.peers.isEmpty && !self.isHosting {
self.connectedToChat = false
}
}
在上一节中,您使用此方法来知道何时发送工作。 在这里,您正在使用它执行以下操作:
- 1) 如果用户连接到聊天,请将其添加到对等方列表中。
- 2) 如果您是
host
,请将整个聊天记录发送给新连接的用户。 稍后将实现。 - 3) 当某人断开连接时,请将其从同伴列表中删除。
- 4) 如果主机
host
和所有其他对等方离开,则自动结束会话。
在这两种设备上构建和运行,在一个设备上托管hosting
,在另一个设备上加入。 现在,您会在聊天顶部看到两个用户,如下所示:
Sending Data to Multiple Devices
现在您就可以开始在用户之间发送消息了! 在ChatConnectionManager.swift
中,将send(_ :)
替换为以下代码:
func send(_ message: String) {
// 1
let chatMessage = ChatMessage(
displayName: myPeerId.displayName,
body: message)
messages.append(chatMessage)
// 2
guard
let session = session,
let data = message.data(using: .utf8),
!session.connectedPeers.isEmpty
else { return }
do {
// 3
try session.send(data, toPeers: session.connectedPeers, with: .reliable)
} catch {
print(error.localizedDescription)
}
}
以下是上述代码的细分:
- 1) 创建带有本地使用所需相关数据的
ChatMessage
。 - 2) 编码消息字符串。
- 3) 使用
MCSession
发送到所有连接的peers
。
接下来,将session(_:didReceive:fromPeer :)
替换为以下内容:
func session(
_ session: MCSession,
didReceive data: Data,
fromPeer peerID: MCPeerID
) {
guard let message = String(data: data, encoding: .utf8) else { return }
let chatMessage = ChatMessage(displayName: peerID.displayName, body: message)
DispatchQueue.main.async {
self.messages.append(chatMessage)
}
}
在这两种设备上构建并运行,并在两者之间创建聊天会话。 您会看到以下内容:
如果您退出聊天并返回,您将看到聊天记录已消失。 您可以通过在用户加入时将整个聊天记录发送给用户来解决此问题。
将sendHistory(to :)
替换为以下内容:
func sendHistory(to peer: MCPeerID) {
// 1
let tempFile = URL(fileURLWithPath: NSTemporaryDirectory())
.appendingPathComponent("messages.data")
guard let historyData = try? JSONEncoder().encode(messages) else { return }
// 2
try? historyData.write(to: tempFile)
// 3
session?.sendResource(
at: tempFile,
withName: "Chat_History",
toPeer: peer
) { error in
if let error = error {
print(error.localizedDescription)
}
}
}
此代码将在hosting
设备上执行。 这是发生了什么:
- 1) 在您的临时目录中创建
URL
。 - 2) 将聊天记录写入此
URL
上的文件。 - 3) 使用
MCSession
发送资源而不是发送Data
。
由于您不是直接发送数据,因此需要使用另一种MCSessionDelegate
委托方法。 将session(_:didFinishReceivingResourceWithName:fromPeer:at:withError:)
替换为以下内容:
func session(
_ session: MCSession,
didFinishReceivingResourceWithName resourceName: String,
fromPeer peerID: MCPeerID,
at localURL: URL?,
withError error: Error?
) {
// 1
guard
let localURL = localURL,
let data = try? Data(contentsOf: localURL),
// 2
let messages = try? JSONDecoder().decode([ChatMessage].self, from: data)
else { return }
DispatchQueue.main.async {
// 3
self.messages.insert(contentsOf: messages, at: 0)
}
}
此代码在连接到会话的对等方peer
上执行。 这是正在发生的事情:
- 1) 如果资源已成功本地保存在设备上,您将在此处收到
URL
。 - 2) 该文件的内容被解码为
ChatMessage
。 - 3) 这些消息会插入您的本地消息中,当您加入聊天时会显示这些消息。
在这两种设备上构建并运行。 创建聊天会话并在两个设备之间发送消息,如下所示:
在用于加入会话的设备上,选择Leave
:
重新加入同一会话,您将看到完整的聊天记录,如下所示:
现在,您应该可以使用Multipeer Connectivity
并在没有Internet
的情况下在设备之间发送通信了。 还有更多的东西要学习,例如在设备之间发送和接收流。
您可以通过查看更多的iOS & Swift Tutorials或参考Apple’s documentation来了解更多信息。
后记
本篇主要讲述了
MultipeerConnectivity
的一个简单示例,感兴趣的给个赞或者关注~~~