Skip to content

Commit

Permalink
Release 1.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
rwbutler committed Nov 14, 2018
1 parent e6d55a5 commit 9e050d4
Show file tree
Hide file tree
Showing 5 changed files with 260 additions and 53 deletions.
40 changes: 40 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.1.0] - 2018-11-14

### Added
- Allows the polling interval to be configured.
- Exposes the `ConnectivityDidChange` notification name as part of the public interface.

### Changed
- Enforces SSL by default.

## [1.0.0] - 2018-09-20
### Changed
- Updated for Xcode 10 and Swift 4.2.

## [0.0.4] - 2018-08-18
### Changed
- Fixed an issue whereby the callback could be invoked more frequently than necessary if using the polling option.

## [0.0.3] - 2018-08-18
### Added
- Adds a sample application to demonstrate how to use Connectivity.
### Changed
- Improvements to code structure and an early exit mechanism such that once the required number of successful connectivity checks has been met any pending checks will be cancelled as they will no longer affect the result.

## [0.0.2] - 2018-08-07
### Changed
- This release introduces support for Swift 4 and integration using the Carthage dependency manager. In order to integrate Connectivity into your project via Carthage, add the following line to your project's Cartfile:

```
github "rwbutler/Connectivity"
```

## [0.0.1] - 2018-07-27
### Added
- Connectivity is a framework which improves on Reachability by allowing developers to detect whether true Internet connectivity is available or whether a captive portal is blocking Internet traffic.
2 changes: 1 addition & 1 deletion Connectivity.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'Connectivity'
s.version = '1.0.0'
s.version = '1.1.0'
s.summary = 'Connectivity improves on Reachability for determining Internet connectivity in your iOS application'
s.description = <<-DESC
Connectivity wraps Apple's Reachability code to provide a reliable measure of whether Internet connectivity is available where Reachability alone can only indicate whether _an interface is available that might allow a connection_. Connectivity's objective is to solve the captive portal problem whereby an iOS device is connected to a WiFi network lacking Internet connectivity. Such situations are commonplace and may occur for example when connecting to a public WiFi network which requires the user to register before use. Connectivity can detect such situations enabling you to react accordingly.
Expand Down
110 changes: 67 additions & 43 deletions Connectivity/Classes/Connectivity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
//

extension Notification.Name {
static let ReachabilityDidChange = Notification.Name("kNetworkReachabilityChangedNotification")
static let ConnectivityDidChange = Notification.Name("kNetworkConnectivityChangedNotification")
public static let ReachabilityDidChange = Notification.Name("kNetworkReachabilityChangedNotification")
public static let ConnectivityDidChange = Notification.Name("kNetworkConnectivityChangedNotification")
}

