Quellcode durchsuchen

Initial check in

Signed-off-by: Ashley Mills <ashleymills@mac.com>
Ashley Mills vor 11 Jahren
Ursprung
Commit
acc3ef30f8
3 geänderte Dateien mit 385 neuen und 19 gelöschten Zeilen
  1. 18 19
      LICENSE
  2. 2 0
      README.md
  3. 365 0
      Reachability.swift

+ 18 - 19
LICENSE

@@ -1,22 +1,21 @@
-The MIT License (MIT)
+/*
+Copyright (c) 2014, Ashley Mills
+All rights reserved.
 
-Copyright (c) 2014 Ashley Mills
+Redistribution and use in source, with or without modification, is permitted provided that the following condition is met:
 
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
 
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/

+ 2 - 0
README.md

@@ -2,3 +2,5 @@ Reachability.swift
 ==================
 
 Replacement for Apple's Reachability re-written in Swift with callbacks
+
+Inspired by https://github.com/tonymillion/Reachability 

+ 365 - 0
Reachability.swift

@@ -0,0 +1,365 @@
+/*
+Copyright (c) 2014, Ashley Mills
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+let ReachabilityChangedNotification = "ReachabilityChangedNotification"
+
+class Reachability {
+    
+    typealias NetworkReachable = (Reachability) -> ()
+    typealias NetworkUneachable = (Reachability) -> ()
+    typealias StartNotifier = (Reachability) -> (Bool)
+    
+    enum NetworkStatus {
+        // Apple NetworkStatus Compatible Names.
+        case NotReachable, ReachableViaWiFi, ReachableViaWWAN
+    }
+    
+    var reachabilityRef: SCNetworkReachability?
+    var reachabilitySerialQueue: dispatch_queue_t?
+    var reachabilityObject: AnyObject?
+    var reachableBlock: NetworkReachable?
+    var unreachableBlock: NetworkUneachable?
+    var startNotifierBlock: StartNotifier?
+    var reachableOnWWAN: Bool
+    
+    init(reachabilityRef: SCNetworkReachability) {
+        reachableOnWWAN = true;
+        self.reachabilityRef = reachabilityRef;
+    }
+    
+    convenience init(hostname: String) {
+        let ref = SCNetworkReachabilityCreateWithName(nil, (hostname as NSString).UTF8String).takeRetainedValue()
+        self.init(reachabilityRef: ref)
+    }
+    
+    class func reachabilityForInternetConnection() -> Reachability {
+        
+        var zeroAddress = sockaddr_in(sin_len: __uint8_t(0), sin_family: sa_family_t(0), sin_port: in_port_t(0), sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
+        zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
+        zeroAddress.sin_family = sa_family_t(AF_INET)
+        
+        let ref = withUnsafePointer(&zeroAddress) {
+            SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, UnsafePointer($0)).takeRetainedValue()
+        }
+        return Reachability(reachabilityRef: ref)
+    }
+    
+    class func reachabilityForLocalWiFi() -> Reachability {
+        
+        var localWifiAddress: sockaddr_in = sockaddr_in(sin_len: __uint8_t(0), sin_family: sa_family_t(0), sin_port: in_port_t(0), sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
+        localWifiAddress.sin_len = UInt8(sizeofValue(localWifiAddress))
+        localWifiAddress.sin_family = sa_family_t(AF_INET)
+        
+        // IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
+        localWifiAddress.sin_addr.s_addr = in_addr_t(Int64(0xA9FE0000).bigEndian)
+        
+        let ref = withUnsafePointer(&localWifiAddress) {
+            SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, UnsafePointer($0)).takeRetainedValue()
+        }
+        return Reachability(reachabilityRef: ref)
+    }
+    
+    func startNotifier() -> Bool {
+        
+        reachabilityObject = self
+        // First, we need to create a serial queue.
+        // We allocate this once for the lifetime of the notifier.
+        reachabilitySerialQueue = dispatch_queue_create("com.joylordsystems.reachability", nil)
+        if reachabilitySerialQueue == nil {
+            return false
+        }
+        
+        // TODO:
+        let callback:(SCNetworkReachability!, SCNetworkReachabilityFlags, UnsafeMutablePointer<Void>) -> () = { (target: SCNetworkReachability!, flags: SCNetworkReachabilityFlags, info: UnsafeMutablePointer<Void>) in
+            self.reachabilityChanged(flags)
+        }
+        
+        let p = UnsafeMutablePointer<(SCNetworkReachability!, SCNetworkReachabilityFlags, UnsafeMutablePointer<Void>) -> Void>.alloc(1)
+        p.initialize(callback)
+        
+        let cp = COpaquePointer(p) // convert UnsafeMutablePointer to COpaquePointer
+        let fp = CFunctionPointer<(SCNetworkReachability!, SCNetworkReachabilityFlags, UnsafeMutablePointer<Void>) -> Void>(cp) // convert COpaquePointer to CFunctionPointer
+        
+        if SCNetworkReachabilitySetCallback(self.reachabilityRef, fp, nil) != 0 {
+            
+            println("SCNetworkReachabilitySetCallback() failed: \(SCErrorString(SCError()))")
+            
+            // Clear out the dispatch queue
+            reachabilitySerialQueue = nil;
+            reachabilityObject = nil;
+            
+            return false;
+        }
+        
+        // Set it as our reachability queue, which will retain the queue
+        if SCNetworkReachabilitySetDispatchQueue(reachabilityRef, reachabilitySerialQueue) == 0
+        {
+            println("SCNetworkReachabilitySetDispatchQueue() failed: \(SCErrorString(SCError()))")
+            
+            // First stop, any callbacks!
+            SCNetworkReachabilitySetCallback(reachabilityRef, nil, nil)
+            
+            // Then clear out the dispatch queue.
+            reachabilitySerialQueue = nil
+            reachabilityObject = nil
+            
+            return false
+        }
+        
+        return true;
+    }
+    
+    func stopNotifier() {
+        
+        // First stop, any callbacks!
+        SCNetworkReachabilitySetCallback(reachabilityRef, nil, nil)
+        
+        // Unregister target from the GCD serial dispatch queue.
+        SCNetworkReachabilitySetDispatchQueue(nil, nil);
+        
+        reachabilitySerialQueue = nil;
+        reachabilityObject = nil;
+    }
+    
+    func reachabilityChanged(flags: SCNetworkReachabilityFlags) {
+        if isReachableWithFlags(flags) {
+            if let block = reachableBlock {
+                block(self)
+            }
+        } else {
+            if let block = unreachableBlock {
+                block(self)
+            }
+        }
+        
+        // this makes sure the change notification happens on the MAIN THREAD
+        dispatch_async(dispatch_get_main_queue()) {
+            NSNotificationCenter.defaultCenter().postNotificationName(ReachabilityChangedNotification, object:self)
+        }
+    }
+    
+    func isReachableWithFlags(flags: SCNetworkReachabilityFlags) -> Bool {
+        
+        let reachable = isReachable(flags)
+        
+        if reachable == 0 {
+            return false
+        }
+        
+        if isConnectionRequiredOrTransient(flags) {
+            return false
+        }
+        
+        #if TARGET_OS_IPHONE
+            if isOnWWAN(flags) && !reachableOnWWAN {
+            // We don't want to connect when on 3G.
+            return false
+            }
+        #endif
+        
+        return true
+    }
+    
+    func isReachableWithTest(test: (SCNetworkReachabilityFlags) -> (Bool)) -> Bool {
+        var flags: SCNetworkReachabilityFlags = 0
+        let gotFlags = SCNetworkReachabilityGetFlags(reachabilityRef, &flags) != 0
+        if gotFlags {
+            return test(flags)
+        }
+        
+        return false
+    }
+    
+    func isReachable() -> Bool {
+        return isReachableWithTest({ (flags: SCNetworkReachabilityFlags) -> (Bool) in
+            return self.isReachableWithFlags(flags)
+        })
+    }
+    
+    func isReachableViaWWAN() -> Bool {
+        #if TARGET_OS_IPHONE
+            return isReachableWithTest({ (flags: SCNetworkReachabilityFlags) -> (Bool) in
+            // Check we're REACHABLE
+            if self.isReachable(flags) {
+            
+            // Now, check we're on WWAN
+            if self.isOnWWAN(flags) {
+            return true
+            }
+            }
+            return false
+            })
+        #endif
+        return false
+    }
+    
+    func isReachableViaWiFi() -> Bool {
+        
+        return isReachableWithTest({ (flags: SCNetworkReachabilityFlags) -> (Bool) in
+            
+            // Check we're reachable
+            if self.isReachable(flags) {
+                #if TARGET_OS_IPHONE
+                    
+                    // Check we're NOT on WWAN
+                    if self.isOnWWAN(flags) {
+                    return false
+                    }
+                #endif
+                return true
+            }
+            
+            return false
+        })
+    }
+    
+    // WWAN may be available, but not active until a connection has been established.
+    // WiFi may require a connection for VPN on Demand.
+    func isConnectionRequired() -> Bool {
+        return connectionRequired()
+    }
+    
+    func connectionRequired() -> Bool {
+        return isReachableWithTest({ (flags: SCNetworkReachabilityFlags) -> (Bool) in
+            return self.isConnectionRequired(flags)
+        })
+    }
+    
+    // Dynamic, on demand connection?
+    func isConnectionOnDemand() -> Bool {
+        return isReachableWithTest({ (flags: SCNetworkReachabilityFlags) -> (Bool) in
+            return self.isConnectionRequired(flags) && self.isConnectionOnTrafficOrDemand(flags)
+        })
+    }
+    
+    // Is user intervention required?
+    func isInterventionRequired() -> Bool {
+        return isReachableWithTest({ (flags: SCNetworkReachabilityFlags) -> (Bool) in
+            return self.isConnectionRequired(flags) && self.isInterventionRequired(flags)
+        })
+    }
+    
+    func isOnWWAN(flags: SCNetworkReachabilityFlags) -> Bool {
+        return flags & SCNetworkReachabilityFlags(kSCNetworkReachabilityFlagsIsWWAN) != 0
+    }
+    func isReachable(flags: SCNetworkReachabilityFlags) -> Bool {
+        return flags & SCNetworkReachabilityFlags(kSCNetworkReachabilityFlagsReachable) != 0
+    }
+    func isConnectionRequired(flags: SCNetworkReachabilityFlags) -> Bool {
+        return flags & SCNetworkReachabilityFlags(kSCNetworkReachabilityFlagsConnectionRequired) != 0
+    }
+    func isInterventionRequired(flags: SCNetworkReachabilityFlags) -> Bool {
+        return flags & SCNetworkReachabilityFlags(kSCNetworkReachabilityFlagsInterventionRequired) != 0
+    }
+    func isConnectionOnTraffic(flags: SCNetworkReachabilityFlags) -> Bool {
+        return flags & SCNetworkReachabilityFlags(kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0
+    }
+    func isConnectionOnDemand(flags: SCNetworkReachabilityFlags) -> Bool {
+        return flags & SCNetworkReachabilityFlags(kSCNetworkReachabilityFlagsConnectionOnDemand) != 0
+    }
+    func isConnectionOnTrafficOrDemand(flags: SCNetworkReachabilityFlags) -> Bool {
+        return flags & SCNetworkReachabilityFlags(kSCNetworkReachabilityFlagsConnectionOnTraffic | kSCNetworkReachabilityFlagsConnectionOnDemand) != 0
+    }
+    func isTransientConnection(flags: SCNetworkReachabilityFlags) -> Bool {
+        return flags & SCNetworkReachabilityFlags(kSCNetworkReachabilityFlagsTransientConnection) != 0
+    }
+    func isLocalAddress(flags: SCNetworkReachabilityFlags) -> Bool {
+        return flags & SCNetworkReachabilityFlags(kSCNetworkReachabilityFlagsIsLocalAddress) != 0
+    }
+    func isDirect(flags: SCNetworkReachabilityFlags) -> Bool {
+        return flags & SCNetworkReachabilityFlags(kSCNetworkReachabilityFlagsIsDirect) != 0
+    }
+    func isConnectionRequiredOrTransient(flags: SCNetworkReachabilityFlags) -> Bool {
+        let testcase = SCNetworkReachabilityFlags(kSCNetworkReachabilityFlagsConnectionRequired | kSCNetworkReachabilityFlagsTransientConnection)
+        return flags & testcase == testcase
+    }
+    
+    // MARK: - *** xx methods ***
+    
+    var currentReachabilityStatus: NetworkStatus {
+        if isReachable() {
+            if isReachableViaWiFi() {
+                return .ReachableViaWiFi
+            }
+            #if	TARGET_OS_IPHONE
+                return .ReachableViaWWAN;a
+            #endif
+            }
+            
+            return .NotReachable
+    }
+    
+    var reachabilityFlags: SCNetworkReachabilityFlags {
+        var flags: SCNetworkReachabilityFlags = 0
+            let gotFlags = SCNetworkReachabilityGetFlags(reachabilityRef, &flags) != 0
+            if gotFlags {
+                return flags
+            }
+            
+            return 0
+    }
+    
+    var currentReachabilityString: String {
+        
+        switch currentReachabilityStatus {
+        case .ReachableViaWWAN:
+            return NSLocalizedString("Cellular", comment: "")
+        case .ReachableViaWiFi:
+            return NSLocalizedString("WiFi", comment: "")
+        case .NotReachable:
+            return NSLocalizedString("No Connection", comment: "");
+            }
+    }
+    
+    var currentReachabilityFlags: String {
+        #if	TARGET_OS_IPHONE
+            let W = isOnWWAN(reachabilityFlags) ? "W" : "-"
+            #else
+            let W = "X"
+            #endif
+            let R = isReachable(reachabilityFlags) ? "R" : "-"
+            let c = isConnectionRequired(reachabilityFlags) ? "c" : "-"
+            let t = isTransientConnection(reachabilityFlags) ? "t" : "-"
+            let i = isInterventionRequired(reachabilityFlags) ? "i" : "-"
+            let C = isConnectionOnTraffic(reachabilityFlags) ? "C" : "-"
+            let D = isConnectionOnDemand(reachabilityFlags) ? "D" : "-"
+            let l = isLocalAddress(reachabilityFlags) ? "l" : "-"
+            let d = isDirect(reachabilityFlags) ? "d" : "-"
+            
+            return "\(W)\(R) \(c)\(t)\(i)\(C)\(D)\(l)\(d)"
+    }
+    
+    deinit {
+        stopNotifier()
+        
+        reachabilityRef = nil
+        reachableBlock = nil
+        unreachableBlock = nil
+    }
+}
+
+