当 wifi 重新打开时,Ashley Mills 可达性不发送通知?
Posted
技术标签:
【中文标题】当 wifi 重新打开时,Ashley Mills 可达性不发送通知?【英文标题】:Ashley Mills reachability not sending notification when wifi turns back on? 【发布时间】:2017-11-02 03:54:56 【问题描述】:我有一个设置,使用Ashley Mills Reachability,它应该在应用程序的连接发生变化时使用NotificationCenter
向应用程序发送通知。设置如下:
func reachabilityChanged(note: Notification)
let reachability = note.object as! Reachability
switch reachability.connection
case .wifi:
print("Reachable via WiFi")
case .cellular:
print("Reachable via Cellular")
case .none:
print("Network not reachable")
override func viewDidLoad()
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(self.reachabilityChanged), name: .reachabilityChanged, object: reachability)
do
try reachability.startNotifier()
catch
print("could not start reachability notifier")
将我的计算机(我正在运行模拟器的计算机)连接到 wifi 后,控制台会准确打印“可通过 Wifi 访问”。关闭 wifi 会导致控制台再次准确打印“无法访问网络”。但是,当我重新打开 wifi 时,我遇到了问题。 “可通过 Wifi 访问”不会打印到日志中……事实上,日志中没有任何内容。我不知道为什么会发生这种情况,也不知道如何解决。有人有什么想法吗? 这是可达性代码:
import SystemConfiguration
import Foundation
public enum ReachabilityError: Error
case FailedToCreateWithAddress(sockaddr_in)
case FailedToCreateWithHostname(String)
case UnableToSetCallback
case UnableToSetDispatchQueue
@available(*, unavailable, renamed: "Notification.Name.reachabilityChanged")
public let ReachabilityChangedNotification = NSNotification.Name("ReachabilityChangedNotification")
extension Notification.Name
public static let reachabilityChanged = Notification.Name("reachabilityChanged")
func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?)
guard let info = info else return
let reachability = Unmanaged<Reachability>.fromOpaque(info).takeUnretainedValue()
reachability.reachabilityChanged()
public class Reachability
public typealias NetworkReachable = (Reachability) -> ()
public typealias NetworkUnreachable = (Reachability) -> ()
@available(*, unavailable, renamed: "Conection")
public enum NetworkStatus: CustomStringConvertible
case notReachable, reachableViaWiFi, reachableViaWWAN
public var description: String
switch self
case .reachableViaWWAN: return "Cellular"
case .reachableViaWiFi: return "WiFi"
case .notReachable: return "No Connection"
public enum Connection: CustomStringConvertible
case none, wifi, cellular
public var description: String
switch self
case .cellular: return "Cellular"
case .wifi: return "WiFi"
case .none: return "No Connection"
public var whenReachable: NetworkReachable?
public var whenUnreachable: NetworkUnreachable?
@available(*, deprecated: 4.0, renamed: "allowsCellularConnection")
public let reachableOnWWAN: Bool = true
/// Set to `false` to force Reachability.connection to .none when on cellular connection (default value `true`)
public var allowsCellularConnection: Bool
// The notification center on which "reachability changed" events are being posted
public var notificationCenter: NotificationCenter = NotificationCenter.default
@available(*, deprecated: 4.0, renamed: "connection.description")
public var currentReachabilityString: String
return "\(connection)"
@available(*, unavailable, renamed: "connection")
public var currentReachabilityStatus: Connection
return connection
public var connection: Connection
guard isReachableFlagSet else return .none
// If we're reachable, but not on an ios device (i.e. simulator), we must be on WiFi
guard isRunningOnDevice else return .wifi
var connection = Connection.none
if !isConnectionRequiredFlagSet
connection = .wifi
if isConnectionOnTrafficOrDemandFlagSet
if !isInterventionRequiredFlagSet
connection = .wifi
if isOnWWANFlagSet
if !allowsCellularConnection
connection = .none
else
connection = .cellular
return connection
fileprivate var previousFlags: SCNetworkReachabilityFlags?
fileprivate var isRunningOnDevice: Bool =
#if (arch(i386) || arch(x86_64)) && os(iOS)
return false
#else
return true
#endif
()
fileprivate var notifierRunning = false
fileprivate let reachabilityRef: SCNetworkReachability
fileprivate let reachabilitySerialQueue = DispatchQueue(label: "uk.co.ashleymills.reachability")
required public init(reachabilityRef: SCNetworkReachability)
allowsCellularConnection = true
self.reachabilityRef = reachabilityRef
public convenience init?(hostname: String)
guard let ref = SCNetworkReachabilityCreateWithName(nil, hostname) else return nil
self.init(reachabilityRef: ref)
public convenience init?()
var zeroAddress = sockaddr()
zeroAddress.sa_len = UInt8(MemoryLayout<sockaddr>.size)
zeroAddress.sa_family = sa_family_t(AF_INET)
guard let ref = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress) else return nil
self.init(reachabilityRef: ref)
deinit
stopNotifier()
public extension Reachability
// MARK: - *** Notifier methods ***
func startNotifier() throws
guard !notifierRunning else return
var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
context.info = UnsafeMutableRawPointer(Unmanaged<Reachability>.passUnretained(self).toOpaque())
if !SCNetworkReachabilitySetCallback(reachabilityRef, callback, &context)
stopNotifier()
throw ReachabilityError.UnableToSetCallback
if !SCNetworkReachabilitySetDispatchQueue(reachabilityRef, reachabilitySerialQueue)
stopNotifier()
throw ReachabilityError.UnableToSetDispatchQueue
// Perform an initial check
reachabilitySerialQueue.async
self.reachabilityChanged()
notifierRunning = true
func stopNotifier()
defer notifierRunning = false
SCNetworkReachabilitySetCallback(reachabilityRef, nil, nil)
SCNetworkReachabilitySetDispatchQueue(reachabilityRef, nil)
// MARK: - *** Connection test methods ***
@available(*, deprecated: 4.0, message: "Please use `connection != .none`")
var isReachable: Bool
guard isReachableFlagSet else return false
if isConnectionRequiredAndTransientFlagSet
return false
if isRunningOnDevice
if isOnWWANFlagSet && !reachableOnWWAN
// We don't want to connect when on cellular connection
return false
return true
@available(*, deprecated: 4.0, message: "Please use `connection == .cellular`")
var isReachableViaWWAN: Bool
// Check we're not on the simulator, we're REACHABLE and check we're on WWAN
return isRunningOnDevice && isReachableFlagSet && isOnWWANFlagSet
@available(*, deprecated: 4.0, message: "Please use `connection == .wifi`")
var isReachableViaWiFi: Bool
// Check we're reachable
guard isReachableFlagSet else return false
// If reachable we're reachable, but not on an iOS device (i.e. simulator), we must be on WiFi
guard isRunningOnDevice else return true
// Check we're NOT on WWAN
return !isOnWWANFlagSet
var description: String
let W = isRunningOnDevice ? (isOnWWANFlagSet ? "W" : "-") : "X"
let R = isReachableFlagSet ? "R" : "-"
let c = isConnectionRequiredFlagSet ? "c" : "-"
let t = isTransientConnectionFlagSet ? "t" : "-"
let i = isInterventionRequiredFlagSet ? "i" : "-"
let C = isConnectionOnTrafficFlagSet ? "C" : "-"
let D = isConnectionOnDemandFlagSet ? "D" : "-"
let l = isLocalAddressFlagSet ? "l" : "-"
let d = isDirectFlagSet ? "d" : "-"
return "\(W)\(R) \(c)\(t)\(i)\(C)\(D)\(l)\(d)"
fileprivate extension Reachability
func reachabilityChanged()
guard previousFlags != flags else return
let block = connection != .none ? whenReachable : whenUnreachable
DispatchQueue.main.async
block?(self)
self.notificationCenter.post(name: .reachabilityChanged, object:self)
previousFlags = flags
var isOnWWANFlagSet: Bool
#if os(iOS)
return flags.contains(.isWWAN)
#else
return false
#endif
var isReachableFlagSet: Bool
return flags.contains(.reachable)
var isConnectionRequiredFlagSet: Bool
return flags.contains(.connectionRequired)
var isInterventionRequiredFlagSet: Bool
return flags.contains(.interventionRequired)
var isConnectionOnTrafficFlagSet: Bool
return flags.contains(.connectionOnTraffic)
var isConnectionOnDemandFlagSet: Bool
return flags.contains(.connectionOnDemand)
var isConnectionOnTrafficOrDemandFlagSet: Bool
return !flags.intersection([.connectionOnTraffic, .connectionOnDemand]).isEmpty
var isTransientConnectionFlagSet: Bool
return flags.contains(.transientConnection)
var isLocalAddressFlagSet: Bool
return flags.contains(.isLocalAddress)
var isDirectFlagSet: Bool
return flags.contains(.isDirect)
var isConnectionRequiredAndTransientFlagSet: Bool
return flags.intersection([.connectionRequired, .transientConnection]) == [.connectionRequired, .transientConnection]
var flags: SCNetworkReachabilityFlags
var flags = SCNetworkReachabilityFlags()
if SCNetworkReachabilityGetFlags(reachabilityRef, &flags)
return flags
else
return SCNetworkReachabilityFlags()
【问题讨论】:
【参考方案1】:在模拟器中每次运行只会触发一次,但在真实的iOS设备上,它可以正常工作。
【讨论】:
以上是关于当 wifi 重新打开时,Ashley Mills 可达性不发送通知?的主要内容,如果未能解决你的问题,请参考以下文章
Firebase -can Database.database().reference(withPath: ".info/connected") 替代 Ashley Mills 可