Checking for internet connection or wifi connection with reachabilitySwift - ios

I'm building an iOS app, at some point i needed to check the app's acces to internet, so i used the ReachabilitySwift library.
After some tests, it seems to me that the library only checks if the device has the wifi connected and not having an actual internet connection provided from my router.
lets say i disconnected my router from internet, if my iOS device is connected via wifi to the router, the reachability tells me that we have internet connection where in actuallity my router has no internet.
I tried the reachability with a particular host but still having the same result
var reachability = Reachability.init(hostname: "google.com");
Is the reachability library supposed to give feedback when the wifi connection is lost or the actual internet connection is lost ?
Thank you in advance.

I have had similar issues with Reachability where I was making web service calls to VPN protected network.
var reachability = Reachability.init(hostname: "google.com");
didnt work for me as it returned true when there is Wifi connection.
I used Alamofire response when a dummy call is made to the server
func networkIsAvailable(available: (Bool, String?) -> Void) {
var message : String = ""
DispatchQueue.main.async {
HUD.show(.progress)
Alamofire.request(Constants.baseUrl, method: .get, parameters: ["foo": "bar"])
.responseJSON(completionHandler: { (response) in
let error = response.result.error as? NSError
if error?.localizedDescription == networkAlert {
message = networkAlert
available(false, message)
} else if error?.code == cannotConnectServerCode || error?.localizedDescription == cannotConnectServerMessage {
message = cannotConnectServerMessage
available(false, anotherNetworkAlert)
} else {
available(true, nil)
}
})
}
}

At WWDC, Apple has said many many times that if you need to simply see if WiFi or cell is up - use Reachable. If you need to see if you can connect to - then don’t use Reachable; instead simply connect and handle the error.
Reachable doesn’t actually check to see if it can connect to that IP based resource and if you are going to get a result back. The only way to do that is to actually try.
Look for networking sessions with Quinn on Apple’s WWDC site to see the same advice.

In the Reachablility.h you can find a declaration:
typedef enum : NSInteger {
NotReachable = 0,
ReachableViaWiFi,
ReachableViaWWAN
} NetworkStatus;
Then, inside Reachability class you can find the method, which returns type:
- (NetworkStatus)currentReachabilityStatus;
So, use it. In your swift code you can do it like this:
if reachability.currentReachabilityStatus == .ReachableViaWiFi {
// Do things...
}

Related

How to create NWConnection

