iOS Location update even app is not running (like find my iphone) - iphone

I want to write location tracking app like "find my iphone" that runs in foreground,background and even terminating ( not running). Location will be sent to my server periodically time. I have searched in google and read many many documents,tutorials comments, codes about this topic. Then I have found this tutorial. But in this tutorial, location is sent to ".txt" file in foreground and background not terminating... I mean, when the app is killed, it is not relaunched in the background to send location ".txt" file .. So I have added and updated some codes to send location when it is not running.. However, I didn't do it... I mean, when I kill(close) the app in multitasking (double tapping home button), it is not sending to location...
Can you help me, how can I fix this problem?
Thanks in advance
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
[self log:[NSString stringWithFormat:#"Background location %.06f %.06f %#" , newLocation.coordinate.latitude, newLocation.coordinate.longitude, newLocation.timestamp]];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
id locationValue = [launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey];
if (locationValue)
{
// create a new manager and start checking for sig changes
[self log:#"didFinishLaunchingWithOptions location key"];
m_locManager = [[CLLocationManager alloc] init];
[self log:#"didFinishLaunchingWithOptions created manager"];
m_locManager.delegate = self;
[self log:#"didFinishLaunchingWithOptions set delegate"];
[m_locManager startMonitoringSignificantLocationChanges];
[self log:#"didFinishLaunchingWithOptions monitoring sig changes"];
return YES;
}
[self log:#"didFinishLaunchingWithOptions"];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
[self log:#"applicationWillResignActive"];
NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setBool:viewController.m_significantSwitch.on forKey:#"significant"];
[userDefaults synchronize];
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
[self log:#"applicationDidEnterBackground"];
[m_locManager startMonitoringSignificantLocationChanges];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
[self log:#"applicationWillEnterForeground"];
[m_locManager stopMonitoringSignificantLocationChanges];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
[self log:#"applicationDidBecomeActive"];
if (![window.subviews count])
{
// Add the view controller's view to the window and display.
[window addSubview:viewController.view];
[window makeKeyAndVisible];
NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
viewController.m_significantSwitch.on = [userDefaults boolForKey:#"significant"];
if (viewController.m_significantSwitch.on)
[viewController actionSignificant:nil];
}
}
- (void)applicationWillTerminate:(UIApplication *)application {
[self log:#"applicationWillTerminate"];
[m_locManager startMonitoringSignificantLocationChanges];
}

That is not correct, when your app is terminated it can still monitor significant location updates.

My friend , you are on wrong way. Actually there is no any way to do a task after killing of app in iOS. You can read about this here in Apple documentation.
Find My iPhone - It is an Apple App and they are using private api's to make this possible. And these type of features not available for general purpose developer programming.
So please don't go on this path.All will go in vain.
Hope this Helps you !

You cannot run anything when the app is killed, except you can recieve push notifications or UILocalNotifications. You could try duplicating UILocalNotifications functionality and do your stuff even when your app is killed/in bg/. BTW this is a complex thing and you could do more digging about ios7 background tasks or something.

This may help you.
Getting the User’s Location
see the section Starting the Significant-Change Location Service. It says
If you leave the significant-change location service running and your iOS app is subsequently suspended or terminated, the service automatically wakes up your app when new location data arrives. At wake-up time, the app is put into the background and you are given a small amount of time (around 10 seconds) to manually restart location services and process the location data.

Related

How to determine if an app is returning from a phone call or resuming from background?

I make phone call from my application using:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"telprompt://XXXXXXXXXX"]];
When the user ends the call, the default Apple-provided Phone app goes to the background and my application resumes focus. This happens automatically.
Now here's what I want: I'd like to call a method every time (and only when) the user returns from a call.
I tried calling this method from applicationWillEnterForeground: or applicationDidBecomeActive: but these callbacks are fired at other times when the application is being launched from the background state(which I dont want).
I'd like to determine if my application is being launched from the background state or if it is returning from a phone call so I can perform a certain task only in the former case and not latter. Any ideas?
----EDIT----
Here's how I finally did it:
See: CallStateDisconnected only detected for incoming calls, not for calls made from my app
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self listenForCalls];
}
- (void)listenForCalls {
self.callCenter = [[CTCallCenter alloc] init];
self.callCenter.callEventHandler = ^(CTCall* myCall) {
NSString *call = myCall.callState;
if([call isEqualToString:CTCallStateDialing]) {
//do ur stuff
}
};
}
You Can use telephony framework, Which provides you call states to determine the state of phone.
You can find out detail from here:
http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Reference/CTCall/Reference/Reference.html#//apple_ref/doc/uid/TP40009590
Why not save a flag indicating that your app sent the user to the phone call. When your applications becomes active, if the flag is set, do the return from phone call method.
ex.
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"DidStartPhoneCall"];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"telprompt://XXXXXXXXXX"]];
Then something like,
-(void)applicationDidBecomeActive {
BOOL activeFromCall = [[NSUserDefaults standardUserDefaults] objectForKey:"DidStartPhoneCall"]
if(activeFromCall && [activeFromCall boolValue] == YES) {
// do your method
}
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:#"DidStartPhoneCall"]; // reste flag
}

How to create a custom alarm which can be set for random days in a week without using local notifications?

I have studied some of the following questions, that are::
1.) How to set alarm for selected days in iphone?
2.) iPhone alarm using repeated local notifications
3.) How to set the alarm in iPhone and save in local notification?
but they all are using local notifications. I am facing problem with local notification as I have to use three buttons on an Alarm View which are: Snooze, Ignore and Okay. I have to perform custom actions on each button click.
Please help me with this stuff.
Suggestions accepted.
Thanks in advance.
Kuldeep.
In you app delegate...
- (void) presentWidget: (NSString*)theDisplayedText {
BOOL widgetIspresent = [WidgetVC widgetIsCurrentlyPresented];
if (!widgetIspresent) {
WidgetVC *widgetVC = [[WidgetVC alloc] initWithNibName:#"WidgetVC" userInfoString:theDisplayedText bundle:nil];
widgetVC.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
widgetVC.userInfoStr = theDisplayedText;
[mainScreenManager presentViewController:widgetVC animated:YES completion:nil];
}
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotif) {
NSLog(#"Recieved Notification didFinishLaunchingWithOptions %#",localNotif);
NSString *theDisplaytext = [localNotif.userInfo valueForKey:#"someKey"];
//here we have to handle whatever notification was pressed - that might also be an old aready passed one
//this all is checked when the widget opens - it will show if the notification is OK or too old
[self presentWidget: theDisplaytext ];
} else {
//so we started the app normally, not via local notification
[self presentWidget];
}
return YES;
}
// Handle the notificaton when the app is running
- (void)application:(UIApplication *)app didReceiveLocalNotification:(UILocalNotification *)localNotif {
// Handle the notificaton when the app is running
NSLog(#"Recieved Notification didReceiveLocalNotification %#",localNotif);
NSString *theDisplaytext = [localNotif.userInfo valueForKey:#"someKey"];
[self presentWidget: theDisplaytext];
}
You need a way to start the UIViewController for the widget, I just created a mainScreenManager helper.
So on the widgetVC you have your "Snooze" and "OK" while the "Ignore" is just the ignoring of the notification itself.
Hope this gets you on an usable track...
ps I ported my app from Android to iPhone, that's why I used the name "widgetVC" for this screen. On Android it is implemented as a widget. Hope no iPhone lover feels offended :-)

Creating a Time Based Reminder App in iPhone

I am working on time based reminder App. in which the user enter his reminder and time for the reminder. The problem is that how to continuously comparing the current time with the user defined time. Any sample code will greatly help. because i am stuck on this point.
Comparing the current time vs. the user defined one is not the right design pattern.
UIKit offers the NSLocalNotification object that is a more high-level abstraction for your task.
Below is a snip of code that create and schedule a local notification at the choosen time:
UILocalNotification *aNotification = [[UILocalNotification alloc] init];
aNotification.fireDate = [NSDate date];
aNotification.timeZone = [NSTimeZone defaultTimeZone];
aNotification.alertBody = #"Notification triggered";
aNotification.alertAction = #"Details";
/* if you wish to pass additional parameters and arguments, you can fill an info dictionary and set it as userInfo property */
//NSDictionary *infoDict = //fill it with a reference to an istance of NSDictionary;
//aNotification.userInfo = infoDict;
[[UIApplication sharedApplication] scheduleLocalNotification:aNotification];
[aNotification release];
Also, be sure to setup your AppDelegate to respond to local notifications, both at startup and during the normal runtime of the app (if you want to be notified even the application is in foreground):
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UILocalNotification *aNotification = [launchOptions objectForKey: UIApplicationLaunchOptionsLocalNotificationKey];
if (aNotification) {
//if we're here, than we have a local notification. Add the code to display it to the user
}
//...
//your applicationDidFinishLaunchingWithOptions code goes here
//...
[self.window makeKeyAndVisible];
return YES;
}
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
//if we're here, than we have a local notification. Add the code to display it to the user
}
More details at the Apple Developer Documentation.
Why not use NSLocalNotification which you can set for a specified time, much like a calendar event. Alternatively you can add calendar events to the users calendar with EKEventKit
Tutorial for local notifications.
Tutorial for event kit.

iPhone performSelectorInBackground

I have this problem:
Here is a part of my appDelegate file where I create a "performSelectorInBackground" method.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self addSplash];
[self getLocation];
[self performSelectorInBackground:#selector(backgroundOp) withObject:nil];
return YES;
}
First I add some splash screen, the I get a location and the call background method.
This is content of background method:
- (void) backgroundOp
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self createEditableCopyOfDatabaseIfNeeded];
[self initTempData];
[self initApp];
[self checkDataVersion];
}
[self setAppStrings];
[self performSelectorOnMainThread:#selector(resultOp) withObject:nil waitUntilDone:YES];
[pool release];
}
I download some data, check version of data, setup strings for application and the call on main thread method to create a tab bar controller code here:
- (void) resultOp
{
tabBarController.delegate = self;
[self.window addSubview:tabBarController.view];
[self addTabBarArrow];
[self.window makeKeyAndVisible];
[self removeSplash];
}
Here I create a tab bar controller and remove splash screen. Then start my firstViewController.
Problem is that in my firstViewController I show a current location, but it is wrong. Sometimes is correct but very often is wrong.
Where is a problem ? Is there any option how to check if background thread end ? Or something other solution for my problem (I need only: show splash with activity indicator and some messages (this messages are changed in method e.g. init, get location etc.), then I need get location, the remove splash and show firstViewController) ... thanks a lot
Edit: Here is code for location:
- (void) getLocation
{
splashScreenController.splashLabel.text = #"Localization ...";
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kDistanceFilter;
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
[locationManager startUpdatingLocation];
}
Keep in mind, that the longer the location update runs, the more accurate it gets. The first 'hit' for the location isn't always the best one (most of the time it is the wrong one).
Maybe you could show your code where you have the events of the CLLocationManager.
Also, how much is the wrong position off of the right position? I think the AGPS thing first quickly checks its location by using WiFi hotspots nearby and after that gets more accurate by using the GPS chip.
Wherever you are using the location you acquire (which I can't really see from the code you posted), you should have checks on the horizontalAccuracy property of the newLocation you are receiving (and verticalAccuracy as well if altitude matters). You can say something like
if(newLocation.horizontalAccuracy < 100) {
//do something with newLocation
//because it is accurate to 100 meters
}
If you do not do these types of checks, you can get some really inaccurate locations, up to three or four kilometers from your real location at first.
Also, when using multiple threads, data integrity can sometimes become a problem. You need to make sure that variables are not being accessed and changed at the same time in multiple methods, or who knows if you will get the correct output.
Also, it is important to note that all of the methods called within backgroundOp will also be preformed in the background, even without explicitly calling them that way. Use
[self performSelectorOnMainThread:foo withObject:foobar waitUntilDone:NO];
to return to the main thread.
Edit:
viewDidLoad {
[super viewDidLoad];
iterations = -5;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation
*)newLocation fromLocation:(CLLocation *)oldLocation {
iterations++;
if(iterations > 0) {
if(newLocation.horizontalAccuracy < 50) {
//do something with location with radius of uncertainty
//of less than 50
}
}

iphone Launch Options

im not getting any launch options after a push notification; heres the code i have but non of the NSLogs seem to print in the debug area.
UILocalNotification *localNotif =
[launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (localNotif) {
NSString *itemName = [localNotif.userInfo objectForKey:#"aps"];
NSLog(#"Custom: %#", itemName);
} else {
NSLog(#"//////////////////////////");
}
when i open the app (via pressing view on the push notification) it goes to the didReceiveRemoteNotification script, im not sure if thats meant to happen..
thanks for reading.
Your application receives push notifications through multiple paths, depending on the state of your app when it is received.
If your app is not launched (not even suspended in background), the launchOptions will contain the notification payload (key UIApplicationLaunchOptionsRemoteNotificationKey).
If it is already running or suspended in background, the app will receive the notifications via application:didReceiveRemoteNotification: in your application delegate.
The process is the same for local notifications (UIApplicationLaunchOptionsLocalNotificationKey in application:didFinishLaunchingWithOptions: and application:didReceiveLocalNotification:)
an error spotted:
NSDictionary *remoteNotif = [launchOptions objectForKey:
UIApplicationLaunchOptionsRemoteNotificationKey];
If you want to receive the remote notification, NSDictionary should be used not UILocalNotification
The remote notification is a payload, containing arguments, not a local notification. You might want to look at this url question:
Crash when handling remote notification when app not running
If you want to do local notification, change it like Ludovic's suggestion
The answers given above are correct. I largely use the following snippet in my application:didFinishLaunchingWithOptions:
if let remoteNotifPayload = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as? [AnyHashable: Any] {
notificationsController.didReceiveRemoteNotification(with: remoteNotifPayload)
}
If you want a local notification (I assume with your var name) replace UIApplicationLaunchOptionsRemoteNotificationKey by UIApplicationLaunchOptionsLocalNotificationKey and this should work.
(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSLog(#"Alert message: %#",[[userInfo valueForKey:#"aps"] valueForKey:#"alert"]);
}
You can use NSUserDefaults to do the trick. In your AppDeligate.m, set a bool to YES in the first time. So after that it never gets to NO.
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//add this if loop
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"HasLaunchedOnce"])
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"HasLaunchedOnce"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}