public class Connectivity {
Expand Down Expand Up @@ -48,38 +48,21 @@ public class Connectivity {
}

// MARK: State
// Whether connectivity checks should be performed without waiting for reachability changes
public var aggressivePolling: Bool = false {
didSet {
setAggressivePolling(enabled: aggressivePolling)
}
}

/// % successful connections required to be deemed to have connectivity
public var connectivityThreshold: Connectivity.Percentage = Connectivity.Percentage(75.0)
public var successThreshold: Connectivity.Percentage = Connectivity.Percentage(75.0)

/// URLs to contact in order to check connectivity
public var connectivityURLs: [URL] = {
var result: [URL] = []
let connectivityDomains: [String] = (isHTTPSOnly)
? [ "www.apple.com" ] // Replace with custom URLs
: [ "www.apple.com",
"apple.com",
"www.appleiphonecell.com",
"www.itools.info",
"www.ibook.info",
"www.airport.us",
"www.thinkdifferent.us"
]
let connectivityPath = "/library/test/success.html"
let httpProtocol = (isHTTPSOnly) ? "https" : "http"
for domain in connectivityDomains {
if let connectivityURL = URL(string: "\(httpProtocol)://\(domain)\(connectivityPath)") {
result.append(connectivityURL)
public var connectivityURLs: [URL] = Connectivity
.defaultConnectivityURLs(shouldUseHTTPS: Connectivity.isHTTPSOnly) {
didSet {
if Connectivity.isHTTPSOnly { // if HTTPS only set only allow HTTPS URLs
connectivityURLs = connectivityURLs.filter({ url in
return url.absoluteString.lowercased().starts(with: "https")
})
}
}
return result
}()
}

/// Response expected from connectivity URLs
private let expectedResponse = "Success"
Expand All @@ -88,29 +71,46 @@ public class Connectivity {
public private(set) var isConnected: Bool = false

/// Whether or not only HTTPS URLs should be used to check connectivity
public static var isHTTPSOnly: Bool = {
guard let bundleInfo = Bundle.main.infoDictionary,
let appTransportSecurity = bundleInfo["NSAppTransportSecurity"] as? [String: Any],
let allowsArbitraryLoads = appTransportSecurity["NSAllowsArbitraryLoads"] as? Bool else {
return true
public static var isHTTPSOnly: Bool = true {
didSet {
// Only set true if `allow arbitrary loads` is set
guard let bundleInfo = Bundle.main.infoDictionary,
let appTransportSecurity = bundleInfo["NSAppTransportSecurity"] as? [String: Any],
let allowsArbitraryLoads = appTransportSecurity["NSAllowsArbitraryLoads"] as? Bool,
allowsArbitraryLoads else {
isHTTPSOnly = true
return
}
}
return !allowsArbitraryLoads
}()
}

/// Whether we are listening for changes in reachability (otherwise performing a one-off connectivity check)
fileprivate var isObservingReachability = false

/// Queue to callback on
private var queue: DispatchQueue = DispatchQueue.main
/// Whether connectivity checks should be performed without waiting for reachability changes
public var isPollingEnabled: Bool = false {
didSet {
if isObservingReachability, oldValue != isPollingEnabled {
setPollingEnabled(isPollingEnabled)
}
}
}

/// Where polling is enabled, the interval at which connectivity checks will be performed.
private var pollingInterval: Double = 10.0

/// Status last time a check was performed
private var previousStatus: ConnectivityStatus?

/// Queue to callback on
private var queue: DispatchQueue = DispatchQueue.main

/// Reachability instance for checking network adapter status
private let reachability: Reachability

/// Status of the current connection
public var status: ConnectivityStatus {
if !isObservingReachability { checkConnectivity() } // Support one-off connectivity checks
switch reachability.currentReachabilityStatus() {
case ReachableViaWWAN:
return (isConnected) ? .connectedViaWWAN : .connectedViaWWANWithoutInternet
Expand Down Expand Up @@ -142,7 +142,8 @@ public class Connectivity {
public var whenDisconnected: NetworkDisconnected?

// MARK: Life cycle
public init() {
public init(shouldUseHTTPS: Bool = true) {
type(of: self).isHTTPSOnly = shouldUseHTTPS
reachability = Reachability.forInternetConnection()
}

Expand Down Expand Up @@ -186,7 +187,7 @@ public extension Connectivity {
checkConnectivity()
reachability.startNotifier()
isObservingReachability = true
setAggressivePolling(enabled: aggressivePolling)
setPollingEnabled(isPollingEnabled)
NotificationCenter.default.addObserver(self,
selector: #selector(reachabilityDidChange(_:)),
name: NSNotification.Name.ReachabilityDidChange,
Expand Down Expand Up @@ -216,7 +217,7 @@ private extension Connectivity {
var failedConnectivityChecks: Double = 0
let totalConnectivityChecks: Double = Double(connectivityURLs.count)
let percentageSuccessful = { (successfulConnectivityChecks / totalConnectivityChecks) * 100.0 }
let isConnected = { percentageSuccessful() >= self.connectivityThreshold.value }
let isConnected = { percentageSuccessful() >= self.successThreshold.value }

// Check whether enough tasks have successfully completed to be considered connected
let earlyExit = {
Expand Down Expand Up @@ -265,6 +266,29 @@ private extension Connectivity {
}
}

/// Set of connectivity URLs used by default if none are otherwise specified.
static func defaultConnectivityURLs(shouldUseHTTPS: Bool) -> [URL] {
var result: [URL] = []
let connectivityDomains: [String] = (shouldUseHTTPS)
? [ "www.apple.com" ] // Replace with custom URLs
: [ "www.apple.com",
"apple.com",
"www.appleiphonecell.com",
"www.itools.info",
"www.ibook.info",
"www.airport.us",
"www.thinkdifferent.us"
]
let connectivityPath = "/library/test/success.html"
let httpProtocol = (isHTTPSOnly) ? "https" : "http"
for domain in connectivityDomains {
if let connectivityURL = URL(string: "\(httpProtocol)://\(domain)\(connectivityPath)") {
result.append(connectivityURL)
}
}
return result
}

/// Checks connectivity when change in reachability observed
@objc func reachabilityDidChange(_ notification: NSNotification) {
checkConnectivity()
Expand All @@ -278,12 +302,12 @@ private extension Connectivity {
return previousStatus != currentStatus
}

/// Checks connectivity every 5 seconds rather than waiting for changes in Reachability status
func setAggressivePolling(enabled: Bool) {
/// Checks connectivity every <polling interval> seconds rather than waiting for changes in Reachability status
func setPollingEnabled(_ enabled: Bool) {
if #available(iOS 10.0, *) {
timer?.invalidate()
guard enabled else { return }
timer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true, block: { [weak self] _ in
timer = Timer.scheduledTimer(withTimeInterval: pollingInterval, repeats: true, block: { [weak self] _ in
self?.checkConnectivity()
})
}
Expand Down
Loading

0 comments on commit 9e050d4

Please sign in to comment.