Determining the event when the iOS App is in Closed State to send a LocalNotification on seeing a Beacon - ios

I'm Developing a App using a iBeacon functionality. I want to fire an event when the App is in background & when it is closed. These have different Alert messages. I was able to determine when the App goes to Background. But was finding it difficult when the App gets closed.
I set a checkpoint for the App when it is in background state. But how should we find if the App is closed completely.
Thanks,

i don't know what exactly you want but you can check you app state by following line of code
UIApplicationState state = [[UIApplication sharedApplication] applicationState];
UIApplicationStateBackground when application is in background
UIApplicationStateInactive when app is not in background

Take a look at UIApplicationDelegate's - (void)applicationWillTerminate:(UIApplication *)application method. Seems like what you need. It will be called before application is terminated (for example as a result of user removing it from the list of running apps).

Related

Check if the application is inactive in the foreground mode

I can check if my application is in the foreground or background mode through the AppDelegate. I want now to check if the application is inactive even it's in the foreground mode. In other words, I want to check that the user is not using the app even if it is in the foreground. Is there any way to do it from the AppDelegate? Is there any other way for the check?
There is UIApplicationStateInactive state in UIApplicationState that serves exactly that purpose.

iBeacon-App: Custom code when launched from lockscreen

Since iOS 8, the operating system is indicating an iBeacon-enabled application, which is inside a defined region, with an icon in the left bottom corner of the lockscreen (see http://appleinsider.com/articles/14/06/03/apples-ios-8-uses-ibeacon-tech-brings-location-aware-app-access-to-lock-screen for reference).
I want to make use of this feature in my app by running custom code if the app is launched from the lockscreen (e.g. switch to specific view).
How to check in the Application Delegate if the app was launched from the lockscreen? I couldn't find any documentation on this.
AFAIK, it's not possible to detect whether your app was brought into the foreground via the "Suggested apps" feature (that's what Apple calls the icon on the lock screen), or by any other means (app switcher, app icon on the home screen).
You could do some heuristics. If the app came into the foreground and there are no beacons in range (you can check that with ranging), then there's no way it was via the lock screen icon.
There is a Excellent article on this topic by Matt Coneybeare
Below I have pointed out some of the important points from that article , for more info check out that article.
From Article of Matt Coneybeare
On iOS 6 and lower it could be detected using the current UIApplicationState in applicationWillEnterForeground
UIApplicationState state = [[UIApplication sharedApplication] ApplicationState];
if (UIApplicationStateInactive == state)
// Coming from locked screen (iOS 6)
else
// Coming from Springboard, another App, etc...
But From iOS 7 onwards, the state value is UIApplicationStateBackground in both scenarios.
It seems that there is no possible way to detect where the App is being launched from on iOS 7, but there is a way to detect if you are going to the Lockscreen vs Homescreen (or something else).
The trick is to read the screen brightness in applicationDidEnterBackground.
When the App hits the background due to the lock button being pressed or an auto-lock timeout, the brightness will be 0.0 on iOS 7.
Otherwise, it will be > 0 when the home button is pressed or another App launched from the multitask selector or notification center.
When the app is launched by beacon detection, your AppDelegate's (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region method will be invoked.
You can put any custom code inside that method, perhaps to set a flag indicating this is how the app was launched.
The following code shows how to detect that tapping a local notification launched the app from the lock screen. For details, see: https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/IPhoneOSClientImp.html
- (BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UILocalNotification *localNotif =
[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotif) {
// do something
}
...
return YES;
}
This is not the same as launching the app by tapping the icon on the bottom of the lock screen, but it is similar. If you present a local notification on beacon detection it will work as described above if tapped.
I believe the app icon shows up on the bottom of the lock screen only if your app is launched into the background by beacon detection and does not present a local notification. If this is the case you are looking for, you might examine the launchOptions above and see if a different key is present in this case.

Determining if a UILocalNotification was fired from scheduling or user interaction

