How to respond to low power prompt in IOS? - ios

I'm sure this has been asked before, but I can't seem to find it and I'm not sure how to rephrase it.
In IOS 9+ when the power gets low iOS gives you a prompt to optionally engage low power mode.
I'd like be able to pause the activity in my app when this alert is visible.
I'm sure there is a delegate method that I can use. Does anyone know the name of it?
Thanks!

Watch for NSProcessInfoPowerStateDidChangeNotification as described in React to Low Power Mode on iPhones. When you get that notification, check the state:
Once your app is notified of a power state change, it should then query isLowPowerModeEnabled to determine the current power state...
Your app can query the current power state at any time by accessing
the isLowPowerModeEnabled property of the NSProcessInfo class, as
shown in Listing 7-2. This property contains a boolean value,
indicating whether Low Power Mode is enabled or disabled.

Or maybe you're just looking for
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
in your main AppDelegate.m This is called whenever any system popup is shown.

Related

Confused over which application state notifications I should be observing

My app is a livestreaming app that uses voice and video. I want to:
Detect when a user has brought up Notification Centre/Control centre over the app
Detect when the user receives some kind of full screen notification like battery low
Detect when the user receives a phone call
Detect when a user has pressed the home button to background the app
Detect when the app terminates.
I'm a bit confused as to which notifications I should be observing to detect these events.
My guess is:
.willResignActiveNotification
.willResignActiveNotification
.willResignActiveNotification or .didEnterBackgroundNotification?
.didEnterBackgroundNotification
.willTerminateNotification
And to detect when the app is back in its active state for 1 to 4 I need .didBecomeActiveNotification?
Is this right? Which one is number 3?
Yes, You should observer .willResignActiveNotification because your application still exists below iOS's Phone Application, which is presented by iOS when there is an incoming call. .didEnterBackgroundNotification will not be fired on incoming call, it will be fired when you press the home button.
Now, once you done with the call either by rejecting it or after finish your talk the Phone Application of iOS is removed from top and make your application active. So there you can observe for .didBecomeActiveNotification for all cases.
You can also check the commented lines in the methods provided by Xcode, when you create a new project. Checkout AppDelegate.swift to understand the difference
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state.
// This can occur for certain types of temporary interruptions
// **(such as an incoming phone call or SMS message)**
// or when the user quits the application and
// it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers,
// and invalidate graphics rendering callbacks.
// Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data,
// invalidate timers, and store enough application state information to
// restore your application to its current state in case it is terminated later.
// If your application supports background execution,
// this method is called instead of applicationWillTerminate: when the user quits.
}
Summarising it with your cases:
Detect when the user receives a phone call
only .willResignActiveNotification will be fired.
Detect when a user has pressed the home button to background the app
both .willResignActiveNotification and .didEnterBackgroundNotification will be fired respectively.
Hope it helps.

What should an ARKit app do when the user leaves the current screen?

Should the app keep the ARKit session open or pause it while the user leaves the current view controller or app? I've noticed a battery drain when using ARKit.
You should not pause the session when the user leaves the app to the background, as sessionWasInterrupted delegate automatically handles that:
An interruption is equivalent to manually pausing the session. Do not
call pause() in response to this callback, as that prevents your app
from being notified when the interruption ends.
And if the user stays on your app, but leaves the AR experience section, it depends on what your app does and its logic. You could pause and resume the session, or stop the session, save the world map and restore the session the next time user enters AR section later (even after terminating the app), just like how it was before the user left, including virtual contents that have been added before, or just start a new session.
ARKit is processor intensive and performs heavy processes on each frame the app is running, so the battery usage is heavy as well.

App restarts when woken from background

G'day iOS Guru's,
I have searched extensively for an answer, but can't find one (I bet the first response to my question will be to another similar question, but I cant find it).
Anyway, my problem is that I am running a simple map app that the user can drop pins on the map with a customised circle overlay around the dropped pin.
When the app goes into the background (iphone locked or home button pressed), if I re-enter the app within ~ 5 mins, the pins are still there and the app reopens to the last screen.
All good.
However, if I leave the app in the background for longer than 5 mins, the app restarts and all the pins are lost.
I have "Application does not run in background = NO" in the plist, and also enabled "App registers for location updates" under Required background modes.
How can I prevent the app from restarting after it enters the background and load the last opened view?
iOS can, and will, terminate your app while it's in the background if it needs additional resources to carry out whatever's going on in the foreground.
You need to ensure that your data is saved/archived when your app is terminated, and unpacked when re-launched so as to go back to where the user last was. The traditional way to do this is to use the applicationDidEnterBackground method, which is called when your app is suspended. You can then save all the data you need in order to resume cleanly in case your app is later terminated.
However, if you're targeting iOS 6 and upwards you can take advantage of a new feature - State Presumption & Restoration (link to documentation). State restoration off-loads some (but not all) of the heavy lifting onto iOS, and it can automatically snapshot your UI and provides easier ways to preserve and restore data.
in your AppDelegate.m
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
// Save your data
}