Premise
I'm using Apple's Network framework to create a peer-to-peer app. What I'm currently trying to do is:
Device A establishes a connection with Device B and sends data.
Device B saves the NWConnection information of Device A.
Device B establishes a connection with Device A again using the saved MWConnection information and sends data.
I modelled off Apple's demo, which is essentially this source code here. Unlike Apple's demo, which establishes a single two-way connection and maintains that connection at all times, my app connects to multiple devices that can drop in and out of the connections at any time. This is why I want to be able to a) distinguish a specific device and b) initiate a new connection.
Problem
The problem I'm having is being able to reconstruct the NWConnection object using the information provided when a connection has been established. There are two ways of instantiating this object.
init(host: NWEndpoint.Host, port: NWEndpoint.Port, using: NWParameters)
init(to: NWEndpoint, using: NWParameters)
My attempts have been trying to gather the endpoint information like the host and the port while the connection with the desired device has been established and instantiate NWEndpoint to be used in NWConnection. But, I haven't been able to re-establish the connection thus far.
Following is the portion of the object that is used to initiate a connection. My full code is modified, but Apple's counterpart can be seen here.
class PeerConnection {
weak var delegate: PeerConnectionDelegate?
weak var statusDelegate: StatusDelegate?
var connection: NWConnection?
let initiatedConnection: Bool
init(endpoint: NWEndpoint, interface: NWInterface?, passcode: String, delegate: PeerConnectionDelegate) {
self.delegate = delegate
self.initiatedConnection = true
let connection = NWConnection(to: endpoint, using: NWParameters(passcode: passcode))
self.connection = connection
startConnection()
}
init(connection: NWConnection, delegate: PeerConnectionDelegate) {
self.delegate = delegate
self.connection = connection
self.initiatedConnection = false
startConnection()
}
// Handle starting the peer-to-peer connection for both inbound and outbound connections.
func startConnection() {
guard let connection = connection else {
return
}
connection.stateUpdateHandler = { newState in
switch newState {
case .ready:
print("\(connection) established")
// When the connection is ready, start receiving messages.
self.receiveNextMessage()
// Notify your delegate that the connection is ready.
if let delegate = self.statusDelegate {
delegate.showConnectionStatus(.connectionSuccess("Connection Success"))
}
case .failed(let error):
print("\(connection) failed with \(error)")
// Cancel the connection upon a failure.
connection.cancel()
// Notify your delegate that the connection failed.
if let delegate = self.statusDelegate {
delegate.showConnectionStatus(.connectionFail("Connection Fail"))
}
default:
break
}
}
// Start the connection establishment.
connection.start(queue: .main)
}
}
This is how I receive data when another device sends it.
func receiveNextMessage() {
guard let connection = connection else {
return
}
/// Has to call itself again within the closure because the maximum message is once.
connection.receiveMessage { (content, context, isComplete, error) in
// Extract your message type from the received context.
if let message = context?.protocolMetadata(definition: GameProtocol.definition) as? NWProtocolFramer.Message {
self.delegate?.receivedMessage(content: content, message: message, connection: connection)
}
if error == nil {
// Continue to receive more messages until you receive and error.
self.receiveNextMessage()
}
}
}
Finally, following is how I attempt to reconstruct MWConnection:
func receivedMessage(content: Data?, message: NWProtocolFramer.Message, connection: NWConnection) {
switch(connection.endpoint) {
case .hostPort(let host, let port):
/// first attempt
let endpoint = NWEndpoint.hostPort(host: host, port: port)
let newConnection = PeerConnection(endpoint: endpoint, interface: nil, passcode: passcode, delegate: self)
/// second attempt
let connection = NWConnection(host: host, port: port, using: NWParameters(passcode: passcode))
let newConnection = PeerConnection(connection: connection, delegate: self)
default:
break
}
}
NWConnection is instantiated inside initializer of PeerConnection.

SFSpeechRecognizer online: at which url is sent the request?

I'm developing an iOS application in Swift that uses SFSpeechRecognizer (package: Speech).
This application is developed for an organization that uses VPN and blocks every request from/to the external network.
This is partial code:
let speechRecognizer = SFSpeechRecognizer(locale: Locale.init(identifier: self.userLanguageExt))
let recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
let recognitionTask = self.speechRecognizer?.recognitionTask(with: self.recognitionRequest!,resultHandler: { (result, error) in
if let result = result{
...
}
else if error == nil {
...
}
})
I need to know from/to which url is received/sent the RecognizerRequest so I can comunicate it to network team of the organization and they will open the connection to those url. On docs I couldn't find a lot.
Answer
17.250.13.5 (if you check the ip lookup on https://www.iplocation.net/ you find that is an Apple domain)
How
I've done tcpdump on my device following this documentation and catched the packets traffic: https://developer.apple.com/documentation/network/recording_a_packet_trace

How to detect if an iOS user is connected to cellular network versus wi-fi?

I need to differentiate between the iPhone/iPad user being connected to cellular versus wifi. Under the SCNetworkReachabilityFlag .isWWAN, Apple says:
The absence of this flag does not necessarily mean that a connection will never pass over a cellular network. If you need to robustly prevent cellular networking, read Avoiding Common Networking Mistakes in Networking Overview.
What this means is, if this flag is enabled, the user is most likely connecting via a cellular network, but it's not guaranteed. I read Avoiding Common Networking Mistakes but it is not helpful.
How can I be 100% sure that the user is on a cellular network (or not)?
My code looks like this:
let reachability = SCNetworkReachabilityCreateWithName(nil, "localhost")
var flags = SCNetworkReachabilityFlags()
if let reachability = reachability {
SCNetworkReachabilityGetFlags(reachability, &flags)
}
let isConnectedToCellular = flags.contains(.isWWAN)
EDIT:
If you are using this code, be sure to call it on a background thread and not the main thread.
You can use Reachability.swift Either you use this, or get some idea on how some certain flow is made and works.
It has a Connection enum that goes like this:
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"
}
}
}
And NetworkStatus:
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"
}
}
}
And from there you can do the following:
Check if the device is connected to the mobile data / cellular Or Wifi.
Observe reachability / internet connection.
hope this help
func getWiFiName() -> String? {
var ssid: String?
if let interfaces = CNCopySupportedInterfaces() as NSArray? {
for interface in interfaces {
if let interfaceInfo = CNCopyCurrentNetworkInfo(interface as! CFString) as NSDictionary? {
ssid = interfaceInfo[kCNNetworkInfoKeySSID as String] as? String
break
}
}
}
return ssid
}
if this return nil then you'r connected over cellular if device connected to a wifi then it will return the wifi name (SSID)
don't forget to turn on network extensions and access wifi information on project capabilities
THIS DOESNT WORK ON SIMULATOR (IT SHOULD BE REAL DEVICE)!!!!
and add this two
import NetworkExtension
import SystemConfiguration.CaptiveNetwork

