I'm working on an iPhone app that needs to send the current location to a server so it knows what push notifications to send. It doesn't have to be very precise, startMonitoringSignificantLocationChanges is perfect for my needs.
This all works well as long as the app is running on screen or in the background. However if I kill/terminate the app it doesn't work anymore. From what I understand the app should be automatically relaunched with the special UIApplicationLaunchOptionsLocationKey as launch option. However the app doesn't relaunch (at least not in simulator).
I've read some stuff here too:
Behaviour for significant change location API when terminated/suspended?
Does the automatic relaunching only work when the app is terminated from suspended state by the system and not when you manually kill the app? I also tried the special info.plist UIApplicationExitsOnSuspend which also terminates the app when it goes into the background. It doesn't get relaunched then either.
Is there a way to simulate the app being terminated by the system in the simulator?
What happens after an iOS update when the phone has restarted? Is there a way to make sure that the app will get relaunched?
An app is relaunched by an SLC regardless of how it was killed provided when it was killed at least one CLLocationManager had called startMonitoringSignificantLocationChanges. There is one caveat to this - in version iOS7.0(.x) it was broken. It started working again in iOS7.1+.
To get this working requires that you complete a few steps.
In you project capabilities you must enable the background mode location updates because you want to be woken in the background.
You need to add the key NSLocationAlwaysUsageDescription to the info.plist containing a description of why you want to always be able to use location in the background.
In the code you must request authorization from the user to always use location
In the code you must request that location updates continue to be delivered while in the background
In the code you must start monitoring for significant location changes
Here is an example:
AppDelegate,h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate, CLLocationManagerDelegate>
#property (strong, nonatomic) UIWindow *window;
#property CLLocationManager* locationMgr;
#end
AppDelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize locationMgr;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(#"app launching");
locationMgr = [[CLLocationManager alloc] init];
[locationMgr setDelegate:self];
// Added in iOS8
if([locationMgr respondsToSelector:#selector(requestAlwaysAuthorization)])
[locationMgr requestAlwaysAuthorization];
// Added in iOS9
if([locationMgr respondsToSelector:#selector(setAllowsBackgroundLocationUpdates:)])
[locationMgr setAllowsBackgroundLocationUpdates:YES];
[locationMgr startMonitoringSignificantLocationChanges];
return YES;
}
-(void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(#"app delegate received significant location change");
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:[[UIApplication sharedApplication] applicationIconBadgeNumber]+1];
}
#end
The first time you run the app on your device, click on OK to allow the app to use your location in the background when it is requested. Then double click the home button and swipe the app off the task switcher to kill it. Click home, then swipe up from the bottom of the screen to open the Control Center and turn on Airplane Mode, wait a few seconds, then turn off airplane mode. Watch the badge counter increment on your app.
It was launched by iOS on an SLC.
One gotcha I would like to add. If you create two CLLocationManager instances and call startMonitoringSignificantLocationChanges on both, then call stopMonitoringSignificantLocationChanges on one. Even though the other CLLocationManager will continue to receive SLC events while the app continues to run, when you app exits for any reason, it will not be relaunched.
It seems the last call before exit sets the relaunch behaviour.
start, start, stop, exit - app doesn't relaunch on SLC.
start, start, stop start, exit - app does relaunch on SLC.
I've answered a question like this.
You can check my answer on the link below.
https://stackoverflow.com/a/35722254/3368791.
Related
I use MKMapView it works fine on iPhone, iPad and simulators but in iPod it crash when i second time enter in the view(first time it work fine). I have tried this but it is not work for me:
-(void) backButtonAction
{
[_mapView setDelegate:nil];
[self.navigationController popViewControllerAnimated:YES];
}
When I try to execute the code on an iPod(go second time on view) .I get an error ( EXC_BAD_ACCESS(code=EXC_ARM_DA_ALIGN,address=0x494f6055) )
By this solution didUpdateUserLocation method is not called and you are not able to get user location internally from didUpdateUserLocation method but until Apple not fixes it.This is the only solution i got from the link EXC_BAD_ACCESS at lauch for EAGLContext renderbufferStorage: fromDrawable: in Cocos2d app whie debugging
which i do and remove the crash.
In Xcode, go to Product -> Scheme -> Edit Scheme ... And for the Run Debug configuration (on left side) choose "Options" (on right side) and configure "GPU Frame Capture" as Disabled.
I know there are hundreds of topics out there concerning the background fetch on iOS. I simply cannot solve my problem to get the background fetch for my app to work. It is absoulutely substantial for the outcome of my app to have a working background fetch. My background fetch works fine on the simulator via Debug -> Simulate Background fetch and also on device with the special scheme setting: "Launch due to a background fetch event". I know that it doesn´t gets executed when the user is force quitting the app. I tried to lock the iPhone and wait for hours then unlock it to try to trigger the background fetch. Nothing happens. Actually everything works fine but the background fetch simply NEVER gets executed on my iPhone. I know that iOS has a special algorithm for calling background threads so a little patient is needed. But after 2 months of waiting for a background fetch to happen automatically I don´t have patients anymore. What I did:
App capabilites: Background fetch activated
Info.plist: Required background modes: App downloads content from the network
App delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if ([UIApplication instancesRespondToSelector:#selector(registerUserNotificationSettings:)]){
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
}
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:2.0];
return YES;
}
- (void) application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
//Do my stuff
completionHandler (UIBackgroundFetchResultNewData);
}
Did you check out to go Settings->General->background app refresh and check if its enabled?
It could be the problem...
I am new to iOS app development and near completion to developing my first app. So now begins the finishing work, which includes how my app should behave when it reaches certain events or states. I know the code to handle such tasks goes into appDelegate.m but I am kinda confused about what I am actually supposed to do. My app is simple, it triggers an animation with sound when a button is pressed and I want the sound to stop as soon as the user hits the home button. I tried this but in vain:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
finalViewController.AudioServicesDisposeSystemSoundID(soundID)
}
Besides my app also crashes when I press the home button sign twice and try to close my app. It gives me the 'signal SIGABRT' error in main.m. Please help.
Try doing it in here instead:
- (void)applicationWillResignActive:(UIApplication *)application{}
or maybe
- (void)applicationWillTerminate:(UIApplication *)application{}
You say that you're getting an error like:
use of undeclared identifier soundID
If soundID is a property of your app delegate, you should access it using property notation, like:
self.soundID
or:
[self soundID]
The "undeclared identifier" means that the compiler doesn't know what you're talking about when you say soundID. The instance variable that's backing that property probably has a different name (like _soundID), so soundID doesn't refer to the ivar itself, it's just the property name.
Use the given code snippet to stop the sound & access the soundId which you have passed in AudioServicesPlaySystemSound(soundID). You can create the soundId variable in appDelegate & save the soundId when you play the system sound.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
AudioServicesDisposeSystemSoundID(soundID)
}
I am working on an app that keeps track of user's location at a time-interval set by the user himself(e.g. every 5 minutes) and sends it to a server page by ASIHTTPRequest.
This app should be able to receive updates on foreground, either on background or even when the app is not running(location services).
Although my app successfully receives updates on the foreground and background, it does not seem to wake up when it is not running and do not send me up any requests to the server.
I am using CLLocationManager and its delegate to perform startMonitoringSignificantLocationChanges for when it is on the background.
On Settings, the icon for my app in Location Services appears with a purple arrow as expected.
On my info.plist, I have Required Background Modes set with an item locations as required and methods:
locationManager:didUpdateToLocation:fromLocation:
locationManager:didFailWithError:
implemented.
My method:
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
is also implemented and checks whether launchOptions
contains UIApplicationLaunchOptions- LocationKey before starting the significant locations monitoring for when it should wake up / relaunch.
Is there any way I can find out whether my app is really being relaunched?
Is there any extra config that needs to be set in order this to work?
Please let me know if I should provide any additional info.
Specs I am using:
SDK Xcode 4.2.1
CLLocation is inside a Singleton class (read somewhere this might impact)
iOS deployment target: 4.3
Tested on Iphone 3GS,4 and Xcode's iOS 5 simulator, same behavior happens to all of these devices.
Devices:universal
UPDATE
I inserted my code inside -[UIApplication beginBackgroundTaskWithExpirationHandler:] and tried to check against errors with UIBackgroundTaskInvalid. However, it does not even seem to enter the (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions method.
I am keeping track of the app by trying to save and retrieve data by using SQLite. When executing on both foreground and background, it records the data with no problem. When the app is not running, no data is saved at all.
How are you currently checking to see if the app relaunches? Are you logging anything?
The app will relaunch to the background, so you won't see your app come alive. It will actually shut down automatically after some time again. You can do some work and request more background time using -[UIApplication beginBackgroundTaskWithExpirationHandler:].
Another answer here on SO posted some example code. From your description I cannot see anything missing, compare your code to that project to see if your missing something.
Im trying to find a way to save data before my app enters multitasking, i know how to save data, but i dont know what method to use to save it before the app enters multitasking.
-(void)applicationDidEnterBackground:(UIApplication *)application{
this one? because i have everything set up to save, but it doesn't seem to be saving it, and im positive that its the multitasking part because it works on the ios 3 simulator. Do i have to save it in the delegate?
Thanks,
Jacob
EDIT: On the IOS 3 one i have it saving data in the
- (void)applicationWillTerminate:(UIApplication *)application {
Yes Jacob, You have to save it in the application delegate of your app.
The method -(void)applicationWillResignActive:(UIApplication *)application gets called when the device enters standby mode or when the app is switched to background.
So the saving part you can add to this method .
Also to make the app save data for iOS versions < 4.0 , add the saving code to applicationWillTerminate: also.
You should use the method what is the method Apple recommends
-(void)applicationDidEnterBackground:(UIApplication *)application
but you can also use
- (void)applicationWillResignActive:(UIApplication *)application
which is the method that is called instead of
- (void)applicationWillTerminate:(UIApplication *)application
Take a look at this Delegate method:
-(void)applicationWillResignActive:(UIApplication *)application
This allows you to react when the application becomes inactive. See the Docs for more information.
Happy coding :)