Keep app running while iOS device locked?

I have an app that makes heavy use of video out. In a typical use-case, I'll have an iPad connected to an external monitor. I just want the external monitor on; the iPad display does not need to stay on.
The ideal case would be for someone to connect to an external monitor, then lock their iPad. But that pauses my app. (Currently, I'm calling setIdleTimerDisabled to keep the iPad from locking up and pausing my app.)
I'd like to give the user the option of locking the iPad, but still having my app running and sending images to video out. (Note: I'm not talking about keeping my app running when it's not in the foreground. I just want to keep it running while it's in the foreground, but the device is locked.)
Is this possible?
I would say no, it is not possible. Here's why:
The docs read:
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.
Something interesting to note in the docs above is that a bit further down under "What to do when an interruption occurs" Apple recommends that you stop doing certain tasks.
In response to this change, your app should do the following in its applicationWillResignActive: method:
Stop timers and other periodic tasks.
Stop any running metadata queries.
Do not initiate any new tasks.
Pause movie playback (except when playing back over AirPlay).
Enter into a pause state if your app is a game.
Throttle back OpenGL ES frame rates.
Suspend any dispatch queues or operation queues executing non-critical code. (You can continue processing network requests and other time-sensitive background tasks while inactive.)
This tells me that Apple doesn't want or expect your app to be doing much of anything in this state, other than preparing to be fully backgrounded.
On a related note here's a thread that shows how to determine whether you've hit the Sleep/Wake button or not:
Is it possible to distinguish between locking the device and sending an app to background?

How to perform last actions upon user exiting an iPhone app?

Is there a way to perform some last actions when the user kills the application on iPhone?
In UIApplicationDelegate there is applicationWillTerminate: but as I understand it's not guaranteed to get called when the application terminates. Is there another way?
You can't rely on applicationWillTerminate being called. From the documentation:
For apps that do not support background execution or are linked against iOS 3.x or earlier, this method is always called when the user quits the app. For apps that support background execution, this method is generally not called when the user quits the app because the app simply moves to the background in that case. However, this method may be called in situations where the app is running in the background (not suspended) and the system needs to terminate it for some reason.
The proper place to save any state is when the app enters the background. Once that happens, there is no way to know if the app will return to the foreground or if it gets killed and then started from the beginning.
All methods concerning your app state are in your AppDelegate when you use one of the project templates.
Put the code in the applicationWillResignActive: method. It will get called if your app goes to an inactive state (terminating or no).
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
The "correct" place to save state is in both -applicationDidEnterBackground: and -applicationWillTerminate:. Don't worry about double-saving; generally only one of them is called (IME, -applicationWillTerminate: is not called when your app is killed in the background).
Caveat: -applicationDidEnterBackground: is not guaranteed to be called, since it is called after your app enters the background (and thus becomes eligible for killing without notice!). If the device is low on memory when your app is backgrounded, it might be killed. The best way to avoid this is to not use too much memory in the first place.
You could use
-applicationWillResignActive:, but I do not recommend this: apps become inactive quite frequently. An obvious is system dialogs (location/privacy prompts, Wi-Fi, notifications that show as alerts, alarms), TWTweetSheet, and I suspect MFMailComposeViewController, MFMessageComposeViewController, Notification Center, the app-switcher bar (e.g. to change tracks/enable orientation lock).
you can use applicationWillResignActive method in the appdelegate, or you can do the following, if you want to save stuff, but for some reason, you dont want to do it in the app delegate:
- (void) viewDidLoad/init {
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(myApplicationWillResign)
name:UIApplicationWillResignActiveNotification
object:NULL];
}
- (void) myApplicationWillResign {
NSLog(#"About to die, perform last actions");
}

Resources