I'm trying to determine different scenarios of UIApplication didReceiveLocalNotification:. If a user clicks the notification the while app is inactive, I should bring them to the corresponding UI page. Otherwise, if user just opened the app without tapping a notification, I should let them stay in the UI page which they left off from.
However, there is a little problem as the UILocalNotification was scheduled by myself.
[[UIApplication sharedApplication] scheduleLocalNotification:scheduledAlert];
So every time it fired by iOS, it will call the same delegate method as the callback when I manually clicked the notification on the status bar:
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { ... }
I tried some tricky hack such as counting the fired times while app is inactive mode, counting 1 means iOS firing, and counting 2 means user clicked, and relative counting management code.
But I don't think this could be the best practice. I checked the iOS Messages application, which has the same functionality. If you put the app into inactive mode, such as scroll down the status bar, then it can determine the UILocalNotification is from your touch (and will open the text editing mode) or just you return back to the app (stay in the previous status).
I would appreciate if you guys could let me know what the best solution is here!
I use a custom key-value pair which I set a NSMutableDictionary, which I then assign to UILocalNotification.userInfo, to tell different scenarios.
I check the app state so that I only handle the notification if I'm coming from the background:
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateInactive) {
// Your Code Here
} else {
}

Can the application know whether the Home button or the Power button was pressed? [duplicate]

