Extract NearbyBonjourServiceResolver

This commit is contained in:
Leon Böttger committed 2026-05-20 19:21:54 +02:00
1 parent 6b0e14de3e
commit fd29254e38
4 files changed
+140 -184

No files matched your search

@@ -1,40 +1,70 @@
//
// NearbyOutgoingServiceResolver.swift
// NearbyBonjourServiceResolver.swift
// QuickDrop
//
// Created by Leon Böttger on 19.05.26.
//
import Darwin
import Foundation
import Network
final class NearbyOutgoingServiceResolver: NSObject, NetServiceDelegate {
struct NearbyResolvedBonjourEndpoint {
let endpoint: NWEndpoint
/// Numeric host string; IPv6 link-local hosts may include a `%scopeID` suffix for NWEndpoint routing.
let host: String
let port: UInt16
let interface: NWInterface?
let description: String
let isIPv4: Bool
}
final class NearbyBonjourServiceResolver: NSObject, NetServiceDelegate {
private static let defaultWatchdogGracePeriod: TimeInterval = 0.5
private let service: NetService
private let resolveTimeout: TimeInterval
private let watchdogGracePeriod: TimeInterval
private let interface: NWInterface?
private var timeoutWorkItem: DispatchWorkItem?
private var completion: (([NearbyResolvedServiceEndpoint]) -> Void)?
private var completion: (([NearbyResolvedBonjourEndpoint]) -> Void)?
private var finished = false
init?(
result: NWBrowser.Result,
resolveTimeout: TimeInterval,
completion: @escaping ([NearbyResolvedServiceEndpoint]) -> Void
watchdogGracePeriod: TimeInterval = defaultWatchdogGracePeriod,
completion: @escaping ([NearbyResolvedBonjourEndpoint]) -> Void
) {
guard case let NWEndpoint.service(name: name, type: type, domain: domain, interface: _) = result.endpoint else {
guard let components = Self.serviceEndpointComponents(from: result) else {
return nil
}
self.service = NetService(
domain: Self.normalizedServiceDomain(domain),
type: Self.normalizedServiceType(type),
name: name
domain: Self.normalizedServiceDomain(components.domain),
type: Self.normalizedServiceType(components.type),
name: components.name
)
self.resolveTimeout = resolveTimeout
self.watchdogGracePeriod = watchdogGracePeriod
self.interface = components.interface
self.completion = completion
super.init()
}
private static func serviceEndpointComponents(
from result: NWBrowser.Result
) -> (name: String, type: String, domain: String, interface: NWInterface?)? {
guard case let NWEndpoint.service(name: name, type: type, domain: domain, interface: interface) = result.endpoint else {
return nil
}
return (name: name, type: type, domain: domain, interface: interface)
}
func start() {
service.delegate = self
service.resolve(withTimeout: resolveTimeout)
@@ -43,7 +73,7 @@ final class NearbyOutgoingServiceResolver: NSObject, NetServiceDelegate {
self?.finish(endpoints: [])
}
self.timeoutWorkItem = timeoutWorkItem
DispatchQueue.main.asyncAfter(deadline: .now() + resolveTimeout + 0.5, execute: timeoutWorkItem)
DispatchQueue.main.asyncAfter(deadline: .now() + resolveTimeout + watchdogGracePeriod, execute: timeoutWorkItem)
}
@@ -53,7 +83,7 @@ final class NearbyOutgoingServiceResolver: NSObject, NetServiceDelegate {
func netServiceDidResolveAddress(_ sender: NetService) {
finish(endpoints: Self.resolvedEndpoints(from: sender))
finish(endpoints: Self.resolvedEndpoints(from: sender, interface: interface))
}
@@ -62,7 +92,7 @@ final class NearbyOutgoingServiceResolver: NSObject, NetServiceDelegate {
}
private func finish(endpoints: [NearbyResolvedServiceEndpoint], notify: Bool = true) {
private func finish(endpoints: [NearbyResolvedBonjourEndpoint], notify: Bool = true) {
guard !finished else { return }
finished = true
timeoutWorkItem?.cancel()
@@ -80,9 +110,12 @@ final class NearbyOutgoingServiceResolver: NSObject, NetServiceDelegate {
}
private static func resolvedEndpoints(from service: NetService) -> [NearbyResolvedServiceEndpoint] {
private static func resolvedEndpoints(
from service: NetService,
interface: NWInterface?
) -> [NearbyResolvedBonjourEndpoint] {
let endpoints = (service.addresses ?? [])
.compactMap(resolvedEndpoint)
.compactMap { resolvedEndpoint(from: $0, interface: interface) }
var seenDescriptions = Set<String>()
let uniqueEndpoints = endpoints.filter { endpoint in
@@ -98,7 +131,10 @@ final class NearbyOutgoingServiceResolver: NSObject, NetServiceDelegate {
}
private static func resolvedEndpoint(from addressData: Data) -> NearbyResolvedServiceEndpoint? {
private static func resolvedEndpoint(
from addressData: Data,
interface: NWInterface?
) -> NearbyResolvedBonjourEndpoint? {
addressData.withUnsafeBytes { rawBuffer in
guard let baseAddress = rawBuffer.baseAddress else { return nil }
@@ -123,7 +159,11 @@ final class NearbyOutgoingServiceResolver: NSObject, NetServiceDelegate {
guard result == 0 else { return nil }
let host = String(cString: hostBuffer)
var host = String(cString: hostBuffer)
if addressFamily == AF_INET6 {
host = scopedIPv6Host(host, addressData: addressData)
}
guard let portRawValue = UInt16(String(cString: portBuffer)),
let port = NWEndpoint.Port(rawValue: portRawValue) else {
return nil
@@ -137,8 +177,13 @@ final class NearbyOutgoingServiceResolver: NSObject, NetServiceDelegate {
description = "\(host):\(portRawValue)"
}
return NearbyResolvedServiceEndpoint(
let isIPv6LinkLocal = addressFamily == AF_INET6 && host.lowercased().hasPrefix("fe80:")
return NearbyResolvedBonjourEndpoint(
endpoint: endpoint,
host: host,
port: portRawValue,
interface: isIPv6LinkLocal ? interface : nil,
description: description,
isIPv4: addressFamily == AF_INET
)
@@ -146,6 +191,33 @@ final class NearbyOutgoingServiceResolver: NSObject, NetServiceDelegate {
}
private static func scopedIPv6Host(
_ host: String,
addressData: Data
) -> String {
guard !host.contains("%"),
host.lowercased().hasPrefix("fe80:") else {
return host
}
guard let scopeID = ipv6ScopeID(from: addressData), scopeID != 0 else {
return host
}
return "\(host)%\(scopeID)"
}
private static func ipv6ScopeID(from addressData: Data) -> UInt32? {
addressData.withUnsafeBytes { rawBuffer in
guard let baseAddress = rawBuffer.baseAddress else { return nil }
let sockaddrPointer = baseAddress.assumingMemoryBound(to: sockaddr.self)
guard Int32(sockaddrPointer.pointee.sa_family) == AF_INET6 else { return nil }
return baseAddress.assumingMemoryBound(to: sockaddr_in6.self).pointee.sin6_scope_id
}
}
private static func normalizedServiceDomain(_ domain: String) -> String {
let trimmedDomain = domain.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmedDomain.isEmpty else { return "local." }
@@ -158,10 +230,3 @@ final class NearbyOutgoingServiceResolver: NSObject, NetServiceDelegate {
return trimmedType.hasSuffix(".") ? trimmedType : "\(trimmedType)."
}
}
struct NearbyResolvedServiceEndpoint {
let endpoint: NWEndpoint
let description: String
let isIPv4: Bool
}
@@ -10,7 +10,6 @@ import UIKit
import DeviceKit
#endif
import Darwin
import Foundation
import Network
import System
@@ -35,7 +34,7 @@ public class NearbyConnectionManager: NSObject, NetServiceDelegate, InboundNearb
private var inboundAppDelegates: [InboundAppDelegate] = []
private var outgoingTransfers: [String: OutgoingTransferInfo] = [:]
private var pendingOutgoingTransferPreparations: [String: UUID] = [:]
private var outgoingServiceResolvers: [String: NearbyOutgoingServiceResolver] = [:]
private var outgoingServiceResolvers: [String: NearbyBonjourServiceResolver] = [:]
private let pendingNotificationSyncTrustQueue = DispatchQueue(label: "NearbyConnectionManager.pendingNotificationSyncTrust")
private var pendingNotificationSyncTrust: [String: PendingReceiverTrust] = [:]
private var startedDeviceDiscovery = false
@@ -812,7 +811,7 @@ public class NearbyConnectionManager: NSObject, NetServiceDelegate, InboundNearb
preparationFinished?()
self.resolveOutgoingEndpoint(for: info.service, deviceID: deviceID) { endpoint in
self.resolveOutgoingEndpoint(for: info.service, deviceID: deviceID) { endpoint, requiredInterface in
guard let info = self.foundServices[deviceID],
self.pendingOutgoingTransferPreparations[deviceID] == preparationID else {
return
@@ -822,7 +821,9 @@ public class NearbyConnectionManager: NSObject, NetServiceDelegate, InboundNearb
let tcp = NWProtocolTCP.Options()
tcp.noDelay = true
let nwconn = NWConnection(to: endpoint, using: NWParameters(tls: .none, tcp: tcp))
let parameters = NWParameters(tls: .none, tcp: tcp)
parameters.requiredInterface = requiredInterface
let nwconn = NWConnection(to: endpoint, using: parameters)
let conn = OutboundNearbyConnection(
connection: nwconn,
@@ -861,21 +862,21 @@ public class NearbyConnectionManager: NSObject, NetServiceDelegate, InboundNearb
private func resolveOutgoingEndpoint(
for service: NWBrowser.Result,
deviceID: String,
completion: @escaping (NWEndpoint) -> Void
completion: @escaping (NWEndpoint, NWInterface?) -> Void
) {
guard let resolver = NearbyOutgoingServiceResolver(result: service, resolveTimeout: 2.5, completion: { [weak self] endpoints in
guard let resolver = NearbyBonjourServiceResolver(result: service, resolveTimeout: 2.5, completion: { [weak self] endpoints in
guard let self else { return }
self.outgoingServiceResolvers.removeValue(forKey: deviceID)
if let endpoint = endpoints.first {
completion(endpoint.endpoint)
completion(endpoint.endpoint, endpoint.interface)
} else {
log("[NearbyConnectionManager] Could not resolve outgoing service for \(deviceID); falling back to Bonjour endpoint \(service.endpoint)")
completion(service.endpoint)
completion(service.endpoint, nil)
}
}) else {
log("[NearbyConnectionManager] Cannot create resolver for outgoing service; falling back to Bonjour endpoint")
completion(service.endpoint)
completion(service.endpoint, nil)
return
}
@@ -10,7 +10,12 @@ import Foundation
import Network
final class NearbyDeviceNameResolver {
private var hostnameResolvers: [UUID: NearbyNetworkScannerHostnameResolver] = [:]
private static let hostnameLookupQueue = DispatchQueue(
label: "com.leonboettger.quickdrop.deviceNameHostnameLookup",
qos: .utility
)
private var hostnameResolvers: [UUID: NearbyBonjourServiceResolver] = [:]
private var lookupTokens: [String: UUID] = [:]
func needsLookup(for endpointInfo: EndpointInfo?) -> Bool {
@@ -47,10 +52,25 @@ final class NearbyDeviceNameResolver {
private func resolveAdvertisedHostname(for service: NWBrowser.Result, completion: @escaping (String?) -> Void) {
let resolverID = UUID()
guard let resolver = NearbyNetworkScannerHostnameResolver(result: service, resolveTimeout: 0.5, completion: { [weak self] hostname in
self?.hostnameResolvers.removeValue(forKey: resolverID)
completion(hostname)
}) else {
guard let resolver = NearbyBonjourServiceResolver(
result: service,
resolveTimeout: 0.5,
watchdogGracePeriod: 1.0,
completion: { [weak self] endpoints in
self?.hostnameResolvers.removeValue(forKey: resolverID)
guard let ipv4Address = endpoints.first(where: \.isIPv4)?.host else {
completion(nil)
return
}
Self.hostnameLookupQueue.async {
let hostname = NearbyHostLookup.hostname(forIPv4: ipv4Address)
DispatchQueue.main.async {
completion(hostname)
}
}
}
) else {
completion(nil)
return
}
@@ -61,142 +81,12 @@ final class NearbyDeviceNameResolver {
}
private final class NearbyNetworkScannerHostnameResolver: NSObject, NetServiceDelegate {
private static let hostnameLookupQueue = DispatchQueue(
label: "com.leonboettger.quickdrop.networkScannerHostname",
qos: .utility
)
private let service: NetService
private let resolveTimeout: TimeInterval
private var timeoutWorkItem: DispatchWorkItem?
private var completion: ((String?) -> Void)?
private var finished = false
init?(
result: NWBrowser.Result,
resolveTimeout: TimeInterval,
completion: @escaping (String?) -> Void
) {
guard case let NWEndpoint.service(name: name, type: type, domain: domain, interface: _) = result.endpoint else {
return nil
}
self.service = NetService(
domain: Self.normalizedServiceDomain(domain),
type: Self.normalizedServiceType(type),
name: name
)
self.resolveTimeout = resolveTimeout
self.completion = completion
super.init()
}
func start() {
service.delegate = self
service.resolve(withTimeout: resolveTimeout)
let timeoutWorkItem = DispatchWorkItem { [weak self] in
self?.finish(hostname: nil)
}
self.timeoutWorkItem = timeoutWorkItem
DispatchQueue.main.asyncAfter(deadline: .now() + resolveTimeout + 1.0, execute: timeoutWorkItem)
}
func cancel() {
finish(hostname: nil, notify: false)
}
func netServiceDidResolveAddress(_ sender: NetService) {
let numericAddresses = sender.addresses?.compactMap(Self.numericHostString) ?? []
guard let ipv4Address = numericAddresses.first(where: NearbyNetworkScannerHostLookup.isIPv4Address) else {
finish(hostname: nil)
return
}
Self.hostnameLookupQueue.async { [weak self] in
let hostname = NearbyNetworkScannerHostLookup.hostname(forIPv4: ipv4Address)
DispatchQueue.main.async {
self?.finish(hostname: hostname)
}
}
}
func netService(_ sender: NetService, didNotResolve errorDict: [String: NSNumber]) {
finish(hostname: nil)
}
private func finish(hostname: String?, notify: Bool = true) {
guard !finished else { return }
finished = true
timeoutWorkItem?.cancel()
service.stop()
service.delegate = nil
let completion = completion
self.completion = nil
if notify {
completion?(hostname)
}
}
private static func normalizedServiceDomain(_ domain: String) -> String {
let trimmedDomain = domain.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmedDomain.isEmpty else { return "local." }
return trimmedDomain.hasSuffix(".") ? trimmedDomain : "\(trimmedDomain)."
}
private static func normalizedServiceType(_ type: String) -> String {
let trimmedType = type.trimmingCharacters(in: .whitespacesAndNewlines)
return trimmedType.hasSuffix(".") ? trimmedType : "\(trimmedType)."
}
private static func numericHostString(from addressData: Data) -> String? {
addressData.withUnsafeBytes { rawBuffer in
guard let baseAddress = rawBuffer.baseAddress else { return nil }
var hostBuffer = [CChar](repeating: 0, count: Int(NI_MAXHOST))
let sockaddrPointer = baseAddress.assumingMemoryBound(to: sockaddr.self)
let result = getnameinfo(
sockaddrPointer,
socklen_t(addressData.count),
&hostBuffer,
socklen_t(hostBuffer.count),
nil,
0,
NI_NUMERICHOST
)
guard result == 0 else { return nil }
return String(cString: hostBuffer)
.split(separator: "%")
.first
.map(String.init)
}
}
}
private enum NearbyNetworkScannerHostLookup {
private enum NearbyHostLookup {
static func hostname(forIPv4 address: String) -> String? {
reverseDNSName(forIPv4: address).flatMap(prettifyDisplayName)
}
static func isIPv4Address(_ address: String) -> Bool {
!address.contains(":")
}
private static func reverseDNSName(forIPv4 address: String) -> String? {
var socketAddress = sockaddr_in()
socketAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
+16 -16
View File
@@ -31,12 +31,12 @@
EB05DFBE2E59FC8900EF567A /* TrustedDevicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB05DFBD2E59FC8000EF567A /* TrustedDevicesView.swift */; };
EB05DFBF2E59FD0A00EF567A /* TrustedDevicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB05DFBD2E59FC8000EF567A /* TrustedDevicesView.swift */; };
EB05DFC02E5A2EAA00EF567A /* TrustedDevicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB05DFBD2E59FC8000EF567A /* TrustedDevicesView.swift */; };
EB0A22E32FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB0A22E22FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift */; };
EB0A22E42FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB0A22E22FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift */; };
EB0A22E52FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB0A22E22FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift */; };
EB0A22E62FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB0A22E22FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift */; };
EB0A22E72FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB0A22E22FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift */; };
EB0A22E82FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB0A22E22FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift */; };
EB0A22E32FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB0A22E22FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift */; };
EB0A22E42FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB0A22E22FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift */; };
EB0A22E52FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB0A22E22FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift */; };
EB0A22E62FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB0A22E22FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift */; };
EB0A22E72FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB0A22E22FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift */; };
EB0A22E82FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB0A22E22FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift */; };
EB1325D32E701D8E00FD749C /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB1325D22E701D8900FD749C /* Settings.swift */; };
EB1325D42E701D8E00FD749C /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB1325D22E701D8900FD749C /* Settings.swift */; };
EB1325D52E701D8E00FD749C /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB1325D22E701D8900FD749C /* Settings.swift */; };
@@ -524,7 +524,7 @@
A1F5B3D82F3A1A0100A1B2C3 /* PairingToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PairingToken.swift; sourceTree = "<group>"; };
A1F5B3D92F3A1A0100A1B2C4 /* PairingQrSheetManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PairingQrSheetManager.swift; sourceTree = "<group>"; };
EB05DFBD2E59FC8000EF567A /* TrustedDevicesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrustedDevicesView.swift; sourceTree = "<group>"; };
EB0A22E22FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearbyOutgoingServiceResolver.swift; sourceTree = "<group>"; };
EB0A22E22FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearbyBonjourServiceResolver.swift; sourceTree = "<group>"; };
EB1325D22E701D8900FD749C /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; };
EB1325E72E7025D900FD749C /* ActiveNetworkInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveNetworkInterface.swift; sourceTree = "<group>"; };
EB1325E82E7025D900FD749C /* ApIsolation6Tester.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApIsolation6Tester.swift; sourceTree = "<group>"; };
@@ -808,7 +808,7 @@
isa = PBXGroup;
children = (
69DA9A1E29E0C0B300A442DA /* NearbyConnectionManager.swift */,
EB0A22E22FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift */,
EB0A22E22FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift */,
EB3B9F192EF7150400D67050 /* NearbyDeviceNameResolver.swift */,
69DA9A2229E17F0400A442DA /* InboundNearbyConnection.swift */,
A1B2C3DA2F33AA0100ABC001 /* MirroredNotificationSupport.swift */,
@@ -1320,7 +1320,7 @@
EB5C37C52E377A780052EFD7 /* securemessage.pb.swift in Sources */,
EB5C37C62E377A780052EFD7 /* securegcm.pb.swift in Sources */,
EB5C37C72E377A780052EFD7 /* wire_format.pb.swift in Sources */,
EB0A22E42FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift in Sources */,
EB0A22E42FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift in Sources */,
EB5C37C82E377A780052EFD7 /* ukey.pb.swift in Sources */,
EB5C37C92E377A780052EFD7 /* device_to_device_messages.pb.swift in Sources */,
EB950B742E520957002D68FA /* Attachments.swift in Sources */,
@@ -1399,7 +1399,7 @@
EBC05C822E33B58300EECC18 /* ApIsolationIssueView.swift in Sources */,
EBC05C832E33B58300EECC18 /* FirewallIssueView.swift in Sources */,
EB1325FA2E70288300FD749C /* SendToExtension.swift in Sources */,
EB0A22E72FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift in Sources */,
EB0A22E72FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift in Sources */,
EB1325F42E7025D900FD749C /* ApIsolationTester.swift in Sources */,
EB1325F52E7025D900FD749C /* ActiveNetworkInterface.swift in Sources */,
EB1325F62E7025D900FD749C /* ApIsolation6Tester.swift in Sources */,
@@ -1460,7 +1460,7 @@
EB3B9F272EF7150400D6704E /* ApIsolationIssueView.swift in Sources */,
EB3B9F282EF7150400D6704E /* FirewallIssueView.swift in Sources */,
EB3B9F292EF7150400D6704E /* SendToExtension.swift in Sources */,
EB0A22E82FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift in Sources */,
EB0A22E82FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift in Sources */,
EB3B9F2A2EF7150400D6704E /* ApIsolationTester.swift in Sources */,
EB3B9F2B2EF7150400D6704E /* ActiveNetworkInterface.swift in Sources */,
EB3B9F2C2EF7150400D6704E /* ApIsolation6Tester.swift in Sources */,
@@ -1491,7 +1491,7 @@
EB3B9F592EF7151900D6704E /* securemessage.pb.swift in Sources */,
EB3B9F5A2EF7151900D6704E /* securegcm.pb.swift in Sources */,
EB3B9F5B2EF7151900D6704E /* wire_format.pb.swift in Sources */,
EB0A22E52FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift in Sources */,
EB0A22E52FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift in Sources */,
EB3B9F5C2EF7151900D6704E /* ukey.pb.swift in Sources */,
EB3B9F5D2EF7151900D6704E /* device_to_device_messages.pb.swift in Sources */,
EB3B9F5F2EF7151900D6704E /* Attachments.swift in Sources */,
@@ -1540,7 +1540,7 @@
EB5C37F92E377CE70052EFD7 /* securegcm.pb.swift in Sources */,
EB5C37FA2E377CE70052EFD7 /* Helpers.swift in Sources */,
EB5C37FB2E377CE70052EFD7 /* InboundNearbyConnection.swift in Sources */,
EB0A22E62FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift in Sources */,
EB0A22E62FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift in Sources */,
A1B2C3D82F33AA0100ABC001 /* MirroredNotificationSupport.swift in Sources */,
EB9925802E45D53E00357055 /* sharing_enums.pb.swift in Sources */,
EB5C37FC2E377CE70052EFD7 /* OutboundNearbyConnection.swift in Sources */,
@@ -1585,7 +1585,7 @@
EB16B6132E58B4B9007D9792 /* IdentityManager.swift in Sources */,
EB950B4D2E520436002D68FA /* NearbyConnection.swift in Sources */,
EB950B502E520436002D68FA /* wire_format.pb.swift in Sources */,
EB0A22E32FBCF59300B78FF5 /* NearbyOutgoingServiceResolver.swift in Sources */,
EB0A22E32FBCF59300B78FF5 /* NearbyBonjourServiceResolver.swift in Sources */,
EB950B582E5205B4002D68FA /* Zip.swift in Sources */,
EB950B512E520436002D68FA /* securemessage.pb.swift in Sources */,
EBA1BB1F2EF1F6030068E46E /* ChangeDeviceNameModifier.swift in Sources */,
@@ -1812,7 +1812,7 @@
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SHARED_BUILD = 147;
SHARED_BUILD = 148;
SHARED_VERSION = 4.0;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
@@ -1875,7 +1875,7 @@
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
SHARED_BUILD = 147;
SHARED_BUILD = 148;
SHARED_VERSION = 4.0;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_COMPILATION_MODE = wholemodule;