XMPP Server not connected with e-Jabberd - Always return "False"

i am working with XMPP framework and try to connect with server. I have tested with Adium. It connects fine but not working with code.
It always return Failed. can anyone guide me plz
func connect()
{
let stream = XMPPStream()
stream?.addDelegate(self, delegateQueue: DispatchQueue.main)
stream?.hostName = "server.com"
stream?.hostPort = 5222
do
{
try stream?.connect(withTimeout: XMPPStreamTimeoutNone)
}
catch
{
if stream?.isConnected()==true
{
print("Success");
}
else
{
print("Failed");
}
}
}
XMPPStream.connect is asynchronous method and returns immediately. Of course, it needs some time to connect, that is why you shouldn't check isConnected just after connect.
You need to implement XMPPStreamDelegate protocol and when stream will be connected it will "fire" xmppStreamDidConnect: "event", and this is the place where you can continue your connection logic

Unit Testing iOS App which used Alamofire for network request

I am new to iOS Development and I am building an app which uses Alamofire for HTTP request. I need to write Unit test for few things like login and need help with it. I did some research about Stub, Mocks and also read about few frameworks like Nocilla and OHTTPStubs but I am unable to get started. I have a login controller which gets login information like - username, password from storyboard and on login button action I call a server utility method. I have a server utility class which implements the method for making network request.
#IBAction func logIn(sender: AnyObject?) {
server.loginWith(username, password: password, server:url) { (user, error) in
dispatch_async(dispatch_get_main_queue()) {
if let err = error {
self.handleError(err)
return
}
self.performSegueWithIdentifier("unwind", sender: self)
}
}
}
This is server utility class
class Server {
func loginWith(username:String, password:String, server:String, callback:CompleteHandler) {
Alamofire.request(.GET, server + "/login", headers:defaultHeaders).validate().responseJSON {response in
var err:NSError?
var user:Object?
defer {
dispatch_group_leave(self.dispGrp)
callback(user:user, error: err)
}
switch response.result {
case .Success():
//gives me user data
case .Failure(let error):
// gives me error
}
}
How do I Unit test the following code provided I do not wish to make a network call. Please help me as I am stuck since long.
Thank you.
use OHHTTPStubs
Its allow you to :
test your apps with fake network data (stubbed from file) and simulate slow networks, to check your application behavior in bad network conditions
write unit tests that use fake network data from your fixtures.
And support swift 3.0 too

Resources