I'm using this library: https://github.com/tonymillion/Reachability
The problem is sometimes when I check the following expression:
[[[ReachabilityManager sharedManager] reachability] isReachable]; returns NO when should be YES. I know there is internet because i invoke Rest services in the meantime.
Plus, if I execute [Reachability reachabilityWithHostname:#"www.google.com"]; and ask for the method isReachable then works as I expected.
My tests are simple, try on emulator and then plug and unplug the ethernet cable.
#implementation ReachabilityManager
#pragma mark -
#pragma mark Default Manager
+ (ReachabilityManager *)sharedManager {
static ReachabilityManager *_sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedManager = [[self alloc] init];
});
return _sharedManager;
}
#pragma mark -
#pragma mark Memory Management
- (void)dealloc {
// Stop Notifier
if (_reachability) {
[_reachability stopNotifier];
}
}
#pragma mark -
#pragma mark Class Methods
+ (BOOL)isReachable {
return [[[ReachabilityManager sharedManager] reachability] isReachable];
}
+ (BOOL)isUnreachable {
return ![[[ReachabilityManager sharedManager] reachability] isReachable];
}
+ (BOOL)isReachableViaWWAN {
return [[[ReachabilityManager sharedManager] reachability] isReachableViaWWAN];
}
+ (BOOL)isReachableViaWiFi {
return [[[ReachabilityManager sharedManager] reachability] isReachableViaWiFi];
}
#pragma mark -
#pragma mark Private Initialization
- (id)init {
self = [super init];
if (self) {
// Initialize Reachability
self.reachability = [Reachability reachabilityWithHostname:#"www.google.com"];
// Start Monitoring
[self.reachability startNotifier];
}
return self;
}
#end
#property (nonatomic) Reachability *hostReachability;
#property (nonatomic) Reachability *internetReachability;
#property (nonatomic) Reachability *wifiReachability;
Declare one bool,
BOOL _isInternetAvaliable;
Init your reachability,
-(void) initializeReachability {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil];
//hostReachability
NSString *remoteHostName = #"www.apple.com";
self.hostReachability = [Reachability reachabilityWithHostName:remoteHostName];
[self.hostReachability startNotifier];
[self updateInterfaceWithReachability:self.hostReachability];
//internetReachability
self.internetReachability = [Reachability reachabilityForInternetConnection];
[self.internetReachability startNotifier];
[self updateInterfaceWithReachability:self.internetReachability];
//wifiReachability
self.wifiReachability = [Reachability reachabilityForLocalWiFi];
[self.wifiReachability startNotifier];
[self updateInterfaceWithReachability:self.wifiReachability];
}
- (void)updateInterfaceWithReachability:(Reachability *)reachability
{
if (reachability == self.hostReachability)
{
[self configurereachability:reachability];
}
if (reachability == self.internetReachability)
{
[self configurereachability:reachability];
}
if (reachability == self.wifiReachability)
{
[self configurereachability:reachability];
}
}
- (void)configurereachability:(Reachability *)reachability
{
NetworkStatus netStatus = [reachability currentReachabilityStatus];
BOOL connectionRequired = [reachability connectionRequired];
switch (netStatus)
{
case NotReachable: {
_isInternetAvaliable = NO;
break;
}
case ReachableViaWWAN: {
_isInternetAvaliable = YES;
break;
}
case ReachableViaWiFi: {
_isInternetAvaliable = YES;
break;
}
}
if (connectionRequired)
{
_isInternetAvaliable = NO;
}
}
-(BOOL) isInternetAvailable {
return _isInternetAvaliable;
}
Now you are ready to call & access internet status,
if([[ReachabilityManager sharedManager] isInternetAvailable]){
//Internet on
}
Finally I found a reliable solution. https://stackoverflow.com/a/14870229/2139691
Related
I want my app to detect the internet connection loss automatically. So im using the following code.
- (void)applicationDidBecomeActive:(UIApplication *)application {
Reachability *networkReachability = [Reachability reachabilityForInternetConnection];
NetworkStatus networkStatus = [networkReachability currentReachabilityStatus];
if (networkStatus == NotReachable) {
[Settings hideSpinner];
//Show no internet connectivity dialog.
} else {
}
}
But the problem is that it is not checking the internet connectivity continually.
it checks only when the app has become active. How can I be able to check for internet connection continually throughout the app life cycle and throw an warning if internet goes off automatically?
Once your application has launched, you can fire a NSTimer to do the same:
- (void)applicationDidBecomeActive:(UIApplication *)application {
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0f
target:self
selector:#selector(checkForConnectivity)
userInfo:nil
repeats:YES];
}
-(void)checkForConnectivity {
Reachability *networkReachability = [Reachability reachabilityForInternetConnection];
NetworkStatus networkStatus = [networkReachability currentReachabilityStatus];
if (networkStatus == NotReachable) {
//No internet connectivity - perform required action
}
else {
//Internet connectivity is valid
}
}
Thanks!
Add obeserver like this in Reachability method.
1) [[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil];
It will call automatically when your app open/in background mode and it call reachabilityChanged.
2) [[NSNotificationCenter defaultCenter] postNotificationName:#"ChangeInternetConnection" object:nil];
ChangeInternetConnection you have to add observer to your ViewController to get status when internet changing it's status.
- (void) checkInternetConnetion {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil];
//NSString *remoteHostName = #"www.apple.com";
self.internetReachability = [Reachability reachabilityForInternetConnection];
[self.internetReachability startNotifier];
[self updateInterfaceWithReachability:self.internetReachability];
}
#pragma mark - Reachability Methods
- (void)updateInterfaceWithReachability:(Reachability *)reachability {
if (reachability == self.internetReachability) {
[self checkStatus:reachability];
}
if (reachability == self.wifiReachability) {
[self checkStatus:reachability];
}
}
-(void)checkStatus :(Reachability *)reachability {
NetworkStatus netStatus = [reachability currentReachabilityStatus];
BOOL connectionRequired = [reachability connectionRequired];
NSString* statusString = #"";
switch (netStatus) {
case NotReachable: {
self.isInternetOn = FALSE;
break;
}
case ReachableViaWWAN: {
self.isInternetOn = TRUE;
break;
}
case ReachableViaWiFi: {
self.isInternetOn = TRUE;
break;
}
}
[[NSNotificationCenter defaultCenter] postNotificationName:#"ChangeInternetConnection" object:nil];
}
- (void) reachabilityChanged:(NSNotification *)note {
Reachability* curReach = [note object];
NSParameterAssert([curReach isKindOfClass:[Reachability class]]);
[self updateInterfaceWithReachability:curReach];
}
Timer is not an efficient way to do this but you can also use timer too.
- (void)applicationDidBecomeActive:(UIApplication *)application
{
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0f
target:self
selector:#selector(handleConnectivity)
userInfo:nil
repeats:YES];
}
-(void)handleConnectivity
{
Reachability *networkReachability = [Reachability reachabilityForInternetConnection];
NetworkStatus networkStatus = [networkReachability currentReachabilityStatus];
if (networkStatus == NotReachable)
{
//No internet connectivity - perform required action
}
else
{
//Internet connectivity is valid
}
}
Best way is to use Reachability code. Check here for apple sample code. That has a lot of convenience methods to check internet availability, Wifi/WAN connectivity check etc..
For example:-
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(networkChanged:) name:kReachabilityChangedNotification object:nil];
reachability = [Reachability reachabilityForInternetConnection];
[reachability startNotifier];
- (void)networkChanged:(NSNotification *)notification
{
NetworkStatus remoteHostStatus = [reachability currentReachabilityStatus];
if(remoteHostStatus == NotReachable) { NSLog(#"not reachable");}
else if (remoteHostStatus == ReachableViaWiFiNetwork) { NSLog(#"wifi"); }
else if (remoteHostStatus == ReachableViaCarrierDataNetwork) { NSLog(#"carrier"); }
}
You can only check this things in background
*audio—The app plays audible content to the user while in the background. (This content includes streaming audio or video content
using AirPlay.)
*location—The app keeps users informed of their location, even while it is running in the background.
*voip—The app provides the ability for the user to make phone calls using an Internet connection.
*newsstand-content—The app is a Newsstand app that downloads and processes magazine or newspaper content in the background.
*external-accessory—The app works with a hardware accessory that needs to deliver updates on a regular schedule through the External
Accessory framework.
*bluetooth-central—The app works with a Bluetooth accessory that needs to deliver updates on a regular schedule through the Core Bluetooth
framework.
*bluetooth-peripheral—The app supports Bluetooth communication in peripheral mode through the Core Bluetooth framework.
Firstly import in your class: #import "Reachability.h"
Then do like following way:
add an observer for reachability change notification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reachabilityChanged:)
name:kReachabilityChangedNotification object:nil];
-(BOOL)reachabilityChanged:(NSNotification*)note
{
BOOL status =YES;
NSLog(#"reachabilityChanged");
Reachability * reach = [note object];
if([reach isReachable])
{
status = YES;
NSLog(#"your network is Available");
}
else
{
status = NO;
//Do something here
}
return status;
}
Add a observer.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reachabilityChanged:)
name:kReachabilityChangedNotification
object:nil];
-(BOOL)reachabilityChanged:(NSNotification*)note
{
BOOL status =YES;
NSLog(#"reachability is changed");
Reachability * reach = [note object];
if([reach isReachable])
{
status = YES;
NSLog(#"NetWork is Available. Please go ahead");
}
else
{
status = NO;
NSLog(#"NetWork is not Available. Please check your connection.");
}
return status;
}
You can make use of Reachability framework from iOS and combine it with NSTimer.
I have an issue with UIAlertView.
In my AppDelegate I check the reachability of the application:
If it is not reachable I call the alert from Utils class.
- (void)reachabilityChanged:(NSNotification *)note
{
Reachability* currentReachabilityObject = [note object];
NSParameterAssert([currentReachabilityObject isKindOfClass:[Reachability class]]);
NetworkStatus status = [currentReachabilityObject currentReachabilityStatus];
if (status == NotReachable)
{
[Utils showAlert:#"NotReachableNetwork") title:#"Error")];
}
}
And if I turn on/turn off Wi-Fi two-three times I get three alerts.
But I want to show only one.
Please tell me how to check is there any alerts on the screen from AppDelegate.
Why don't you keep a reference to the alert?
That way you just have to check if the alert is nil, if it is nil you can create a new alert. In case it isn't nil, it means you already have one showing and there's no need to show another. Easy as pie.
Please try below code and I think it will work for you.
#pragma mark - Internet Reachability Handlers -
- (void) updateInterfaceWithReachability: (Reachability*) curReach
{
NetworkStatus netStatus = [curReach currentReachabilityStatus];
if (_changeReachability)
{
if(netStatus==NotReachable)
{
[Utils showAlert:#"NotReachableNetwork") title:#"Error")];
_isNetAvailable = NO;
_changeReachability = NO;
}
else
{
_isNetAvailable = YES;
_changeReachability = NO;
}
}
}
//Called by Reachability whenever status changes.
- (void) reachabilityChanged: (NSNotification* )note
{
_changeReachability = YES;
Reachability* curReach = [note object];
NSParameterAssert([curReach isKindOfClass: [Reachability class]]);
[self updateInterfaceWithReachability: curReach];
}
-(void)checkallTypesofInternet
{
// For 3G Connection
hostReach = [Reachability reachabilityWithHostName:#"www.apple.com"];
[hostReach startNotifier];
[self updateInterfaceWithReachability: hostReach];
// For Individual Net Connection
internetReach = [Reachability reachabilityForInternetConnection];
[internetReach startNotifier];
[self updateInterfaceWithReachability: internetReach];
// For WiFi
wifiReach = [Reachability reachabilityForLocalWiFi];
[wifiReach startNotifier];
[self updateInterfaceWithReachability: wifiReach];
}
Let me know if you are still facing any issue.
I have a Boolean value to check Reachability with following code.
#property (nonatomic,assign) BOOL isOnline;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reachabilityChanged:)
name:kReachabilityChangedNotification
object:nil];
Reachability * reach = [Reachability reachabilityWithHostname:#"www.google.com"];
reach.reachableBlock = ^(Reachability * reachability)
{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Reachable");
self.isOnline = YES;
});
};
reach.unreachableBlock = ^(Reachability * reachability)
{
dispatch_async(dispatch_get_main_queue(), ^{
self.isOnline = NO;
NSLog(#"Unable");
});
};
[reach startNotifier];
However when i check it with
if(self.isOnline == YES)
{
NSLog(#"YES");
}
else{
NSLog(#"NO");
}
It's only showing NO. I am sure Reachability can reach to the internet and i have connection. However Boolean value is not set to YES.
How can i do it?
It seems that you are using the Reachability by Tony Million so 1st thing i would suggest is to use isReachable function in it.
Secondly, there is an issue with this reachability in iOS7 so to resolve this you have to do the following
In the Function -(BOOL)isReachableWithFlags:(SCNetworkReachabilityFlags)flags in Reachability.m you have to commit one line
#if TARGET_OS_IPHONE
if(flags & kSCNetworkReachabilityFlagsIsWWAN)
{
// We're on 3G.
if(!self.reachableOnWWAN)
{
// We don't want to connect when on 3G.
// Comment this line
//connectionUP = NO;
}
}
#endif
I have an app to play online music. I have added code in that to detect a call and pause the music while on call and as soon as the call ends, it should again start the song. The problem is that it is behaving properly when the phone is connected via Wifi but not doing the same when connected over mobile data. How to make the song play again after call in Mobile Data as well.?
Here is my code:
Reachability.m
NSString *kReachabilityChangedNotification = #"kNetworkReachabilityChangedNotification";
#pragma mark - Supporting functions
#define kShouldPrintReachabilityFlags 1
static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
{
#if kShouldPrintReachabilityFlags
NSLog(#"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
(flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
(flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
(flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-',
(flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-',
(flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
(flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-',
comment
);
#endif
}
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
{
#pragma unused (target, flags)
NSCAssert(info != NULL, #"info was NULL in ReachabilityCallback");
NSCAssert([(__bridge NSObject*) info isKindOfClass: [Reachability class]], #"info was wrong class in ReachabilityCallback");
Reachability* noteObject = (__bridge Reachability *)info;
// Post a notification to notify the client that the network reachability changed.
[[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];
}
#pragma mark - Reachability implementation
#implementation Reachability
{
BOOL localWiFiRef;
SCNetworkReachabilityRef reachabilityRef;
}
+ (instancetype)reachabilityWithHostName:(NSString *)hostName;
{
Reachability* returnValue = NULL;
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
if (reachability != NULL)
{
returnValue= [[self alloc] init];
if (returnValue != NULL)
{
returnValue->reachabilityRef = reachability;
returnValue->localWiFiRef = NO;
}
}
return returnValue;
}
+ (instancetype)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress;
{
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)hostAddress);
Reachability* returnValue = NULL;
if (reachability != NULL)
{
returnValue = [[self alloc] init];
if (returnValue != NULL)
{
returnValue->reachabilityRef = reachability;
returnValue->localWiFiRef = NO;
}
}
return returnValue;
}
+ (instancetype)reachabilityForInternetConnection;
{
struct sockaddr_in zeroAddress;
bzero(&zeroAddress, sizeof(zeroAddress));
zeroAddress.sin_len = sizeof(zeroAddress);
zeroAddress.sin_family = AF_INET;
return [self reachabilityWithAddress:&zeroAddress];
}
+ (instancetype)reachabilityForLocalWiFi;
{
struct sockaddr_in localWifiAddress;
bzero(&localWifiAddress, sizeof(localWifiAddress));
localWifiAddress.sin_len = sizeof(localWifiAddress);
localWifiAddress.sin_family = AF_INET;
// IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0.
localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
Reachability* returnValue = [self reachabilityWithAddress: &localWifiAddress];
if (returnValue != NULL)
{
returnValue->localWiFiRef = YES;
}
return returnValue;
}
#pragma mark - Start and stop notifier
- (BOOL)startNotifier
{
BOOL returnValue = NO;
SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
if (SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context))
{
if (SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
{
returnValue = YES;
}
}
return returnValue;
}
- (void)stopNotifier
{
if (reachabilityRef != NULL)
{
SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}
}
- (void)dealloc
{
[self stopNotifier];
if (reachabilityRef != NULL)
{
CFRelease(reachabilityRef);
}
}
#pragma mark - Network Flag Handling
- (NetworkStatus)localWiFiStatusForFlags:(SCNetworkReachabilityFlags)flags
{
PrintReachabilityFlags(flags, "localWiFiStatusForFlags");
BOOL returnValue = NotReachable;
if ((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect))
{
returnValue = ReachableViaWiFi;
}
return returnValue;
}
- (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags
{
PrintReachabilityFlags(flags, "networkStatusForFlags");
if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
{
// The target host is not reachable.
return NotReachable;
}
BOOL returnValue = NotReachable;
if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
{
/*
If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi...
*/
returnValue = ReachableViaWiFi;
}
if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
{
/*
... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs...
*/
if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
{
/*
... and no [user] intervention is needed...
*/
returnValue = ReachableViaWiFi;
}
}
if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
{
/*
... but WWAN connections are OK if the calling application is using the CFNetwork APIs.
*/
returnValue = ReachableViaWWAN;
}
return returnValue;
}
- (BOOL)connectionRequired
{
NSAssert(reachabilityRef != NULL, #"connectionRequired called with NULL reachabilityRef");
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
{
return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
}
return NO;
}
- (NetworkStatus)currentReachabilityStatus
{
NSAssert(reachabilityRef != NULL, #"currentNetworkStatus called with NULL reachabilityRef");
NetworkStatus returnValue = NotReachable;
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
{
if (localWiFiRef)
{
returnValue = [self localWiFiStatusForFlags:flags];
}
else
{
returnValue = [self networkStatusForFlags:flags];
}
}
return returnValue;
}
#end
ViewController.m
- (void)viewDidLoad
{
toggleIsOn=TRUE;
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:self.viewVolume.bounds] ;
[self.viewVolume addSubview:volumeView];
[volumeView sizeToFit];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(IBAction)playButtonPressed:(id)sender
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:TRUE forKey:#"FirstPlay"];
[defaults setBool:YES forKey:#"alertShown"];
if(toggleIsOn)
{
if(noNetwork)
{
[self showAlert];
}
else
{
toggleIsOn=!toggleIsOn;
player = nil;
NSString *stringurl = #"";
stringurl = #"http://something.pls";
NSURL *url = [NSURL URLWithString:stringurl];
asset = [AVURLAsset URLAssetWithURL:url options:nil];
playerItem = [AVPlayerItem playerItemWithAsset:asset];
player = [AVPlayer playerWithPlayerItem:playerItem];
player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
[playerItem addObserver:self forKeyPath:#"timedMetadata" options:NSKeyValueObservingOptionNew context:nil];
[playerItem addObserver:self forKeyPath:#"status" options:NSKeyValueObservingOptionNew context:nil];
[player play];
isPlaying = TRUE;
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:#selector(audioSessionInterrupted:) name:AVAudioSessionInterruptionNotification object:nil];
[self.toggleButton setImage:[UIImage imageNamed:#"reload.png"] forState:UIControlStateNormal];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}
}
else
{
[self.toggleButton setImage:[UIImage imageNamed:#"playMusic.png"] forState:UIControlStateNormal];
self->player.rate=0.0;
toggleIsOn=!toggleIsOn;
isPlaying = FALSE;
}
}
- (void)audioSessionInterrupted:(NSNotification *)notification
{
NSNumber *interruptionType = [[notification userInfo] objectForKey:AVAudioSessionInterruptionTypeKey];
NSNumber *interruptionOption = [[notification userInfo] objectForKey:AVAudioSessionInterruptionOptionKey];
switch (interruptionType.unsignedIntegerValue) {
case AVAudioSessionInterruptionTypeBegan:{
// [self.toggleButton setImage:[UIImage imageNamed:#"playMusic.png"] forState:UIControlStateNormal];
// • Audio has stopped, already inactive
// • Change state of UI, etc., to reflect non-playing state
} break;
case AVAudioSessionInterruptionTypeEnded:{
// • Make session active
// • Update user interface
// • AVAudioSessionInterruptionOptionShouldResume option
if (interruptionOption.unsignedIntegerValue == AVAudioSessionInterruptionOptionShouldResume) {
// Here you should continue playback.
if(isPlaying)
{
[player play];
}
}
} break;
default:
break;
}
}
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)audioPlayer
{
if(isPlaying)
{
[player pause];
}
}
-(void)audioRecorderEndInterruption:(AVAudioRecorder *)audioPlayer
{
if(isPlaying)
{
[player play];
}
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:TRUE forKey:#"alertShown"];
[[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];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context {
[playerItem removeObserver:self forKeyPath:keyPath];
if ([keyPath isEqualToString:#"status"]) {
AVPlayerItem *pItem = (AVPlayerItem *)object;
if (pItem.status == AVPlayerItemStatusReadyToPlay)
{
metadatas.text = #"";
}
}
if ([keyPath isEqualToString:#"timedMetadata"]) {
for (AVAssetTrack *track in playerItem.tracks) {
for (AVPlayerItemTrack *item in player.currentItem.tracks) {
if ([item.assetTrack.mediaType isEqual:AVMediaTypeAudio]) {
NSArray *meta = [playerItem timedMetadata];
for (AVMetadataItem *metaItem in meta) {
NSString *source = metaItem.stringValue;
metadatas.text = source;
}
}
}
}
}
[self.toggleButton setImage:[UIImage imageNamed:toggleIsOn ? #"playMusic.png" :#"stop.png"] forState:UIControlStateNormal];
}
-(IBAction) sliderChanged:(id)sender
{
player.volume = slider.value;
}
-(void) checkNetworkStatus:(NSNotification *)notice
{
// called after network status changes
NetworkStatus internetStatus = [internetReachable currentReachabilityStatus];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
switch (internetStatus)
{
case NotReachable:
{
NSLog(#"The internet is down.");
NSLog(#"%d",[defaults boolForKey:#"alertShown"]);
BOOL isAlertShown = [defaults boolForKey:#"alertShown"];
if(isAlertShown)
{
noNetwork = TRUE;
isPlaying = false;
[self showAlert];
}
break;
}
case ReachableViaWiFi:
{
NSLog(#"The internet is working via WIFI.");
if(self.alert)
{
[self.alert dismissWithClickedButtonIndex:0 animated:YES];
self.alert = nil;
}
noNetwork = FALSE;
BOOL isFirstTimePlayed = [defaults boolForKey:#"FirstPlay"];
if(!isPlaying)
{
if(isFirstTimePlayed)
{
[self playButtonPressed:nil];
}
}
break;
}
case ReachableViaWWAN:
{
NSLog(#"The internet is working via WWAN.");
if(self.alert)
{
[self.alert dismissWithClickedButtonIndex:0 animated:YES];
self.alert = nil;
}
noNetwork = FALSE;
BOOL isFirstTimePlayed = [defaults boolForKey:#"FirstPlay"];
if(!isPlaying)
{
if(isFirstTimePlayed)
{
[self playButtonPressed:nil];
}
}
break;
}
}
}
-(void)showAlert
{
//NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
//[defaults setBool:FALSE forKey:#"alertShown"];
//alert = [[UIAlertView alloc] initWithTitle: #"Alert" message: #"You have lost data connectivity. Please wait while we try to establish the connection again." delegate: nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
//[alert show];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:FALSE forKey:#"alertShown"];
self.alert = [[UIAlertView alloc] initWithTitle:#"Alert"
message:#"You have lost data connectivity. Please wait while we try to establish the connection again."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[self.alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(!isPlaying)
{
[player pause];
[self.toggleButton setImage:[UIImage imageNamed:#"playMusic.png"] forState:UIControlStateNormal];
}
}
- (NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
#end
Actually it's not in your hand. It depends on the ISP you are using for data. I've been using Tata Docomo for a while & they don't resume internet connection after a call is made most of the time. It depends on the Call duration too. If its too short, your app will work without an issue. They might be maintaining some data sessions. So, What basically I wanted to tell is, There is nothing you can do here.. :(
Currently i am using the class by apple reachability.m/.h and it works, except it notifies me for any change, where as i would like to only notify the user if the network is not reachable. Currently if i have a internet connection and then loose the network it tells me. However when you reconnect to the network it also tells me, which i do not want. I want it to only tell me when there is a loss/no network.
I believe it has something to do with the call:
- (void)viewWillAppear:(BOOL)animated
{
// check for internet connection
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(checkNetworkStatus:)
name:kReachabilityChangedNotification
object:nil];
internetReachable = [[Reachability
reachabilityForInternetConnection] retain];
[internetReachable startNotifier];
// check if a pathway to a random host exists
hostReachable = [[Reachability reachabilityWithHostName:
#"www.google.ca"] retain];
[hostReachable startNotifier];
// now patiently wait for the notification
}
when calling -[NSNotificationCenter addObserver:selector:name:object:], does the name have any other function then being literally a name? this is my first time using NSNotificationCenter so i am not well versed in this matter.
EDIT:
Here is my checkNetworkStatus function: (The problem is i am getting "NotReachable" as the network connection is coming back and NSAlert goes off multiple times)
- (void) checkNetworkStatus:(NSNotification *)notice
{
// called after network status changes
NetworkStatus internetStatus = [internetReachable currentReachabilityStatus];
switch (internetStatus)
{
case NotReachable:
{
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:#"Network Failed" message:#"Please check your connection and try again." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil ];
[alert show];
NSLog(#"The internet is down.");
break;
}
case ReachableViaWiFi:
{
NSLog(#"The internet is working via WIFI.");
break;
}
case ReachableViaWWAN:
{
NSLog(#"The internet is working via WWAN.");
break;
}
}
NetworkStatus hostStatus = [hostReachable currentReachabilityStatus];
switch (hostStatus)
{
case NotReachable:
{
NSLog(#"A gateway to the host server is down.");
break;
}
case ReachableViaWiFi:
{
NSLog(#"A gateway to the host server is working via WIFI.");
break;
}
case ReachableViaWWAN:
{
NSLog(#"A gateway to the host server is working via WWAN.");
break;
}
}
}
Reachability will send a notification when the status has changed, but what you do with that notification is entirely up to you. If you don't want to tell the user that the network is back, you don't have to.
The "name" parameter in the NSNotificationCenter method indicates what notification you are subscribing to. When an object posts a notification, it does so with a particular name.
If you replace the www.hostname.com with just an IP address, it will only alert once instead of multiple times.
I just started playing around with Reachability and hopefully what I discovered is of use to you.
With regards to multiple 'Not Reachable' while reconnecting, could it be linked to this? Here the poster brought up the definition of 'reachable' for a remote host. I'm guessing while reconnecting the package is not able to go through successfully?
Another possibility is in Reachability Readme.txt
IMPORTANT: Reachability must use DNS to resolve the host name before it
can determine the Reachability of that host, and this may take time on
certain network connections. Because of this, the API will return
NotReachable until name resolution has completed. This delay may be
visible in the interface on some networks.
Maybe give it the IP directly and see if it helps?
With Reachability 2.2, you can add
[hostReach connectionRequired];
before
[internetReachable startNotifier];
to solve this problem.
runmad answered this problem here:
https://stackoverflow.com/a/2157858/623260
I would implement the whole Reachability class, tie it into your code as necessary and remove or comment out parts of Reachability. Just remove, one by one, the things you do not want to be notified of. Obviously, you need a good understanding of obj-c, the Reachability class, notifications, etc., but it can be done.
One thing you can do is unsubscribe to the changed notification NSNotificationCenter removeObserver... while you're processing one in the callback. Add back the observer before returning.
We can check rechability using this code
add class Reachability.h
#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
typedef enum {
NotReachable = 0,
ReachableViaWiFi,
ReachableViaWWAN
} NetworkStatus;
#define kReachabilityChangedNotification #"kNetworkReachabilityChangedNotification"
#interface Reachability: NSObject
{
BOOL localWiFiRef;
SCNetworkReachabilityRef reachabilityRef;
}
//reachabilityWithHostName- Use to check the reachability of a particular host name.
+ (Reachability*) reachabilityWithHostName: (NSString*) hostName;
//reachabilityWithAddress- Use to check the reachability of a particular IP address.
+ (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress;
//reachabilityForInternetConnection- checks whether the default route is available.
// Should be used by applications that do not connect to a particular host
+ (Reachability*) reachabilityForInternetConnection;
//reachabilityForLocalWiFi- checks whether a local wifi connection is available.
+ (Reachability*) reachabilityForLocalWiFi;
//Start listening for reachability notifications on the current run loop
- (BOOL) startNotifier;
- (void) stopNotifier;
- (NetworkStatus) currentReachabilityStatus;
//WWAN may be available, but not active until a connection has been established.
//WiFi may require a connection for VPN on Demand.
- (BOOL) connectionRequired;
#end
Reachability.m
#import <sys/socket.h>
#import <netinet/in.h>
#import <netinet6/in6.h>
#import <arpa/inet.h>
#import <ifaddrs.h>
#import <netdb.h>
#import <CoreFoundation/CoreFoundation.h>
#import "Reachability.h"
#define kShouldPrintReachabilityFlags 1
static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
{
#if kShouldPrintReachabilityFlags
NSLog(#"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
(flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
(flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
(flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-',
(flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-',
(flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
(flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-',
comment
);
#endif
}
#implementation Reachability
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
{
#pragma unused (target, flags)
NSCAssert(info != NULL, #"info was NULL in ReachabilityCallback");
NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], #"info was wrong class in ReachabilityCallback");
//We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively
// in case someon uses the Reachablity object in a different thread.
NSAutoreleasePool* myPool = [[NSAutoreleasePool alloc] init];
Reachability* noteObject = (Reachability*) info;
// Post a notification to notify the client that the network reachability changed.
[[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];
[myPool release];
}
- (BOOL) startNotifier
{
BOOL retVal = NO;
SCNetworkReachabilityContext context = {0, self, NULL, NULL, NULL};
if(SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context))
{
if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
{
retVal = YES;
}
}
return retVal;
}
- (void) stopNotifier
{
if(reachabilityRef!= NULL)
{
SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}
}
- (void) dealloc
{
[self stopNotifier];
if(reachabilityRef!= NULL)
{
CFRelease(reachabilityRef);
}
[super dealloc];
}
+ (Reachability*) reachabilityWithHostName: (NSString*) hostName;
{
Reachability* retVal = NULL;
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
if(reachability!= NULL)
{
retVal= [[[self alloc] init] autorelease];
if(retVal!= NULL)
{
retVal->reachabilityRef = reachability;
retVal->localWiFiRef = NO;
}
}
return retVal;
}
+ (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress;
{
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress);
Reachability* retVal = NULL;
if(reachability!= NULL)
{
retVal= [[[self alloc] init] autorelease];
if(retVal!= NULL)
{
retVal->reachabilityRef = reachability;
retVal->localWiFiRef = NO;
}
}
return retVal;
}
+ (Reachability*) reachabilityForInternetConnection;
{
struct sockaddr_in zeroAddress;
bzero(&zeroAddress, sizeof(zeroAddress));
zeroAddress.sin_len = sizeof(zeroAddress);
zeroAddress.sin_family = AF_INET;
return [self reachabilityWithAddress: &zeroAddress];
}
+ (Reachability*) reachabilityForLocalWiFi;
{
struct sockaddr_in localWifiAddress;
bzero(&localWifiAddress, sizeof(localWifiAddress));
localWifiAddress.sin_len = sizeof(localWifiAddress);
localWifiAddress.sin_family = AF_INET;
// IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
Reachability* retVal = [self reachabilityWithAddress: &localWifiAddress];
if(retVal!= NULL)
{
retVal->localWiFiRef = YES;
}
return retVal;
}
#pragma mark Network Flag Handling
- (NetworkStatus) localWiFiStatusForFlags: (SCNetworkReachabilityFlags) flags
{
PrintReachabilityFlags(flags, "localWiFiStatusForFlags");
BOOL retVal = NotReachable;
if((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect))
{
retVal = ReachableViaWiFi;
}
return retVal;
}
- (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags
{
PrintReachabilityFlags(flags, "networkStatusForFlags");
if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
{
// if target host is not reachable
return NotReachable;
}
BOOL retVal = NotReachable;
if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
{
// if target host is reachable and no connection is required
// then we'll assume (for now) that your on Wi-Fi
retVal = ReachableViaWiFi;
}
if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
{
// ... and the connection is on-demand (or on-traffic) if the
// calling application is using the CFSocketStream or higher APIs
if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
{
// ... and no [user] intervention is needed
retVal = ReachableViaWiFi;
}
}
if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
{
// ... but WWAN connections are OK if the calling application
// is using the CFNetwork (CFSocketStream?) APIs.
retVal = ReachableViaWWAN;
}
return retVal;
}
- (BOOL) connectionRequired;
{
NSAssert(reachabilityRef != NULL, #"connectionRequired called with NULL reachabilityRef");
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
{
return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
}
return NO;
}
- (NetworkStatus) currentReachabilityStatus
{
NSAssert(reachabilityRef != NULL, #"currentNetworkStatus called with NULL reachabilityRef");
NetworkStatus retVal = NotReachable;
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
{
if(localWiFiRef)
{
retVal = [self localWiFiStatusForFlags: flags];
}
else
{
retVal = [self networkStatusForFlags: flags];
}
}
return retVal;
}
#end
and use via direct calling method in appdel class using
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(checkNetworkStatus:) name:kReachabilityChangedNotification object:nil];
-(void) checkNetworkStatus:(NSNotification *)notice
{
Reachability* internetReachable;
BOOL isInternetActive;
// called after network status changes
NetworkStatus internetStatus = [internetReachable currentReachabilityStatus];
switch (internetStatus)
{
case NotReachable:
{
NSLog(#"The internet is down.");
isInternetActive = NO;
break;
}
case ReachableViaWiFi:
{
NSLog(#"The internet is working via WIFI.");
isInternetActive = YES;
break;
}
case ReachableViaWWAN:
{
NSLog(#"The internet is working via WWAN.");
isInternetActive = YES;
break;
}
}
NetworkStatus hostStatus = [hostReachable currentReachabilityStatus];
switch (hostStatus)
{
case NotReachable:
{
NSLog(#"A gateway to the host server is down.");
// self.hostActive = NO;
break;
}
case ReachableViaWiFi:
{
NSLog(#"A gateway to the host server is working via WIFI.");
// self.hostActive = YES;
break;
}
case ReachableViaWWAN:
{
NSLog(#"A gateway to the host server is working via WWAN.");
// self.hostActive = YES;
break;
}
}
}