Swift iOS- 有wifi但没有网络怎么办?
Swift iOS- What to do when there is a wifi connection but no internet connection?
我在 iOS 应用程序中使用 Alamofire。我在 viewWillAppear 和带有 NSNotifications 的 AppDelegate 中使用 bool 值来检查是否有互联网连接。如果没有 wifi 连接,则会出现一个弹出窗口通知用户。如果有 wifi 连接,弹出窗口消失,一切正常。只要 wifi 明显无法正常工作,我就没有遇到任何问题。
我在一次聚会上有人向我解释说它的工作方式是寻找 wifi 连接而不是互联网连接。例如,如果我有一个 wifi 路由器并且它已插入但路由器未连接到互联网,Alamofire 会将此视为成功连接,因为它实际上正在连接到 wifi,尽管它不知道 wifi 无法连接上网。
我只是处于连接到开放网络的情况,我的应用程序最初的响应就像我实际上连接到互联网一样(没有弹出窗口),但我无法连接到任何东西。无线网络信号是满的。在终端 I 运行 ping 后发现连接已断开。我的应用无法区分。
如何让弹出窗口出现在这种情况下?
还有什么是 .case 未知的?
Alamofire.Swift:
import Foundation
import Alamofire
open class NetworkManager {
open static var sharedManager: NetworkReachabilityManager = {
let reachabilityManager = NetworkReachabilityManager()
reachabilityManager?.listener = { (status) in
switch status {
case .notReachable:
print("The network is not reachable")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "unsuccessful"), object: nil)
case .unknown : //???????
print("It is unknown wether the network is reachable")
//I'm not sure whether to put a Notification for successful or unsuccessful???
case .reachable(.ethernetOrWiFi):
print("The network is reachable over the WiFi connection")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "successful"), object: nil)
case .reachable(.wwan):
print("The network is reachable over the WWAN connection")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "successful"), object: nil)
}
}
reachabilityManager?.startListening()
return reachabilityManager!
}()
}
AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
NetworkManager.sharedManager.startListening()
一些风投:
override func viewWillAppear() {
super.viewWillAppear()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(successful), name: "successful", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(unsuccessful), name: "unsuccessful", object: nil)
if NetworkManager.sharedManager.isReachable == true{
self.successful()
}else{
self.unsuccessful()
}
if NetworkManager.sharedManager.isReachableOnWWAN == true{
self.successful()
}else{
self.unsuccessful()
}
if NetworkManager.sharedManager.isReachableOnEthernetOrWiFi == true{
self.successful()
}else{
self.unsuccessful()
}
}
func successful(){
//dismiss pop up
}
func unsuccessful(){
//show pop up
}
deinit{
NSNotificationCenter.defaultCenter().removeObserver(self, name: "successful", object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: "unsuccessful", object: nil)
}
}
你可以初始化NetworkReachabilityManager
主机,例如google主机,因为默认是0.0.0.0
let reachabilityManager = Alamofire.NetworkReachabilityManager(host: "www.google.com")
当您开始监听可达性管理器对主机执行 ping 操作时。如果网络可用,您可以缓存 SSID 并在 SSID 更改时再次 ping。
case .unknown
最好放一个不成功的通知。
示例获取 SSID(它在模拟器中不起作用):
func fetchSSIDInfo() -> String? {
if let interfaces = CNCopySupportedInterfaces() {
for i in 0..<CFArrayGetCount(interfaces){
let interfaceName: UnsafeRawPointer = CFArrayGetValueAtIndex(interfaces, i)
let rec = unsafeBitCast(interfaceName, to: AnyObject.self)
let unsafeInterfaceData = CNCopyCurrentNetworkInfo("\(rec)" as CFString)
if let unsafeInterfaceData = unsafeInterfaceData as? Dictionary<AnyHashable, Any> {
return unsafeInterfaceData["SSID"] as? String
}
}
}
return nil
}
我遵循了这个 AshleyMills Reachability 文件(添加在下面),它使用 google.com
来测试连接。
重要的是要注意我设置它的方式是它专门监视 viewWillAppear 并且在切换选项卡和 pushing/popping/presenting 视图控制器时效果最好。在实际的 AshleyMills GitHub 回购中,他使用 DispatchQueue.asyncAfter( .now() + 5) 计时器和其他代码来持续监控,但我的回答中没有包含这些代码。为了持续监控,您应该使用上面 link 中的他的 ViewController 文件或此线程中我的
将此添加到 viewWillAppear
和 viewWillDisappear
:
var reachability: Reachability?
let reachabilityConnection = Reachability()!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setupReachability("www.google.com") // inside China use www.alibaba.com
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
stopNotifier()
}
func setupReachability(_ hostName: String) {
self.reachability = Reachability(hostname: hostName)
startNotifier()
}
func startNotifier() {
do {
print("notifier started")
try reachability?.startNotifier()
monitorReachability()
} catch {
print("*****Could not start notifier*****")
}
}
func monitorReachability() {
reachability?.whenReachable = { [weak self] (_) in
self?.reachabilityChanged()
}
reachability?.whenUnreachable = { [weak self] (_) in
self?.reachabilityChanged()
}
}
func reachabilityChanged() {
let reachability = reachabilityConnection
switch reachability.connection {
case .wifi:
print("----Reachable via WiFi")
case .cellular:
print("----Reachable via Cellular")
case .none:
print("----No Signal")
}
}
func stopNotifier() {
reachability?.stopNotifier()
reachability = nil
print("notifier stopped")
}
为 AshleyMills 文件创建一个文件并将其添加到其中。我将文件命名为 Networkability:
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: "Connection")
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 targetEnvironment(simulator)
return false
#else
return true
#endif
}()
fileprivate var notifierRunning = false
fileprivate let reachabilityRef: SCNetworkReachability
fileprivate let reachabilitySerialQueue = DispatchQueue(label: "uk.co.ashleymills.reachability")
fileprivate var usingHostname = false
required public init(reachabilityRef: SCNetworkReachability, usingHostname: Bool = false) {
allowsCellularConnection = true
self.reachabilityRef = reachabilityRef
self.usingHostname = usingHostname
}
public convenience init?(hostname: String) {
guard let ref = SCNetworkReachabilityCreateWithName(nil, hostname) else { return nil }
self.init(reachabilityRef: ref, usingHostname: true)
}
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 }
guard let reachable = whenReachable else { return }
guard let unreachable = whenUnreachable else { return }
print("?????>>>>>>\(reachable)")
let block = connection != .none ? reachable : unreachable
DispatchQueue.main.async {
if self.usingHostname {
print("USING HOSTNAME ABOUT TO CALL BLOCK")
}
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) {
print("Returning flags \(flags)")
return flags
} else {
return SCNetworkReachabilityFlags()
}
}
}
这是一个使用 Firebase 的答案。您必须事先 install the Firebase pod。将此添加到 viewWillAppear
和 viewWillDisappear
:
import Firebase
let connectedRef = Database.database().reference(withPath: ".info/connected")
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
checkForAFirebaseConnection()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
connectedRef.removeAllObservers()
}
func checkForAFirebaseConnection() {
connectedRef.observe(.value, with: { [weak self](connected) in
if let boolean = connected.value as? Bool, boolean == true {
print("Firebase is connected")
} else {
print("Firebase is NOT connected")
}
})
}
我遇到了同样的问题,所以在 Whosebug 上的一些答案的帮助下,我创建了一个代码,如果响应状态为 200,则简单地异步命中 google.com 并且在完成处理程序中 return 为真。
Swift4 中的代码:
class func checkInternet(showLoader: Bool = true, completionHandler:@escaping (_ internet:Bool) -> Void)
{
UIApplication.shared.isNetworkActivityIndicatorVisible = true
let url = URL(string: "http://www.google.com/")
var req = URLRequest.init(url: url!)
req.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalAndRemoteCacheData
req.timeoutInterval = 10.0
if showLoader {
Loader.startLoading()
}
let task = URLSession.shared.dataTask(with: req) { (data, response, error) in
if showLoader {
Loader.stopLoading()
}
if error != nil {
completionHandler(false)
} else {
if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 200 {
completionHandler(true)
} else {
completionHandler(false)
}
} else {
completionHandler(false)
}
}
}
task.resume()
}
现在您可以像这样使用它:
InternetCheck.checkInternet(completionHandler: { (available) in
if available {
print("Net available")
} else {
print("Net not available")
}
我在 iOS 应用程序中使用 Alamofire。我在 viewWillAppear 和带有 NSNotifications 的 AppDelegate 中使用 bool 值来检查是否有互联网连接。如果没有 wifi 连接,则会出现一个弹出窗口通知用户。如果有 wifi 连接,弹出窗口消失,一切正常。只要 wifi 明显无法正常工作,我就没有遇到任何问题。
我在一次聚会上有人向我解释说它的工作方式是寻找 wifi 连接而不是互联网连接。例如,如果我有一个 wifi 路由器并且它已插入但路由器未连接到互联网,Alamofire 会将此视为成功连接,因为它实际上正在连接到 wifi,尽管它不知道 wifi 无法连接上网。
我只是处于连接到开放网络的情况,我的应用程序最初的响应就像我实际上连接到互联网一样(没有弹出窗口),但我无法连接到任何东西。无线网络信号是满的。在终端 I 运行 ping 后发现连接已断开。我的应用无法区分。
如何让弹出窗口出现在这种情况下?
还有什么是 .case 未知的?
Alamofire.Swift:
import Foundation
import Alamofire
open class NetworkManager {
open static var sharedManager: NetworkReachabilityManager = {
let reachabilityManager = NetworkReachabilityManager()
reachabilityManager?.listener = { (status) in
switch status {
case .notReachable:
print("The network is not reachable")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "unsuccessful"), object: nil)
case .unknown : //???????
print("It is unknown wether the network is reachable")
//I'm not sure whether to put a Notification for successful or unsuccessful???
case .reachable(.ethernetOrWiFi):
print("The network is reachable over the WiFi connection")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "successful"), object: nil)
case .reachable(.wwan):
print("The network is reachable over the WWAN connection")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "successful"), object: nil)
}
}
reachabilityManager?.startListening()
return reachabilityManager!
}()
}
AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
NetworkManager.sharedManager.startListening()
一些风投:
override func viewWillAppear() {
super.viewWillAppear()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(successful), name: "successful", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(unsuccessful), name: "unsuccessful", object: nil)
if NetworkManager.sharedManager.isReachable == true{
self.successful()
}else{
self.unsuccessful()
}
if NetworkManager.sharedManager.isReachableOnWWAN == true{
self.successful()
}else{
self.unsuccessful()
}
if NetworkManager.sharedManager.isReachableOnEthernetOrWiFi == true{
self.successful()
}else{
self.unsuccessful()
}
}
func successful(){
//dismiss pop up
}
func unsuccessful(){
//show pop up
}
deinit{
NSNotificationCenter.defaultCenter().removeObserver(self, name: "successful", object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: "unsuccessful", object: nil)
}
}
你可以初始化NetworkReachabilityManager
主机,例如google主机,因为默认是0.0.0.0
let reachabilityManager = Alamofire.NetworkReachabilityManager(host: "www.google.com")
当您开始监听可达性管理器对主机执行 ping 操作时。如果网络可用,您可以缓存 SSID 并在 SSID 更改时再次 ping。
case .unknown
最好放一个不成功的通知。
示例获取 SSID(它在模拟器中不起作用):
func fetchSSIDInfo() -> String? {
if let interfaces = CNCopySupportedInterfaces() {
for i in 0..<CFArrayGetCount(interfaces){
let interfaceName: UnsafeRawPointer = CFArrayGetValueAtIndex(interfaces, i)
let rec = unsafeBitCast(interfaceName, to: AnyObject.self)
let unsafeInterfaceData = CNCopyCurrentNetworkInfo("\(rec)" as CFString)
if let unsafeInterfaceData = unsafeInterfaceData as? Dictionary<AnyHashable, Any> {
return unsafeInterfaceData["SSID"] as? String
}
}
}
return nil
}
我遵循了这个 AshleyMills Reachability 文件(添加在下面),它使用 google.com
来测试连接。
重要的是要注意我设置它的方式是它专门监视 viewWillAppear 并且在切换选项卡和 pushing/popping/presenting 视图控制器时效果最好。在实际的 AshleyMills GitHub 回购中,他使用 DispatchQueue.asyncAfter( .now() + 5) 计时器和其他代码来持续监控,但我的回答中没有包含这些代码。为了持续监控,您应该使用上面 link 中的他的 ViewController 文件或此线程中我的
将此添加到 viewWillAppear
和 viewWillDisappear
:
var reachability: Reachability?
let reachabilityConnection = Reachability()!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setupReachability("www.google.com") // inside China use www.alibaba.com
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
stopNotifier()
}
func setupReachability(_ hostName: String) {
self.reachability = Reachability(hostname: hostName)
startNotifier()
}
func startNotifier() {
do {
print("notifier started")
try reachability?.startNotifier()
monitorReachability()
} catch {
print("*****Could not start notifier*****")
}
}
func monitorReachability() {
reachability?.whenReachable = { [weak self] (_) in
self?.reachabilityChanged()
}
reachability?.whenUnreachable = { [weak self] (_) in
self?.reachabilityChanged()
}
}
func reachabilityChanged() {
let reachability = reachabilityConnection
switch reachability.connection {
case .wifi:
print("----Reachable via WiFi")
case .cellular:
print("----Reachable via Cellular")
case .none:
print("----No Signal")
}
}
func stopNotifier() {
reachability?.stopNotifier()
reachability = nil
print("notifier stopped")
}
为 AshleyMills 文件创建一个文件并将其添加到其中。我将文件命名为 Networkability:
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: "Connection")
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 targetEnvironment(simulator)
return false
#else
return true
#endif
}()
fileprivate var notifierRunning = false
fileprivate let reachabilityRef: SCNetworkReachability
fileprivate let reachabilitySerialQueue = DispatchQueue(label: "uk.co.ashleymills.reachability")
fileprivate var usingHostname = false
required public init(reachabilityRef: SCNetworkReachability, usingHostname: Bool = false) {
allowsCellularConnection = true
self.reachabilityRef = reachabilityRef
self.usingHostname = usingHostname
}
public convenience init?(hostname: String) {
guard let ref = SCNetworkReachabilityCreateWithName(nil, hostname) else { return nil }
self.init(reachabilityRef: ref, usingHostname: true)
}
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 }
guard let reachable = whenReachable else { return }
guard let unreachable = whenUnreachable else { return }
print("?????>>>>>>\(reachable)")
let block = connection != .none ? reachable : unreachable
DispatchQueue.main.async {
if self.usingHostname {
print("USING HOSTNAME ABOUT TO CALL BLOCK")
}
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) {
print("Returning flags \(flags)")
return flags
} else {
return SCNetworkReachabilityFlags()
}
}
}
这是一个使用 Firebase 的答案。您必须事先 install the Firebase pod。将此添加到 viewWillAppear
和 viewWillDisappear
:
import Firebase
let connectedRef = Database.database().reference(withPath: ".info/connected")
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
checkForAFirebaseConnection()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
connectedRef.removeAllObservers()
}
func checkForAFirebaseConnection() {
connectedRef.observe(.value, with: { [weak self](connected) in
if let boolean = connected.value as? Bool, boolean == true {
print("Firebase is connected")
} else {
print("Firebase is NOT connected")
}
})
}
我遇到了同样的问题,所以在 Whosebug 上的一些答案的帮助下,我创建了一个代码,如果响应状态为 200,则简单地异步命中 google.com 并且在完成处理程序中 return 为真。
Swift4 中的代码:
class func checkInternet(showLoader: Bool = true, completionHandler:@escaping (_ internet:Bool) -> Void)
{
UIApplication.shared.isNetworkActivityIndicatorVisible = true
let url = URL(string: "http://www.google.com/")
var req = URLRequest.init(url: url!)
req.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalAndRemoteCacheData
req.timeoutInterval = 10.0
if showLoader {
Loader.startLoading()
}
let task = URLSession.shared.dataTask(with: req) { (data, response, error) in
if showLoader {
Loader.stopLoading()
}
if error != nil {
completionHandler(false)
} else {
if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 200 {
completionHandler(true)
} else {
completionHandler(false)
}
} else {
completionHandler(false)
}
}
}
task.resume()
}
现在您可以像这样使用它:
InternetCheck.checkInternet(completionHandler: { (available) in
if available {
print("Net available")
} else {
print("Net not available")
}