iOS isActiveNetworkMetered api - ios

I'm developing an iOS app which needs to know whether the cellular network is metered to save the cost, do we have an api in iOS to get the information?
In android the api is http://developer.android.com/reference/android/net/ConnectivityManager.html#isActiveNetworkMetered().
Returns if the currently active data network is metered. A network is classified as metered when the user is sensitive to heavy data usage on that connection due to monetary costs, data limitations or battery/performance issues. You should check this before doing large data transfers, and warn the user or delay the operation until another network is available.
Thanks,
James

There is no check exactly to check like network is metered or not but you can check whether the network connection is via cellular or wifi.
You can use the Reachability class provide by apple here
Then implement the following to find whether you have connected on cellular
- (BOOL)networkCheckForCellular
{
Reachability *wifiReach = [Reachability reachabilityForInternetConnection];
NetworkStatus netStatus = [wifiReach currentReachabilityStatus];
switch (netStatus)
{
case NotReachable:
{
NSLog(#"%#",#"NETWORKCHECK: Not Connected");
return false;
break;
}
case ReachableViaWiFi:
{
NSLog(#"%#",#"NETWORKCHECK: Connected Via WiFi");
return false;
break;
}
case ReachableViaWWAN:
{
NSLog(#"%#",#"NETWORKCHECK: Connected Via WWAN");
return true;
break;
}
}
return false;
}

Related

How do I detect change in internet connection on iOS, delegate style?

I need a function to run only when the system detects there is no internet connection, then another function to run when the system detects an internet connection.
I'm thinking of something like this:
func onInternetConnection() {
//Enable actions
}
func onInternetDisconnection() {
//Disable actions, alert user
}
I will also need a way to detect when the system is reconnecting, so I can let the user know it's reconnecting, like in Facebook's Messenger.
How can I do this?
I'm using Moya/Alamofire for my network layer.
This works in case of Alamofire
import Alamofire
// In your view did load or in app delegate do like this
let reachabilityManager = NetworkReachabilityManager()
reachabilityManager.listener = { status in
switch status {
case .notReachable:
print("The network is not reachable")
self.onInternetDisconnection()
case .unknown :
print("It is unknown whether the network is reachable")
self.onInternetDisconnection() // not sure what to do for this case
case .reachable(.ethernetOrWiFi):
print("The network is reachable over the WiFi connection")
self.onInternetConnection()
case .reachable(.wwan):
print("The network is reachable over the WWAN connection")
self.onInternetConnection()
}
}
Alamofire and Rechability are library and that have some features to check internet connection. You can use one from that.

How to detect internet connection when connected to wifi but no intenernet: iOS

I just want to know how to detect internet connectivity in iOS when device is connected to wifi but no intenet connection in modem.
I have used apple's and AFNetworking's reachability but they only check for connectivity and returns connected flag even there is no working internet in modem.
I found the solution by hitting host via Reachability:-
Might be helpful for someone.
-(BOOL)isCheckConnection {
Reachability *rc = [Reachability reachabilityWithHostName:#"www.google.com"];
NetworkStatus internetStatus = [rc currentReachabilityStatus];
if(internetStatus==0)
{
//#"NoAccess";
return NO;
}
else if(internetStatus==1)
{
//#"ReachableViaWiFi";
return YES;
} else if(internetStatus==2)
{
//#"ReachableViaWWAN";
return YES;
}
else
{
//#"Reachable";
return YES;
}
}
In order to be sure that your device is really connected to internet, at least you have to try a ping to a up&running at anytime server (like stackoverflow.com o google.com).
Of course, as suggested by #jonrsharpe in question's comments, if this check is necessary in order to understand if app can reach the web server, then a ping or something like that to your web server is also necessary.
But a ping to a surely working web server (like google) will give you the answer it your device is connected to internet (so your modem can reach internet), that way if your web server is not responding you can accordingly show a warning alert in your app to inform user that currently your server is unreachable.
Going to code, you can try to check connection status with Reachability library like below
Reachability *reachability = [Reachability reachabilityWithHostName:#"stackoverflow.com"];
NetworkStatus networkStatus = [reachability currentReachabilityStatus];
and then check networkStatus variable: if 0 you don't have access to internet, otherwise YES, so
if(networkStatus==0) {
// no access to internet
} else {
// you have access to internet
}

Observe WiFi / 3G changes

Is it possible to observe when the user switch between WiFi and cellular data (3G/4G)?
Maybe something in Reachability, but I don't know what.
The easiest way I think is import CoreTelephony and observe CTRadioAccessTechnologyDidChangeNotification and then switch over that like this:
let networkInfo = CTTelephonyNetworkInfo()
let radio = networkInfo.currentRadioAccessTechnology
guard let currentRadio = radio else {
print("No radio info available")
return
}
switch currentRadio {
case CTRadioAccessTechnologyLTE,
CTRadioAccessTechnologyHSDPA: //3.5G "T-Mobile 4G"
print("This is 4G / LTE")
case CTRadioAccessTechnologyeHRPD, //3.5G "Verizon 3G"
CTRadioAccessTechnologyHSUPA,
CTRadioAccessTechnologyWCDMA,
CTRadioAccessTechnologyCDMAEVDORev0,
CTRadioAccessTechnologyCDMAEVDORevA,
CTRadioAccessTechnologyCDMAEVDORevB:
print("This is 3G")
case CTRadioAccessTechnologyGPRS,
CTRadioAccessTechnologyCDMA1x
CTRadioAccessTechnologyEdge:
print("This is 2G")
default:
print("Unknown cellular network type")
}
If you listen for that notification while also using standard Reachability, you can use this switch to get cell network type. You will need currentReachabilityStatus to independently check for a WiFi connection. As far as I am aware, in Swift you need to set up a bridging header to use Apple's Reachability class but there are Swift implementations available as well on github.
Yes Reachability provide you with type of network connected. It gives 3 different status - Not Connected to internet, Connected to Wifi, Connected to Mobile Data.
NetworkStatus status = [reachability currentReachabilityStatus];
if(status == NotReachable)
{
//No Connectivity to Internet
}
else if (status == ReachableViaWiFi)
{
//Connected via WiFi
}
else if (status == ReachableViaWWAN)
{
//Connected via Mobile Data
}

Mac Low Energy...Developers license necessary to test?

So, I am writing an app for my mac to operate as a central and connect to my iPhone as a peripheral. My iPhone is ready to receive connections and I'm working on the Mac app. When I wrote the iPhone app I found that the simulator in Xcode would not simulate the low-energy functionality and so I purchased an iOS developers license to deploy the app to my phone and test it, which solved my problem.
Now, with the mac app, I think I may be having the same problem...with one difference.
- (BOOL) isLECapableHardware
{
NSString * state = nil;
switch ([manager state])
{
case CBCentralManagerStateUnsupported:
state = #"The platform/hardware doesn't support Bluetooth Low Energy.";
NSLog(#"Central manager state: %#", state);
break;
case CBCentralManagerStateUnauthorized:
state = #"The app is not authorized to use Bluetooth Low Energy.";
NSLog(#"Central manager state: %#", state);
break;
case CBCentralManagerStatePoweredOff:
state = #"Bluetooth is currently powered off.";
NSLog(#"Central manager state: %#", state);
break;
case CBCentralManagerStatePoweredOn:
return TRUE;
case CBCentralManagerStateUnknown:
default:
state = #"Bluetooth is currently powered off.";
NSLog(#"Central manager state: %#", state);
return FALSE;
}
NSLog(#"Central manager state: %#", state);
[_textField setStringValue:state];
return false;
}
When this is called, it always falls all the way through to the default case. With the iPhone app I was falling into state unsupported while trying to test it with the simulator. Does this just mean that I need to buy a mac developers license in addition to the iOS one? Or could there be some other issue?

iOS: reachabilityWithHostname YES although it should be NO

I tested different frameworks, e.g.
https://github.com/tonymillion/Reachability
https://github.com/VerticodeLabs/VCLReachability
https://github.com/kstenerud/KSReachability
and I would like to know if a host is reachable. On my iPhone, I set my iMac as proxy (Charles) and block or don't block the connections, but the reachability is always YES. Only if I set a non-existing host, it returns NO. But if the host exists but I block the connection to it, I always get isReachable. Isn't there a way to check if the host is really reachable?
If I try with KSReachability, I'm doing the following:
self.reachability = [KSReachability reachabilityToHost:#"www.stackoverflow.com"];
self.reachability.notificationName = kDefaultNetworkReachabilityChangedNotification;
self.reachability.onReachabilityChanged = ^(KSReachability *reachability) {
NSLog(#"isReachable: %i", reachability.reachable);
};
I always get isReachable: 1 there with the following configuration:
connected to Wifi
configured my iMac as HTTP-Proxy
blocking www.stackoverflow.com in my Charles Proxy
When I try to reach www.stackoverflow.com in Safari, the page can't be opened (as expected). I would expect the reachability to be false (isReachable: 0) in this case.
EDIT
So the most important question for me is - how to achieve the behavior I'm expecting? I.e. that the app continuously checks if the given host is really reachable?
The code statement:
self.reachability = [KSReachability reachabilityToHost:#"www.stackoverflow.com"];
actually calls below method:
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL,
[hostName UTF8String]);
SCNetworkReachability reference says:
The SCNetworkReachability programming interface allows an application
to determine the status of a system's current network configuration
and the reachability of a target host. A remote host is considered
reachable when a data packet, sent by an application into the network
stack, can leave the local device. Reachability does not guarantee
that the data packet will actually be received by the host.
The explanation clears that iOS system doesn't send any request to outside world to check the reachability. It just tells that data packet can leave the device or not. If system were to send the request it automatically means that it is connected to network.
You can verify this by mentioning a valid host like "www.stackoverflow.com" and check in charles (first unblock it) that no request is sent.You can also check with other valid host names like "www.abcdefgh.com" (verify this by running it in Safari and see in charles) it also gives you the reachability but charles shows no request.Also if you put http:// before any valid host, something like "http://www.stackoverflow.com" it will also fails reachability. So it is clear that it is not an outgoing http request. If system has to send a request outside then what's the point of providing the class? A developer could have created a network connection and try to connect to a host and see if it passes or fails.
However it is interesting that if an invalid host like "www.hjjkhkhk.com" is provided iOS system gives reachability as false. Now the question is how iOS system finds a valid or invalid host without sending any query to outside world? May be it is periodically caching a list of DNS ranges??? Highly improbable to me.
In your AppDelegate add this method:
#import "Reachability.h"
-(NSString *)checkNetworkConnectivity
{
NSString *networkValue;
Reachability *rc = [Reachability reachabilityWithHostName:#"www.stackoverflow.com"];
NetworkStatus internetStatus = [rc currentReachabilityStatus];
if(internetStatus==0)
{
networkValue = #"NoAccess";
}
else if(internetStatus==1)
{
networkValue = #"ReachableViaWiFi";
} else if(internetStatus==2)
{
networkValue = #"ReachableViaWWAN";
}
else
{
networkValue = #"Reachable";
}
return networkValue;
}
Checking if the host is reachable
NSString *netStr = [appDelegate checkNetworkConnectivity];
if([netStr isEqualToString:#"NoAccess"])
{
[appDelegate callNoNetworkAlert];
}
Firstly, unless we see some code, we cannot make sure what you're doing, you're doing the right way. However I will assume you are doing it correctly.
Secondly, you should test what FreeNickname has suggested in his comment. Maybe it's not actually unreachable, and the reachability is acting correctly, when you expect a different response.
Last, but very important, from the Reachability docs :
Note: Reachability cannot tell your application if you can connect to a particular host, only that an interface is available that might allow a connection, and whether that interface is the WWAN.
What it means is that, even though your server might not be returning any responses, Reachability does NOT check that. It only checks if your server is available , such that a packet can be sent. What it does with that packet is of no concern to Reachability. If Reachability is able to transmit the entire packet, it assumes your host is reachable. It will return unreachable iff your server is down, disconnected, or does not exist.
I would like to add that To listen the Network changes at Runtime, you need to listen to the Notifications that tell you that a Network state has been changed.
This is how you can do this :
Implement a listener in AppDelegate file.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reachabilityChanged:)
name:kReachabilityChangedNotification object:nil];
Now reachabilityChanged will be called when there is a change in Network status (perhaps connectivity of internet connection or it's disconnection). You can do appropriate handling in reachabilityChanged event
like:
- (void) reachabilityChanged:(NSNotification *)note
{
Reachability* reachability = [note object];
if (reachability == self.hostReachability)
{
isHostReachable = YES; //A flag to keep track of connectivity
}
if (reachability == self.internetReachability)
{
isInternetAvailable = YES;
}
if (reachability == self.wifiReachability)
{
isWifiAvailable = YES;
}
//If all are true that means we have host and Internet available
if (isHostReachable && isInternetAvailable && isWifiAvailable)
{
isInternetAvailable = true;
}
}
Hope this will help you.
AFNetworking
A delightful iOS and OS X networking framework
http://afnetworking.com
Network Reachability Manager
AFNetworkReachabilityManager monitors the reachability of domains, and addresses for both WWAN and WiFi network interfaces.
Shared Network Reachability
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status)
{
NSLog(#"Reachability: %#", AFStringFromNetworkReachabilityStatus(status));
}];
HTTP Manager Reachability
NSURL *baseURL = [NSURL URLWithString:#"http://example.com/"];
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:baseURL];
NSOperationQueue *operationQueue = manager.operationQueue;
[manager.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status)
{
switch (status)
{
case AFNetworkReachabilityStatusReachableViaWWAN:
case AFNetworkReachabilityStatusReachableViaWiFi:
[operationQueue setSuspended:NO];
break;
case AFNetworkReachabilityStatusNotReachable:
default:
[operationQueue setSuspended:YES];
break;
}
}];

Resources