How to selectively enable background processing in iOS4 - xcode

I have successfully enabled background processing for my Core Location app. In order to ensure I am on the right track here is a quick overview of how I implemented ENTERING background mode:
1: info.plist: Added key "Required background modes" with value "App registers for location updates"
2:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[self.locationManager stopUpdatingLocation];
[self.locationManager startMonitoringSignificantLocationChanges];
}
When EXITING background mode I did so with this code:
- (void)applicationWillEnterForeground:(UIApplication *)application
{
self.locationManager.delegate = self;
[self.locationManager stopMonitoringSignificantLocationChanges];
[self.locationManager startUpdatingLocation];
}
This seems to be working well as I am getting locations reported while my iPhone is off. Any advice on whether this approach is considered "best practice" would be appreciated.
My concern is that even when my app is explicitly terminated on the iPhone the Location Services arrow still shows on the status bar.
My question is: Is it possible to programatically enable/disable an application's background processing?
My reason for this is that if my user does not want to use the location awareness portion of my app, I would like to prevent the app from processing in the background, even if it is not receiving locations.
Thanks and much for any info!
Thank-you for your prompt answers. What seems to be happening is that even though I issue
[self.locationManager stopMonitoringSignificantLocationChanges];
and
[self.locationManager stopUpdatingLocation];
the Location Services arrow thingy on the status bar stays on, even when my app has exited. I have force terminated it as well, but the arrow stays on.
I also have no other apps that are running as suspended. I have looked in Settings > Location Services > MyApp and see that both myApp and the built-in Maps app indicate that they are currently using Location Services, however, neither is actually running.
Does anyone have any idea why this is happening? Could it be that I am not freeing up resources properly when my app either goes into the background or terminates?
All answers are much appreciated.

