I am building an application and trying to check and see if a device is still available on the network (by connecting to the devices IPAddress). I am using reachability to confirm that it is available.
When I network access for the iOS device (turn on airplane mode for example) everything works properly, but if I remove the device from the network, reachability does not seem to notice the change.
It seems like reachability is caching the results, and not seeing the update.
Don't use reachability then!
Use this bit of code instead which works a treat;
NSString *connected = [NSString stringWithContentsOfURL:[NSURL URLWithString:#"http://www.google.com"]];
wait(25000);
if (connected == NULL) {
NSLog(#"Not Connected");
//Code to show if not connected
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:#"Oops! You aren't connected to the Internet."
delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
} else {
NSLog(#"Connected Successfully!");
//Any other code for successful connection
}
The SCReachability API only checks if the local hardware is configured such that it could reach the specified address; it does not actually attempt to reach it. To determine if the target is alive and kicking, you must attempt to open a connection to it.
Check out this answer. While the pixelbit's answer is viable, burtlo is right to bring up that just waiting 25 seconds isn't a great idea. Using the NSURLConnection is much cleaner.
Apple updated the Reachabilty class file. You can test it with latest Xcode.
here is link:
Apple Reachabilty Sample Code
I tested with Xcode 8.3.1 on iPhone 6 version 10.3.1.
It will notify user for change in network status.
Related
I got the pop up, i have accepted, i see it in the notifications and it is turned on but this code always returns no and i cant seem to find out why
UIApplication *application = [UIApplication sharedApplication];
BOOL enabled;
// Try to use the newer isRegisteredForRemoteNotifications otherwise use the enabledRemoteNotificationTypes.
if ([application respondsToSelector:#selector(isRegisteredForRemoteNotifications)])
{
enabled = [application isRegisteredForRemoteNotifications];
}
else
{
UIRemoteNotificationType types = [application enabledRemoteNotificationTypes];
enabled = types & UIRemoteNotificationTypeAlert;
}
if (enabled){
NSLog(#"is registered");
}else{
NSLog(#"is not registered");
}
I think what makes it happen might be:
isRegisteredForRemoteNotifications will always return NO in
simulators.
registerForRemoteNotifications fails.
I was struggling with the same problem, this worked for me.
BOOL enabled = NO;
UIUserNotificationSettings *notificationSettings = [SharedApplication currentUserNotificationSettings];
enabled = notificationSettings.types < 4;
As per the Apple documentation isRegisteredForRemoteNotifications will return NO if registration has not occurred, has failed, or has been denied by the user. YES will be returned if the app has registered for remote notifications and has received is device token. So in answer to your question NO it will not always return no it will also return yes if a your app has registered for remote notifications and it has received it device token.
Checkout the Apple Documentation for a better description
Return Value
YES if the app is registered for remote notifications and received its device token or NO if registration has not occurred, has failed, or has been denied by the user.
Discussion
This method reflects only the successful completion of the remote registration process that begins when you call the registerForRemoteNotifications method. This method does not reflect whether remote notifications are actually available due to connectivity issues. The value returned by this method takes into account the user’s preferences for receiving remote notifications.
I think the simulator will always return no, try running your code on a real device and see if the behavior continues
After iOS10 and to make it work both on the simulator and on a real device you should use something like this:
[[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
if (settings.alertStyle == UNAlertStyleNone)
NSLog(#“ACCESS DENIED!”);
else
NSLog(#“ACCESS GRANTED!”);
}];
If you are NOT planning to test on the simulator you may use the code below (unfortunately this will always return NO on the simulator):
[[UIApplication sharedApplication] isRegisteredForRemoteNotifications];
Do NOT use the code below if you are planning to compile for iOS 10 or iOS11 because it has been deprecated on iOS10:
[SharedApplication currentUserNotificationSettings];
In my case, [UIApplication sharedApplication].isRegisteredForRemoteNotifications is always NO when capability Background Modes > Remote notifications hasn't been turned on.
I'm using the Multipeer Connectivity Framework to transfer files between devices. I'm using the standard MCAdvertiserAssistant and MCBrowserViewController to connect the devices. On the first try from device A to device B things work fine. Same things on the first transfer from device B to device A.
If you try either direction again, after MCBrowserViewController presents its dialog to choose a peer and you select one, the popup to accept the request on the other device never appears. No error messages, no calls to delegate methods - just nothing. Has anyone come across this and any ideas?
I had the same problem and solved it with initiating all the necessary components every time I start advertising or browsing for peers. It isn't the cleanest solution but in my case it works 100%.
The code below is how I implemented it, so this is without the build-in ViewController provided by Apple.
Please be aware that [session disconnect] is an async method which sometimes take a few seconds to complete.
- (void)startBrowsing
{
// Initiate new advertiser
isAdvertising = YES;
_peerID = [[MCPeerID alloc] initWithDisplayName:#"Wallet"];
_session = [[MCSession alloc] initWithPeer:_peerID];
_session.delegate = self;
_advertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:_peerID discoveryInfo:nil serviceType:#"made2pay"];
_advertiser.delegate = self;
// Start advertiser
[_advertiser startAdvertisingPeer];
}
- (void)stopBrowsing
{
[_advertiser stopAdvertisingPeer];
[_session disconnect];
_session = nil;
_peerID = nil;
_advertiser = nil;
isAdvertising = NO;
}
I would like to detect when a user refused the microphone permission on my iOS application.
I only get this value when I try to record the microphone: -120.000000 db
But before to get this I have to set up an AVAudioSession. Is there another function?
And I got this message in the output:
Microphone input permission refused - will record only silence
Thanks.
If you are still compiling with iOS SDK 6.0 (as I am) you have to be a bit more indirect than #Luis E. Prado, as the requestRecordPermission method doesn't exist.
Here's how I did it. Remove the autorelease bit if you're using ARC. On iOS6 nothing happens, and on iOS7 either the 'microphone is enabled' message is logged or the alert is popped up.
AVAudioSession *session = [AVAudioSession sharedInstance];
if ([session respondsToSelector:#selector(requestRecordPermission:)]) {
[session performSelector:#selector(requestRecordPermission:) withObject:^(BOOL granted) {
if (granted) {
// Microphone enabled code
NSLog(#"Microphone is enabled..");
}
else {
// Microphone disabled code
NSLog(#"Microphone is disabled..");
// We're in a background thread here, so jump to main thread to do UI work.
dispatch_async(dispatch_get_main_queue(), ^{
[[[[UIAlertView alloc] initWithTitle:#"Microphone Access Denied"
message:#"This app requires access to your device's Microphone.\n\nPlease enable Microphone access for this app in Settings / Privacy / Microphone"
delegate:nil
cancelButtonTitle:#"Dismiss"
otherButtonTitles:nil] autorelease] show];
});
}
}];
}
EDIT: It turns out that the withObject block is executed in a background thread, so DO NOT do any UI work in there, or your app may hang. I've adjusted the code above. A client pointed this out on what was thankfully a beta release. Apologies for the mistake.
Please note that this will only work if built with Xcode 5, and not with 4.6
Add the AVFoundation Framework to your project
Then import the AVAudioSession header file, from the AVFoundation framework, where you intend to check if the microphone setting is enabled
#import <AVFoundation/AVAudioSession.h>
Then simply call this method
[[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) {
if (granted) {
// Microphone enabled code
}
else {
// Microphone disabled code
}
}];
The first time this method runs, it will show the prompt to allow microphone access and based on the users response it will execute the completion block. From the second time onwards it will just act based on the stored setting on the device.
Swift answer:
if AVAudioSession.sharedInstance().recordPermission() == .Denied {
print("Microphone permission refused");
}
Or you can use framework like PermissionScope which permit to easily check permissions. https://github.com/nickoneill/PermissionScope
Edit: Swift 3 answer:
import AVFoundation
...
if AVAudioSession.sharedInstance().recordPermission() == .denied {
print("Microphone permission refused");
}
I'm not 100% certain if we're allowed to talk about iOS 7 outside of Apple's devforums, but I found the answer you're looking for there.
In short, you'll find your solution in the AVAudioSession.h header file in the SDK. And if you want to make use of it while still supporting iOS 6, make certain to use "respondsToSelector:" to check for the API availability.
Here is my code that calls "displayAlert". The problem is not only do I get an error message (wait_fences: failed to receive reply: 10004003) but the "alert" is displayed twice!
if(gSiteID.globalSiteID.length == 0) { // user didn't choose site
[self displayAlert:NSLocalizedString(#"Missing Site ID", nil) andData:NSLocalizedString(#"You must choose a site from the View Sites page",nil)];
return;
}
This the code for "displayAlert":
- (void) displayAlert: (NSString *) title andData: (NSString *) errorMsg {
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle: title
message: errorMsg
delegate:nil
cancelButtonTitle: #"OK"
otherButtonTitles: nil];
[alert show];
return;
}
I have searched SO and Google and found nothing that is specific to my issue. What am I doing wrong?
Are you testing this on a real device or the simulator? wait_fences: failed to receive reply usually means something bad happened with the debugger's connection to your device, or that you sat at a breakpoint for a really long time and it timed out. Are you sure that the code only executes once, and that nothing else could call that method? Stick breakpoints in your if statement and in your displayAlert:andData: method and see what happens. Run through your logic and find all the cases when that display alert method can be called and stick breakpoints on all of them.
I found the problem: indeed I was calling it twice from different .cs files (do you see the egg on my face?). Jack Lawrence please post your answer to the question, since you hit it on the head.
I am trying to redirect all NSLog output to be able to see all my logs in a UITextView inside the app (for debug purposes, and maybe later to log everything using TestFlight). I can't use the well-known DLog because I want to catch logs from frameworks I don't own.
I'm doing this by 'redirecting' stderr to a pipe and reading from this pipe.
Anyway, this works well on the simulator and on the device when the app is launched from within Xcode.
But, this does not work when the app is launched "by hand" on the device.
It seems that NSLog calls have no effect on the device: I don't read anything from the pipe. However, if I manually write on stderr : fprintf(stderr, "test") I can read it from the pipe, so the problem is not with stderr but rather with the NSLog function.
Why does it do nothing on devices ? Is there a way to make it write on stderr even on the device ?
If it is not possible to use NSLog on devices, is there another way to gather logs from external frameworks ?
Thank you.
NSLog goes to the system log on devices. You can access the system log using the C API asl (Apple System Log); also check out this blog post.
However if you're using TestFlight it's much easier to just replace/append those NSLog statements with the TFLog statement.
TFLog(#"This comment is live on TestFlight.");
If you want some UILogging, you could consider using ULog, a UIAlertView based Logging #define directive.
// ULog will show the UIAlertView only when the DEBUG variable is set
#ifdef DEBUG
# define ULog(fmt, ...) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:#"%s\n [Line %d] ", __PRETTY_FUNCTION__, __LINE__] message:[NSString stringWithFormat:fmt, ##__VA_ARGS__] delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil]; [alert show]; }
#else
# define ULog(...)
#endif
(source: http://overbythere.co.uk/blog/2012/01/alternatives-nslog)