How to check celluar/wifi internet strength in Objective c? - objective-c

I am developing an iot app ,I want to show a pop-up in case wifi/celluar internet is slow .
How to implement the slow networks alert in objective c ?

I think you could try the Reachbility application to help you out checking if you have internet or not. As for the server itself, you can use the NSUrlConnection Delegate methods to check if there was a problem with your request (by seeing the kind of HTTP code that comes)
Reachability *reachability = [Reachability reachabilityForInternetConnection];
NetworkStatus internetStatus = [reachability currentReachabilityStatus];
if(internetStatus == NotReachable) {
UIAlertView *errorView;
errorView = [[UIAlertView alloc]
initWithTitle: NSLocalizedString(#"Network error", #"Network error")
message: NSLocalizedString(#"No internet connection found, this application requires an internet connection to gather the data required.", #"Network error")
delegate: self
cancelButtonTitle: NSLocalizedString(#"Close", #"Network error") otherButtonTitles: nil];
[errorView show];
[errorView autorelease];
}

Full example to check internet connection.
please download reachability class .h and .m from here
Follow these steps
viewcontroller.h
#class Reachability;
#interface DashboardVC : UIViewController
{
Reachability* internetReachable;
Reachability* hostReachable;
}
-(void) checkNetworkStatus:(NSNotification *)notice;
viewcontroller.m
-(void) viewWillAppear:(BOOL)animated
{
// check for internet connection
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(checkNetworkStatus:) name:kReachabilityChangedNotification object:nil];
internetReachable = [Reachability reachabilityForInternetConnection];
[internetReachable startNotifier];
// check if a pathway to a random host exists
hostReachable = [Reachability reachabilityWithHostName:#"www.apple.com"];
[hostReachable startNotifier];
// now patiently wait for the notification
}
-(void) checkNetworkStatus:(NSNotification *)notice
{
// called after network status changes
NetworkStatus internetStatus = [internetReachable currentReachabilityStatus];
switch (internetStatus)
{
case NotReachable:
{
NSLog(#"The internet is down.");
break;
}
case ReachableViaWiFi:
{
NSLog(#"The internet is working via WIFI.");//your device is connected with wifi
break;
}
case ReachableViaWWAN:
{
NSLog(#"The internet is working via WWAN.");//your internet is connected with mobile data
break;
}
}
}

You can send a request to your server and given that it's about 5-10 KB of data you expect to be returned, then create a timer callback that is scheduled for say 20 seconds.
If you don't get a response within 20 seconds, then let's consider that a slow connection.
// make POST request to server, the POST request should have a callback method assigned
[self testSpeed];
// schedule a method to be called after 20 seconds
myTimer = [NSTimer scheduledTimerWithInterval:20.0 selector:#selector(stopSpeedTest) .... ];
// your POST request callback method
-(void)speedTestCallback
{
[myTimer invalidate];
myTimer = nil;
[self alertGoodSpeed];
}
// your stopSpeedTest method to identify app didn't receive response within 20 seconds
-(void)stopSpeedTest
{
[self alertTooSlow];
}

Related

iOS 7 - Proper stop of stop and 'clear' dispatch_queue_t

I am having a long method which download a set of data and files from server and I have a Reachability class to monitor the network connection. What I want to do is if network disconnected, stop the queue and 'clear' it. When user click a button to retry, it start everything from beginning. So, what is the proper steps?
Is it
in .h file
#property (nonatomic) dispatch_queue_t background_q;
#property (nonatomic) Reachability *reachMonitor;
in .m file
- (void)downloadBigDataAndFiles {
self.reachMonitor = [Reachability reachabilityForInternetConnection];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(reachabilityValueChanged:) name:kReachabilityChangedNotification object:nil];
[reachMonitor startNotifier];
self.background_q = dispatch_queue_create("backgroundMasterQueue", NULL);
dispatch_async(background_q, ^{
// Do whatever
});
}
When disconnected
- (void)reachabilityValueChanged:(NSNotification *)notification {
if ([self.reachMonitor currentReachabilityStatus] == NotReachable) {
if (self.background_q) { // <- is it necessary?
dispatch_suspend(self.background_q);
self.background_q = nil; // <- is it necessary?
}
} else if (([self.reachMonitor currentReachabilityStatus] == ReachableViaWWAN) || ([self.reachMonitor currentReachabilityStatus] == ReachableViaWiFi)) {
// show up retry button...
}
}

MultipeerConnectivity Session management

I am really stuck at the moment trying to get the grasp of invites in the MultipeerConnectivityFramework.
Right now I have an ipad App acting as the Advertiser and an iphone App acting as Browser.
I have implemented a sharedService for the MultipeerFramework and did the following:
Advertiser
#implementation MultipeerConnectivityService {
MCNearbyServiceAdvertiser *_advertiser;
MCSession *_session;
MCNearbyServiceBrowser *_browser;
}
- (void)automaticAdvertiseWithName:(NSString *)name {
MCPeerID *peerID = [[MCPeerID alloc] initWithDisplayName:name];
_session = [[MCSession alloc] initWithPeer:peerID];
_session.delegate = self;
_advertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:peerID discoveryInfo:nil serviceType:kServiceType];
_advertiser.delegate = self;
[_advertiser startAdvertisingPeer];
}
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void (^)(BOOL, MCSession *))invitationHandler {
invitationHandler([#YES boolValue], _session);
NSLog(#"Invitation accepted");
}
Browser
- (void)automaticBrowsingWithName:(NSString *)name {
MCPeerID *peerID = [[MCPeerID alloc] initWithDisplayName:name];
_browser = [[MCNearbyServiceBrowser alloc] initWithPeer:peerID serviceType:kServiceType];
_browser.delegate = self;
[_browser startBrowsingForPeers];
}
- (void)browser:(MCNearbyServiceBrowser *)browser didNotStartBrowsingForPeers:(NSError *)error {
if ([_delegate respondsToSelector:#selector(browser:didNotStartBrowsingForPeers:)]) {
[_delegate browserDidNotStartBrowsingForPeers];
}
}
- (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info {
[browser invitePeer:peerID toSession:[self getMCSession] withContext:nil timeout:10];
if ([_delegate respondsToSelector:#selector(browser:foundPeer:)]) {
[_delegate browser:browser foundPeer:peerID];
}
}
- (void)browser:(MCNearbyServiceBrowser *)browser lostPeer:(MCPeerID *)peerID {
if ([_delegate respondsToSelector:#selector(browserLostPeer:)]) {
[_delegate browserLostPeer:peerID];
}
}
- (MCSession *) getMCSession {
return _session;
}
But then I am getting as feedback in the console:
-[MCNearbyServiceBrowser invitePeer:toSession:withContext:timeout:] Bad argument session=nil
When I check for the found Advertisers, everything is OK. My advertiser ipad is being found. But how can I manage the invite?
So I don't get it right now... When I send an invitation by the browser, what session do I have to use? On the iPad I set up the session like you can see in the "automaticAdvertiseWithName" method. but on the iphone I don't do this when calling "automaticBrowsingWithName"... Is that the problem? And don't they have to be the same session to successfully connect them? And how can I successfully invite my advertiser ipad to the browser?
I am confused by the notion of creating a new session when one has already been created by the advertiser.
I am actually not sure, if the delegate didReceiveInvitation is adding the peer to the connectedPeers at all.
- (void)automaticAdvertiseWithName:(NSString *)name {
MCPeerID *peerID = [[MCPeerID alloc] initWithDisplayName:name];
self.session = [[MCSession alloc] initWithPeer:peerID];
self.session.delegate = self;
_advertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:peerID discoveryInfo:nil serviceType:kServiceType];
_advertiser.delegate = self;
[_advertiser startAdvertisingPeer];
}
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void (^)(BOOL, MCSession *))invitationHandler {
BOOL accept = YES;
invitationHandler(accept, self.session);
NSLog(#"Invitation accepted: %#", self.session);
}
And when I call the property "connectedPeers" on my session, there are no connected peers at all, even though the delegate found one. Did I make a mistake there?
Your problem is that your session is null at the time you call invitePeer:toSession:withContext:timeout...Anyway you have two options to fix this.
You have two options :
Option 1
- move the peerID creation, session creation and session delegate assignment in a place where its executed at all time. For example in the init code for MultipeerConnectivityService class of if its a UIViewController in the viewDidLoad.
Option 2
- add the following snippet before you call "invitePeer:toSession:withContext:timeout:"
if (!_session) {
MCPeerID *peerID = [[MCPeerID alloc] initWithDisplayName:#"Browser"]; // you can customize the name here
_session = [[MCSession alloc] initWithPeer:peerID];
_session.delegate = self;
}
Hope this helps ...good luck!

How to interrupt AVPlayer for incoming call manually

I've used this method How do I get my AVPlayer to play while app is in background? to have an AVPlayer play in the background so the user can listen while browsing safari etc. Only problem is now AVPlayer continues to play when there is an incoming call and stays playing during the call. Is there a way to catch the incoming call and end call events so AVPlayer can be stopped and started manually?
Through coreTelephony framework we have to find or detect the incoming call. From there you have to initiate your local notification to stop your AVPlayer.
after importing do like this
CTCallCenter * _callCenter = [[CTCallCenter alloc] init];
_callCenter.callEventHandler = ^(CTCall* call)
{
if ([call.callState isEqualToString:CTCallStateDisconnected])
{
NSLog(#"Call has been disconnected");
}
else if([call.callState isEqualToString:CTCallStateDialing])
{
NSLog(#"Call start");
}
else if ([call.callState isEqualToString:CTCallStateConnected])
{
NSLog(#"Call has just been connected");
}
else if([call.callState isEqualToString:CTCallStateIncoming])
{
NSLog(#"Call is incoming");
// You have to initiate/post your local notification through NSNotification center like this
[[NSNotificationCenter defaultCenter] postNotificationName:#"stopAVPlayer" object:nil];
} else
{
NSLog(#"None of the conditions");
}
};
Refer this :https://developer.apple.com/library/ios/navigation/#section=Frameworks&topic=CoreTelephony
You could use the CallKit for getting phone call event now. (iOS 10.0+)
This is good for me.
#import <CallKit/CallKit.h>
#interface ViewController ()<CXCallObserverDelegate> {
CXCallObserver *_center;
}
-(void)viewDidLoad
_center = [[CXCallObserver alloc] init];
dispatch_queue_t queue = dispatch_queue_create("THIS_IS_A_CALL",NULL);
[_center setDelegate:self queue:queue];
Delegate
- (void)callObserver:(CXCallObserver *)callObserver callChanged:(CXCall *)call {
NSString *tag = #"callObserver";
NSString *content = #"";
if (call.isOutgoing) {
content = #"call.isOutgoing";
}
if (call.hasEnded) {
content = #"call.hasEnded";
}
if (call.hasConnected) {
content = #"call.hasConnected";
}
if (call.isOnHold) {
content = #"call.isOnHold";
}
NSLog(#"%# - %#", tag, content);
}
More detail: https://developer.apple.com/documentation/callkit

How to define a reachability timeout on ios

I use the Reachability class to know if I have an internet connection available. The problem is when wifi is available but not internet, the - (NetworkStatus) currentReachabilityStatus method take too much time.
my code:
Reachability* reachability = [Reachability reachabilityWithHostName:#"www.apple.com"];
NetworkStatus remoteHostStatus = [reachability currentReachabilityStatus];
The application "freeze" temporarily on the second line. How to define the maximum time for this waiting ?
I don't think so. But more importantly, I don't think you'd want to if you could (you may get false positives). Let Reachability run it's course.
If you look at the Reachability demo project, the notion isn't to invoke reachabilityWithHostName and check currentReachabilityStatus when you need the Internet. You invoke currentReachabilityStatus at during your app delegate's didFinishLaunchingWithOptions, set up a notification, and Reachability will tell you when the Internet connectivity has changed. I find that subsequent checks to currentReachabilityStatus are plenty fast (regardless of connectivity) when I (a) setup reachability at startup; but (b) check for connectivity in a just-in-time manner.
And if you absolutely need to start your processing immediately, then the question is whether you can push that into the background (e.g. dispatch_async()). E.g., my app retrieves updates from the server, but because that's happening in the background, neither me nor my user are aware of any delays.
I was having issues with the same thing but I found a way to specify a timeout. I replaced this method inside the Reachability Class from Apple.
- (NetworkStatus)currentReachabilityStatus
{
NSAssert(_reachabilityRef != NULL, #"currentNetworkStatus called with NULL SCNetworkReachabilityRef");
//NetworkStatus returnValue = NotReachable;
__block SCNetworkReachabilityFlags flags;
__block BOOL timeOut = NO;
double delayInSeconds = 5.0;
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(delay, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void){
timeOut = YES;
});
__block NetworkStatus returnValue = NotReachable;
__block BOOL returned = NO;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
{
if (_alwaysReturnLocalWiFiStatus)
{
returnValue = [self localWiFiStatusForFlags:flags];
}
else
{
returnValue = [self networkStatusForFlags:flags];
}
}
returned = YES;
});
while (!returned && !timeOut) {
if (!timeOut && !returned){
[NSThread sleepForTimeInterval:.02];
} else {
break;
}
}
return returnValue;
}

Connect to devices on local network using cocoa

I have been trying to develop an app for my ipad which i can use to connect to my local network devices in order to get files and so on without any progress.
What i want to do is to first detect the devices on the network and then select which i want to browse files from by connecting to it.
What i got so far is
#import "BrowseForNetworkDevices.h"
#implementation BrowseForNetworkDevices
- (id)init
{
self = [super init];
if (self)
{
services = [[NSMutableArray alloc] init];
serviceBrowser = [[NSNetServiceBrowser alloc] init];
[serviceBrowser setDelegate: delegateObject];
searching = NO;
}
return self;
}
- (void)dealloc
{
[services release];
[serviceBrowser release];
[super dealloc];
}
// Sent when browsing begins
- (void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)browser
{
searching = YES;
[serviceBrowser searchForServicesOfType:#" " inDomain:#"local."];
[self updateUI];
}
// Sent when browsing stops
- (void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)browser
{
searching = NO;
[self updateUI];
}
// Sent if browsing fails
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser
didNotSearch:(NSDictionary *)errorDict
{
searching = NO;
[self handleError:[errorDict objectForKey:NSNetServicesErrorCode]];
}
// Sent when a service appears
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser
didFindService:(NSNetService *)aNetService
moreComing:(BOOL)moreComing
{
//[services addObject:aNetService];
if (![services containsObject:aNetService]) {
[self willChangeValueForKey:#"services"];
[services addObject:aNetService];
[self didChangeValueForKey:#"service"];
}
if(!moreComing)
{
[self updateUI];
}
}
// Sent when a service disappears
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser
didRemoveService:(NSNetService *)aNetService
moreComing:(BOOL)moreComing
{
//[services removeObject:aNetService];
if ([services containsObject:aNetService]) {
[self willChangeValueForKey:#"service"];
[services removeObject:aNetService];
[self didChangeValueForKey:#"service"];
}
if(!moreComing)
{
[self updateUI];
}
}
// Error handling code
- (void)handleError:(NSNumber *)error
{
NSLog(#"An error occurred. Error code = %d", [error intValue]);
// Handle error here
}
// UI update code
- (void)updateUI
{
if(searching)
{
// Update the user interface to indicate searching
for(Class obj in services){
NSLog(#"service found %#", obj);
}
// Also update any UI that lists available services
}
else
{
// Update the user interface to indicate not searching
}
}
#end
Any good tutorials on how to perform such task?
Thanks in advance for all the help
You will need both the network devices and your iPad to be speaking the same protocol. You will need to pick an appropriate protocol. It sounds like what you want to do is file transfer - there are many protocols that can handle this that are implemented in libraries for iOS:
- WebDAV
- HTTP
- FTP
- SFTP
- AFP
- SAMBA
In order for the devices to detect one another you will need to use something like Apple's Bonjour