测试已测试 | ✓ |
Lang语言 | SwiftSwift |
许可证 | MIT |
Released上次发布 | 2016 年 4 月 |
SPM支持 SPM | ✗ |
由 Nathan Kot 维护。
依赖 | |
RxSwift | ~> 2.3.0 |
RxCocoa | ~> 2.3.0 |
使用适配器模式,我们可以使用大量的模拟来测试多点连接代码。实际上,我们试图将 MultipeerConnectivity
中的所有不可测试的部分集中到一个库中。
此库还允许您用其他协议(如 WebSocket)替换底层的 p2p 机制。目前它只支持苹果的 MultipeerConnectivity,但你可以轻松编写对其他协议的自定义适配器。
请注意,NKMultipeer 了大量使用 RxSwift,如果您不熟悉 Rx* 库,请阅读相关内容。此库的箴言是:**一切皆流**。
要查看有效示例,请查看 NKMultipeer 示例
文件夹。
import RxSwift
import RxCocoa
import NKMultipeer
let acceptButton: UIButton
let client: CurrentClient<MCPeerID>
client.startAdvertising()
let connectionRequests = client.incomingConnections().shareReplay(1)
acceptButton.rx_tap
.withLatestFrom(connectionRequests)
.subscribeNext { (peer, context, respond) in respond(true) }
.addDisposableTo(disposeBag)
import RxSwift
import NKMultipeer
let client: CurrentClient<MCPeerID>
client.startBrowsing()
let nearbyPeers = client.nearbyPeers().shareReplay(1)
// Attempt to connect to all peers
nearbyPeers
.map { (peers: [Client<MCPeerID>]) in
peers.map { client.connect($0, context: ["Hello": "there"], timeout: 12) }.zip()
}
.subscribe()
.addDisposableTo(disposeBag)
发送它们
import RxSwift
import RxCocoa
import NKMultipeer
let client: CurrentClient<MCPeerID>
let peer: Observable<Client<MCPeerID>>
let sendButton: UIButton
sendButton.rx_tap
.withLatestFrom(peer)
.map { client.send(peer, "Hello!") }
.switchLatest()
.subscribeNext { _ in print("Message sent") }
.addDisposableTo(disposeBag)
接收它们
import RxSwift
import NKMultipeer
let client: CurrentClient<MCPeerID>
client.receive()
.subscribeNext { (peer: Client<MCPeerID>, message: String) in
print("got message \(message), from peer \(peer)")
}
.addDisposableTo(disposeBag)
RxSwift 使得向另一个节点持久连接发送流数据变得非常直观。
发送者
import RxSwift
import NKMultipeer
let client: CurrentClient<MCPeerID>
let peer: Observable<Client<MCPeerID>>
let queuedMessages: Observable<[UInt8]>
let pipe = peer.map { client.send(peer, streamName: "data.stream") }
pipe.withLatestFrom(queuedMessages) { $0 }
.subscribeNext { (sender, message) in sender(message) }
.addDisposableTo(disposeBag)
接收者
import RxSwift
import NKMultipeer
let client: CurrentClient<MCPeerID>
let peer: Observable<Client<MCPeerID>>
let incomingData = client.receive(peer, streamName: "data.stream").shareReplay(1)
incomingData.subscribeNext { (data) in print(data) }
.addDisposableTo(disposeBag)
import RxSwift
import NKMultipeer
您的项目默认带有 Debug
和 Release
构建配置,我们需要创建一个新的名为 Testing
的配置。请在此处查看逐步说明。
// See the link above,
// You'll need to define a new build configuration and give it the `TESTING` flag
let name = UIDevice.currentDevice().name
#if TESTING
typealias I = MockIden
let client = CurrentClient(session: MockSession(name: name))
#else
typealias I = MCPeerID
let client = CurrentClient(session: MultipeerConnectivitySession(
displayName: name,
serviceType: "multipeerex",
encryptionPreference: .None))
#endif
func send(other: Client, _ string: String, _ mode: MCSessionSendDataMode = .Reliable) -> Observable<()>
func receive() -> Observable<(Client, String)>
func send(other: Client, _ data: NSData, _ mode: MCSessionSendDataMode = .Reliable) -> Observable<()>
func receive() -> Observable<(Client, NSData)>
func send(other: Client, _ json: [String: AnyObject], _ mode: MCSessionSendDataMode = .Reliable) -> Observable<()>
func receive() -> Observable<(Client, [String: AnyObject])>
func send(other: Client, name: String, url: NSURL, _ mode: MCSessionSendDataMode = .Reliable) -> Observable<NSProgress>
func receive() -> Observable<(Client, String, ResourceState)>
func send(other: Client, streamName: String, runLoop: NSRunLoop = NSRunLoop.mainRunLoop()) -> Observable<([UInt8]) -> Void>
func receive(other: Client, streamName: String, runLoop: NSRunLoop = NSRunLoop.mainRunLoop(), maxLength: Int = 512) -> Observable<[UInt8]>
在测试时,使用预处理器宏确保您的代码使用 MockSession
实例而不是 MultipeerConnectivitySession
实例。为了实现这一点,您需要使用预处理器标志并替换引用 Client<T>
的任何地方(因为 T
会有所不同,具体取决于您是否在测试。) 首先,您需要 设置一个新的构建配置,然后您可以使用如下预处理器宏。
let name = UIDevice.currentDevice().name
#if TESTING
typealias I = MockIden
let client = CurrentClient(session: MockSession(name: name))
#else
typealias I = MCPeerID
let client = CurrentClient(session: MultipeerConnectivitySession(
displayName: name,
serviceType: "multipeerex",
encryptionPreference: .None))
#endif
别担心,您实际上通常只需要在一个集中位置使用预处理器宏,编译器之后可以根据客户端的类型进行推断。
在测试环境中模拟其他附近的设备变得非常简单,只需创建其他 CurrentClient(session: MockSession(name: "other"))
。例如,如果您的应用程序在测试环境中运行,下面的代码将模拟一个附近的客户端
let otherclient = CurrentClient(session: MockSession(name: "mockedother"))
// Accept all connections
otherclient.startAdvertising()
otherclient.incomingConnections()
.subscribeNext { (client, context, respond) in respond(true) }
.addDisposableTo(disposeBag)
// Respond to all messages with 'Roger'
otherclient.receive()
.map { (client: Client<MockIden>, string: String) in return otherclient.send(client, "Roger") }
.concat()
.subscribeNext { _ in print("Response sent") }
.addDisposableTo(disposeBag)