因为没有 API 可以直接返回您的本地网络访问状态,您可以使用下一个方法发布您的 Bonjour 服务,并且如果您的应用程序已经设置了对本地网络的访问权限(例如在应用程序启动时),它会返回正确的结果。该方法也会导致警报出现,但在您选择任何按钮之前会返回false,因此为了获得正确的结果,您应该将此检查设置为applicationDidBecomeActive,它会在本地网络警报消失并返回后给出正确的状态到您的应用。
class getLocalNetworkAccessState : NSObject {
var service: NetService
var denied: DispatchWorkItem?
var completion: ((Bool) -> Void)
@discardableResult
init(completion: @escaping (Bool) -> Void) {
self.completion = completion
service = NetService(domain: "local.", type:"_lnp._tcp.", name: "LocalNetworkPrivacy", port: 1100)
super.init()
denied = DispatchWorkItem {
self.completion(false)
self.service.stop()
self.denied = nil
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: denied!)
service.delegate = self
self.service.publish()
}
}
extension getLocalNetworkAccessState : NetServiceDelegate {
func netServiceDidPublish(_ sender: NetService) {
denied?.cancel()
denied = nil
completion(true)
}
func netService(_ sender: NetService, didNotPublish errorDict: [String : NSNumber]) {
print("Error: \(errorDict)")
}
}
使用方法:
getLocalNetworkAccessState { granted in
print(granted ? "granted" : "denied")
}
注意:不要忘记设置NSLocalNetworkUsageDescription 并添加“_lnp._tcp”。到 Info.plist 中的NSBonjourServices。
更新
第二种方法与上面的代码类似,但可以通过检查应用程序状态等待用户的回答,然后返回本地网络隐私的有效访问状态:
class LocalNetworkPrivacy : NSObject {
let service: NetService
var completion: ((Bool) -> Void)?
var timer: Timer?
var publishing = false
override init() {
service = .init(domain: "local.", type:"_lnp._tcp.", name: "LocalNetworkPrivacy", port: 1100)
super.init()
}
@objc
func checkAccessState(completion: @escaping (Bool) -> Void) {
self.completion = completion
timer = .scheduledTimer(withTimeInterval: 2, repeats: true, block: { timer in
guard UIApplication.shared.applicationState == .active else {
return
}
if self.publishing {
self.timer?.invalidate()
self.completion?(false)
}
else {
self.publishing = true
self.service.delegate = self
self.service.publish()
}
})
}
deinit {
service.stop()
}
}
extension LocalNetworkPrivacy : NetServiceDelegate {
func netServiceDidPublish(_ sender: NetService) {
timer?.invalidate()
completion?(true)
}
}
// How to use
LocalNetworkPrivacy().checkAccessState { granted in
print(granted)
}
ObjC
您可以使用swift代码而无需重写ObjC,只需将swift文件添加到您的项目并直接调用checkAccessState(该函数必须标有@objc):
#import "YourProjectName-Swift.h" // import swift classes to objc
...
LocalNetworkPrivacy *local = [LocalNetworkPrivacy new];
[local checkAccessStateWithCompletion:^(BOOL granted) {
NSLog(@"Granted: %@", granted ? @"yes" : @"no");
}];