2017-03-28 304 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"... 
相關問題