You could have a setting saved in NSUserDefaults and use that whether or not to enable your background location services.
NSUserDefaults *defaults = [NSUserDefaults standardDefaults];
someFlag = [defaults boolForKey:#"gpsOnOff"];
if (someFlag) {
// enable background services
}

Related

NSNetService says it is published, but it isn't visible on the network

I'm working on a little iOS app for my own use (initially, at least) and I thought I would use Bonjour to configure networking between two iOS devices.
My server's interface defines
NSNetService *netService;
and the implementation uses the following code to advertise its existence:
const NSString *kSEBonjourServiceDomain = #""; //use defaults
const NSString *kSEBonjourServiceName = #"_test._tcp.";
//...
netService = [[NSNetService alloc] initWithDomain:(NSString *)kSEBonjourServiceDomain type:(NSString *)kSEBonjourServiceName name:#"" port:sin.sin_port];
if (netService)
{
netService.delegate = self;
netService.includesPeerToPeer = YES;
[netService publish];
}
else NSLog(#"Failed to create NSNetService");
When I start the server, my NSNetService object does call the -netServiceDidPublish: delegate method, but when I use Discovery to browse the bonjour services on my network, my service doesn't appear. Apart from the const strings, this code is the same as some code in one of my Mac apps (which works as expected) and also very similar to Apple's sample code.
I've gone through all the options in Xcode's capabilities tab in case I needed to add something there, but I can't see anything relevant. I've also read a bunch of documents and tutorials that don't mention having to do anything more than that, but it wouldn't surprise me to learn that this only works on iOS if you set an obscure build setting to a string that you had to learn about by reading the Human Interface Guidelines for watchOS last September.
So, can anyone enlighten me? What am I missing?
Thanks in advance!
It turned out that due to a silly error elsewhere in my code, sin.sin_port was set to 0 by the time I was registering my NSNetService. Although NSNetService doesn't see this as a problem, it was causing the service to be ignored by service browsers.
So the answer is, a service with a port of 0 will register without error, but won't work.
Thanks to gaige for the assistance.

Apple AirLocation demo App ranging not shows beacons

I have3 Estimote beacons that can be seen with the App store Estimate App.
Now I am trying to run the Apple demo app AirLocation AirLocate
I have changed the UUID in the APLDefaults.m file to the default Estimote UUID _supportedProximityUUIDs = #[[[NSUUID alloc] initWithUUIDString:#"B9407F30-F5F8-466E-AFF9-25556B57FE6D"]];
I have enabled the Region to start startMonitoringForRegion as this stackoverflow says.
But they are not showing up, have you seen this ? Or am I missing some Estimate specific.
Regards
The problem is that AirLocate was written for iOS7, and in iOS8, the permissions model for iBeacons and other location operations has changed. In order to get the program to work on iOS 8 when compiled from XCode 6, you need to add code that requests permission in your AppDelegate. Like this:
if([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
}
This will prompt the user to authorize location operations including beacons. You also need to edit the info.plist for the app, and add a new string key called NSLocationAlwaysUsageDescription with a value like "This app needs access to location services" so the OS can prompt the user for this permission.
After you run your app, you can check in settings to see if this permission has been granted properly.
Another problem I have noticed in iOS 9 is that the calibration sometimes does not work. Seems to be an NSNumber conversion issue. The following edit in APLCalibrationCalculator.m fixed it:-
//measuredPower = [[sample valueForKeyPath:#"#avg.rssi"] integerValue];
measuredPower = [[sample valueForKeyPath:#"#avg.rssi"] intValue];

What can you do in CoreBluetooth background delegate calls?

I am using Core Bluetooth in my project. I have included Session Backgrounding to avail its background mode functionality. I have observed that the delegate for peripheral disconnection,
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;
gets called in the background mode. However any code I write in this method is not executed except for NSLogs. Can somebody explain exactly what kind of code can be executed here?
My aim is to send this disconnection notification to my server.
Ok it seems it was some issue at my end. According the the documentation your app is woken (in the background) for around 10 seconds when it gets a bluetooth related delegate call.
You can use this time to perform any non view updating task and even request for additional time using beginBackgroundTaskWithExpirationHandler.
My code looks like this.
if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
[self sendEmailInBackground:peripheral]; //Code to send a server request
return;
}
and its working in the background mode. This also works when the phone is in lock state.

UILocalNotification and alertLaunchImage

Hmmm……
A question about UILocalNotification and the notificaton's alertLaunchImage.
My app uses UILocalNotifiaction(s) to get users' attention. As usual, an alert is presented with "Action" and "Close" buttons. When the user taps Action, the image specified by alertLaunchImage is presented. The alertLaunchImage is a screenshot of of one of the views of the app which is shown after the data is initialized when launched normally.
Here are the 3 cases when the notification is delivered:
App is running in foreground - no alert, no launchImage is shown as designed. No problems.
If my app is running in background when the notification is delivered, the launchImage works like a charm. No problems. The launchImage with no app-related data is shown and then the app fills up the data. This part works seamlessly.
However, if the app is not running when the notification is delivered, the sequence is confusing - or I missed something. The app gets launched and shows the alertLaunchImage instead of the Default image. Then is goes thru several other screens (as part of initialization and data processing) before the actual screen (live version of alertLaunchImage) is shown.
This can get very confusing to the user. My question comes in here. How can this be avoided?
R/-
Sam.!
you can try cleaning up the alert view settings in applicationWillTerminate:
According to the UIApplicationDelegate reference applicationWillTerminate::
"This method lets your application know
that it is about to be terminated and
purged from memory entirely. You
should use this method to perform any
final clean-up tasks for your
application, such as freeing shared
resources, saving user data,
invalidating timers, and storing
enough application state to
reconstitute your application’s
interface when it is relaunched"
HTH,
Oded
If your app is launched by a local notification, you will receive that notification in the options passed to -application:didFinishLaunchingWithOptions:. Based on that, you can write code that navigates to the correct screen without animations.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UILocalNotification *localNotification = [launchOptions valueForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotification != nil) {
// startup by local notification
} else {
// normal startup
}
}

How do I run code when a user agent process terminates?

What I want
I want a helper app user agent (LSUIElement in Info.plist is True) to add itself to the login items on terminate.
The Problem
I can't get any code to run before the helper app process terminates.
My "add to login items" code runs fine.
Background
I've got a helper app user agent process that runs all the time
On first launch, it adds itself to login items
If the app was moved, on next login, the helper app process can't be found and so isn't launched
What I've Tried
I wonder if I should subclass NSApplication and override terminate: or stop: and put my code in there, but that seems overkill. Surely there's a better way?
I've tried all these different things in the NSApp delegate:
-(void)applicationWillTerminate:(NSApplication *)sender {
[self addHelperAppToLoginItems]
}
-(void)applicationDidTerminate:(NSApplication *)sender {
[self addHelperAppToLoginItems]
}
-(NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
[self addHelperAppToLoginItems]
}
-(void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
selector:#selector(addHelperAppToLoginItems)
name:NSWorkspaceDidTerminateApplicationNotification
object:nil];
}
-(void)addHelperAppToLoginItems {
// This code never gets called!
}
Why do the NSApplication delegate methods not work with a user agent process?
And how can I get the process to check the login items on terminate?
I'd be very grateful for any help. Thanks!
UPDATE 1 6/2/11
After some further digging, the problem is more that processes never really get quit, it's more common for them to get killed by the OS.
This means when you choose to "Quit" a process in Activity Monitor or you shut down the computer, the terminate delegate methods don't get called.
When the following Applescript is run, the delegate methods do get called:
tell application "System Events"
tell application "LapsusHelperApp"
quit
end tell
end tell
After some further digging, the problem is more that processes never really get quit, it's more common for them to get killed by the OS.
This is because you have sudden termination enabled for your application. It's opt-in, so simply remove that key-value pair from your Info.plist and you will then start getting applicationWillTerminate: messages.
Also, the Terminate button in Xcode (at least in 3.x) always works the same way sudden termination does, so you will never get a applicationWillTerminate: message when terminating your app from Xcode.
By the way:
applicationWillTerminate: is a notification message, so its argument is an NSNotification object, not an NSApplication object.
There is no applicationDidTerminate:. A moment's reflection will reveal why. ☺

Resources