I have an app that needs to do something when it’s sent to background using the Home button and something else when the device is locked using the top hardware button. The standard way of solving these requirements are the notifications and delegate methods sent out by UIApplication. On iOS 4 they look like this:
// Pressing the home button
Will resign active.
Did enter background.
// Tapping app icon on Springboard
Will enter foreground.
Did become active.
// Pressing the lock button
Will resign active.
// Unlocking the device
Did become active.
In other words, it’s quite easy to tell between locking and backgrounding. On iOS 5 the behaviour changed:
// Pressing the home button
Will resign active.
Did enter background.
// Tapping app icon on Springboard
Will enter foreground.
Did become active.
// Pressing the lock button
Will resign active.
Did enter background.
// Unlocking the device
Will enter foreground.
Did become active.
Notice that the didEnterBackground and willEnterForeground notifications are now sent out even when (un)locking the device, making it impossible to tell between locking and backgrounding. Is this change documented somewhere? Is it a regression? Do you know another way to distinguish the two cases?
iOS 6
In my preliminary testing via the simulator, checking the application state with
[[UIApplication sharedApplication] applicationState]
in either
- (void)applicationWillEnterForeground:(UIApplication *)application
- (void)applicationDidEnterBackground:(UIApplication *)application
allows you to differentiate between a call to lock the device and just switching back to the homescreen. A lock screen will return 1 (UIApplicationStateInactive), whereas a home button press will register as a 2 (UIApplicationStateBackground).
It seems consistent and should work on an iOS device just as reliably as it does in the simulator.
iOS 7
The iOS 6 method no longer works in iOS 7. In order to do this now, you have to utilize CFNotificationCenter and listen for a darwin notification (labeled: com.apple.springboard.lockcomplete). You can find the github repo with the sample project here: https://github.com/binarydev/ios-home-vs-lock-button
Credit for the iOS 7 fix goes out to wqq
I have looked into this quite a bit so I would love to be wrong here if someone knows something I don't, but technically, there is no documented way to tell the difference between locking the device, and sending to background.
One thing you can check however, is the UIApplicationState during the transition from foreground to background. Locking a device will give UIApplicationStateInactive and moving the App to the background will give UIApplicationStateBackground. But, since this behaviour is not officially documented it may change in the future.
A basic example:
- (void)applicationDidEnterBackground:(UIApplication *)application {
UIApplicationState state = [[UIApplication sharedApplication] applicationState];
NSLog(#"Device state: %#", state);
switch (state) {
case UIApplicationStateActive:
/* ... */
break;
case UIApplicationStateInactive:
/* Device was/is locked */
break;
case UIApplicationStateBackground:
/* User pressed home button or opened another App (from an alert/email/etc) */
break;
}
}
UIApplicationState - The running states of an application
typedef enum {
UIApplicationStateActive,
UIApplicationStateInactive,
UIApplicationStateBackground
}
UIApplicationState
Constants
UIApplicationStateActive - The application
is running in the foreground and currently receiving events. Available
in iOS 4.0 and later.
UIApplicationStateInactive - The application is running in the
foreground but is not receiving events. This might happen as a result
of an interruption or because the application is transitioning to or
from the background.
UIApplicationStateBackground - The application is
running in the background.
According to the UIApplicationDelegate Protocol Reference:
applicationWillResignActive:
didEnterBackground:
// ...
willEnterForeground:
applicationDidBecomeActive:
are the only methods that ever get called in both situations.
According to the iOS 4.3 to iOS 5.0 API Diff, these are the ONLY changes regarding UIApplication or UIApplicationDelegate, so I couldn't find where they documented any of these notification changes:
UIApplication.h
Added -[UIApplication setNewsstandIconImage:]
Added UIApplication.userInterfaceLayoutDirection
Added UIApplicationDelegate.window
Added UIApplication(UINewsstand)
Added UIApplicationLaunchOptionsNewsstandDownloadsKey
Added UIRemoteNotificationTypeNewsstandContentAvailability
Added UIUserInterfaceLayoutDirection
Added UIUserInterfaceLayoutDirectionLeftToRight
Added UIUserInterfaceLayoutDirectionRightToLeft
This is more of a workaround/hack, but according to my experience it's very reliable.
When the device is screen-locked (not just home button-ed, if that's a word :)) - bound network (UDP) sockets are broken.
I was using GCDAsyncUDPSocket (also AsyncUDPSocket before) and they both fire a network/broken pipe error reliably when the device is turned off.
In my case I need the UDP socket anyway, for other apps it might be a bit smelly, however, just binding/listening on a UDP socket without any action is not too terrible if you really need to differentiate here.
This note will [self destruct]; is 5 minutes (so Apple won't find out).
There’s a thread about this issue on Apple Developer Forums (registered developers only, sorry). The gist is that the new behaviour is by design. There are requests for a new API feature to distinguish between the two use cases, but nothing working yet.
Here is what Apple's iOS Programming Guide says:
Pressing the Sleep/Wake button is another type of interruption that
causes your app to be deactivated temporarily. When the user presses
this button, the system disables touch events, moves the app to the
background but sets the value of the app’s applicationState property
to UIApplicationStateInactive (as opposed to
UIApplicationStateBackground), and finally locks the screen.
http://developer.apple.com/library/ios/#DOCUMENTATION/iPhone/conceptual/iPhoneOSProgrammingGuide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html
So, you should check the UIApplication's applicationState property in applicationDidEnterBackground:. If it is UIApplicationStateBackground the user pressed the home button. But if it is UIApplicationStateInactive the user locked the device.

Need clarification about UIApplicationState

I need your help in clarifying my understanding of the various states of an app. I am going to state my interpretation - but please feel free to correct me.
1) App is launched and running in the foreground: state = UIApplicationStateActive
2) User pushes home button: state = UIApplicationStateBackground (????).
Debug stmt in my app shows it to be Active
3) User double-taps Home and kills the app: state = UIApplicationStateInactive
If the value for case 2 is indeed Active, then when is the value set to Background?
My location-based app relies on this values to take appropriate action for the user.
if ( ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) ||
([UIApplication sharedApplication].applicationState == UIApplicationStateInactive) ) {
// isInBackground = YES;
// ------ UI not available
}
else {
// isInBackground = NO;
// ------ UI is available
}
Regards,
Sam.
When the user taps on the app icon, the app briefly goes through a transitional state of UIApplicationStateInactive on its way to becoming UIApplicationStateActive. This is where the app gets itself ready to display to the user.
When the app is open, the application state is UIApplicationStateActive.
If the user presses the home button, and is returned to the springboard (home screen), or the application is interrupted by something, such as a phone call, the application state transitions back to UIApplicationStateInactive.
For the application state of your app to become UIApplicationStateBackground, your application would have to register for a background process. Look into how to background your location services.
Apple documentation:
UIApplicationState Constants Reference
Swift: .Active | Objective-C: UIApplicationStateActive
The app is running in the foreground and currently receiving events.
Available in iOS 4.0 and later.
Swift: .Inactive | Objective-C: UIApplicationStateInactive
The app is running in the foreground but is not receiving events. This
might happen as a result of an interruption or because the app is
transitioning to or from the background.
Available in iOS 4.0 and later.
Swift: .Background | Objective-C: UIApplicationStateBackground
The app is running in the background.
Available in iOS 4.0 and later.
Some examples:
UIApplicationStateActive - App is running in foreground. Simple.
UIApplicationStateInactive - E.g. App was in the background and is opening through a push notification (transitioning atm). Or the control/notification center is presented above your app. You kind of see it, is in foreground.
UIApplicationStateBackground - App is in the background, but still running. E.g. playing music. Then - this can take a while or not (depending on process you are running in background), but in one point your app is killed. You will see app's snapshot and icon between minimized apps, but the app will be launch again first.

Resources