2017-03-28 238 views
1

我在我的iOS应用程序中使用Alamofire。我在viewWillAppear和AppDelegate中使用NSNotifications中的bool值来检查是否有互联网连接。如果没有WiFi连接,弹出窗口会通知用户。如果有wifi连接,弹出消失,一切正常。只要WiFi显然不工作,我没有问题。Alamofire - 当有wifi连接但没有互联网连接时该怎么办?

我在聚会上,有人向我解释,它的工作方式是它寻找无线连接而不是互联网连接。例如,如果我有一个无线路由器,它已插入,但路由器没有连接到互联网阿拉莫菲尔将这视为一个成功的连接,因为它实际上连接到WiFi,虽然它不知道无线连接不能连接到互联网。

我只是在我连接到一个开放网络的情况下,我的应用程序最初回应,就好像我实际上连接到互联网(没有弹出),但我无法连接到任何东西。无线信号已满。在终端,我跑了一个ping,结果证明连接已经死亡。我的应用程序无法区分差异。

enter image description hereenter image description here

如何使弹出出现在这样的sitaution?

什么是.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() 

SomeVC:

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) 
} 
} 

回答

1

可以初始化NetworkReachabilityManager与主机,例如,谷歌的主机,因为默认情况下是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 
    } 
+0

感谢我来试试。我如何缓存SSID? –

+0

添加得到ssid回答,为了保存ssid你可以使用用户默认值或你的数据库或其他方法 – Dialogue

+0

感谢您的帮助。我是否将该函数添加到Reachability类或SomeVC?你怎么称呼它并且用布尔测试?我看到它返回一个可选的String类型的 –

0

对于那些谁是有问题的可达性和这个答案并不能帮助遵循此YouTube VID:

https://youtu.be/wDZmz9IsB-8

他使用Ashly Mills。他解释得很好,而且很有效。

+0

兰斯感谢您试图提供帮助。我想澄清一下,尤其是因为我认为没有任何答案能够真正回答你的问题。您的使用案例是: “例如..如果我有一个无线路由器,它的插入,但路由器没有连接到互联网Alamofire将此视为一个成功的连接,因为它实际上是连接到WiFi,虽然它不知道WiFi无法连接到互联网。“ 这就是你所说的,如果你尝试使用youtube链接的代码并使用Reachability更改Alamofire,它不会回答这个问题。 – IvanMih

+0

@IvanMih我对YouTube上的代码没有任何问题视频我连接到wifi,没有收到任何数据,Ashly Mills的可达性显示没有任何联系,YouTube代码没有按照我刚刚描述的方式工作吗?至于接受的答案,我选择它的原因是因为他正确的说连接到一个网站,如谷歌,保证总是可以到达,如果没有,那么有一个问题。他的解释如何使用它并不清楚,但他是正确的。 –

+0

@伊万米伊凡我做了一些g在周围搜寻,检查这个答案。我在美国,而我没有意识到或想到的是,如果您尝试在不支持中国的国家/地区ping Google,那么它将无法工作。此外,如果你在2G上可能会有问题。 https://stackoverflow.com/questions/24516748/check-network-status-in-swift。我会对不同的答案做更多的研究,然后回到你身边。如果你发现更具体的东西让我知道,发布答案,我会upvote你。如果我找到它,我会为您发布 –

0

下面是这两个解决方案组成的答案:Pavle MijatovicYasin Ugurlu

创建一个新的类,并将其命名连接和复制和粘贴下面的代码在它的内部:

import Foundation 
import SystemConfiguration 

class Connection { 

    class func isConnectedToNetwork() -> Bool { 

     var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0)) 
     zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress)) 
     zeroAddress.sin_family = sa_family_t(AF_INET) 

     guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, { 
      $0.withMemoryRebound(to: sockaddr.self, capacity: 1) { 
       SCNetworkReachabilityCreateWithAddress(nil, $0) 
      } 
     }) else { 
      return false 
     } 

     var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0) 
     if SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) == false { 
      return false 
     } 

     let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0 
     let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0 

     return isReachable && !needsConnection 

    } 

    class func isInternetAvailable(webSiteToPing: String?, completionHandler: @escaping (Bool) -> Void) { 

     // 1. Check the WiFi Connection 
     guard isConnectedToNetwork() else { 
      completionHandler(false) 
      return 
     } 

     // 2. Check the Internet Connection but possibly use www.apple.com or www.alibaba.com instead of google.com because it's not available in China 
     var webAddress = "https://www.google.com" // Default Web Site 
     if let _ = webSiteToPing { 
      webAddress = webSiteToPing! 
     } 

     guard let url = URL(string: webAddress) else { 
      completionHandler(false) 
      print("could not create url from: \(webAddress)") 
      return 
     } 

     let urlRequest = URLRequest(url: url) 
     let session = URLSession.shared 
     let task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) in 
      if error != nil || response == nil { 
       completionHandler(false) 
      } else { 
       completionHandler(true) 
      } 
     }) 
     task.resume() 
    } 
} 

在任何视图控制器你用它在里面viewDidLoad这样称呼它:

override func viewDidLoad() { 
     super.viewDidLoad() 

     // if in china usewww.apple.com or www.alibaba.com instead 
     Connection.isInternetAvailable(webSiteToPing: "https://www.google.com", completionHandler: { 
      (bool) in 

      if bool{ 
       print("Internet connection is good") 
      }else{ 
       print("No internet connection can be found") 
      } 
     }) 
} 

我发现了一些事情是只看到毫秒工作一次,因为如果连接可用"Internet connection is good"打印但如果我去飞行模式"No internet connection can be found"不打印。这不是积极倾听,这让我觉得我必须连接到通知?另一件事是,如果你在中国,那么这是行不通的,因为谷歌在中国不可用。也许一个更好的网站将检查www.apple.com或www.alibaba.com,因为它似乎无处不在。

Connection.isInternetAvailable(webSiteToPing: "https://www.apple.com"... 

Connection.isInternetAvailable(webSiteToPing: "https://www.alibaba.com"... 
相关问题