Last active
April 17, 2019 15:01
-
-
Save irace/925450c6feca746dad7cced8d5375f76 to your computer and use it in GitHub Desktop.
Nearby user discovery through MultipeerConnectivity in Swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
/** | |
Extensions that allow `JSONEncoder` and `JSONDecoder` to produce/consume dictionaries, instead of simply raw data. | |
*/ | |
extension JSONEncoder { | |
func encodeAsJSONObject<T>(_ value: T) throws -> Any where T: Encodable { | |
return try JSONSerialization.jsonObject(with: try encode(value), options: []) | |
} | |
} | |
extension JSONDecoder { | |
func decode<T>(_ type: T.Type, fromJSONObject object: Any) throws -> T where T: Decodable { | |
return try decode(T.self, from: try JSONSerialization.data(withJSONObject: object, options: [])) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import MultipeerConnectivity | |
typealias DiscoveryInfo = [String: String] | |
protocol PeerConnectorDelegate: class { | |
func peerConnectorFoundPeer(id: MCPeerID, withDiscoveryInfo info: DiscoveryInfo?) | |
func peerConnectorLostPeer(id: MCPeerID) | |
} | |
final class PeerConnector: NSObject { | |
private let peerID: MCPeerID | |
private let serviceAdvertiser: MCNearbyServiceAdvertiser? | |
private let serviceBrowser: MCNearbyServiceBrowser | |
// MARK: - Inputs | |
weak var delegate: PeerConnectorDelegate? | |
// MARK: - Initialization | |
init(displayName: String, discoveryInfo: DiscoveryInfo?) { | |
self.peerID = MCPeerID(displayName: displayName) | |
// Must be a unique, at most 15 characters long, and contain only ASCII lowercase letters, numbers and hyphens | |
let serviceType = "my-service" | |
if let discoveryInfo = discoveryInfo { | |
serviceAdvertiser = MCNearbyServiceAdvertiser(peer: peerID, discoveryInfo: discoveryInfo, serviceType: serviceType) | |
} | |
else { | |
serviceAdvertiser = nil | |
} | |
serviceBrowser = MCNearbyServiceBrowser(peer: peerID, serviceType: serviceType) | |
super.init() | |
serviceBrowser.delegate = self | |
} | |
func start() { | |
serviceAdvertiser?.startAdvertisingPeer() | |
serviceBrowser.startBrowsingForPeers() | |
} | |
func stop() { | |
serviceAdvertiser?.stopAdvertisingPeer() | |
serviceBrowser.stopBrowsingForPeers() | |
} | |
} | |
// MARK: - MCNearbyServiceBrowserDelegate | |
extension PeerConnector: MCNearbyServiceBrowserDelegate { | |
func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String: String]?) { | |
log.info("Found peer: \(peerID)") | |
delegate?.peerConnectorFoundPeer(id: peerID, withDiscoveryInfo: info) | |
} | |
func browser(_ browser: MCNearbyServiceBrowser, didNotStartBrowsingForPeers error: Error) { | |
log.warn("Did not start browsing for peers: \(error)") | |
} | |
func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) { | |
log.info("Lost peer: \(peerID)") | |
delegate?.peerConnectorLostPeer(id: peerID) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
struct PeerDiscoveryInfo: Codable { | |
let id: String | |
let firstName: String | |
let lastName: String? | |
let mediumAvatar: String? | |
let jobTitle: String? | |
} | |
extension User { | |
init?(discoveryInfo: DiscoveryInfo?) { | |
guard | |
let discoveryInfo = discoveryInfo, | |
let peerDiscoveryInfo = try? JSONDecoder().decode(PeerDiscoveryInfo.self, fromJSONObject: discoveryInfo), | |
let id = Int(peerDiscoveryInfo.id) | |
else { | |
return nil | |
} | |
self.init( | |
id: id, | |
firstName: peerDiscoveryInfo.firstName, | |
lastName: peerDiscoveryInfo.lastName, | |
avatar: peerDiscoveryInfo.mediumAvatar | |
.map(URL.init) | |
.map({ RemoteImage(medium: $0 )}), | |
jobTitle: peerDiscoveryInfo.jobTitle | |
.map({ JobTitle(name: $0, id: nil) }) | |
) | |
} | |
func toDiscoveryInfo() -> DiscoveryInfo? { | |
let peerDiscoveryInfo = PeerDiscoveryInfo( | |
id: String(id), | |
firstName: firstName, | |
lastName: lastName, | |
mediumAvatar: avatar?.medium?.absoluteString, | |
jobTitle: jobTitle?.name | |
) | |
return (try? JSONEncoder().encodeAsJSONObject(peerDiscoveryInfo)) | |
.flatMap({ $0 as? DiscoveryInfo }) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment