Recording events with Flurry after app was launched due to a monitored region being entered - ios

The scenario is as follows. I have an iOS app that uses the CLLocationManager's region monitoring feature to notify the app when a predefined geographic region is entered. The way region monitoring works, the app can be notified of a user entering a region, even if the app was previously terminated. Basically, the operating system will launch the app (without bringing it to the foreground), when the region is entered, and gives the app a chance to respond to the region being entered.
What I am trying to do is log an event using Flurry when the region is entered. Currently, it does not seem to be working, as the events are not showing up in Flurry, even after several days. I should note that I have tested both i) that Flurry event logging is otherwise working OK when the app is launched as normal by the user and ii) that my app is indeed receiving the region entered and exited events (I use local notifications each time the region is entered or exited).
My suspicion is that it has something to do with the application delegate lifecycle differing when the app is launched as a result of entering a region versus when the app is launched as a result of the user starting it. My first suspicion was that application:didFinishLaunchingWithOptions: was not called when the app was launched in the background. Because my call to [Flurry startSession:#"my_key"] is in the application:didFinishLaunchingWithOptions: method, this would have explained things. However, the Apple documentation for startMonitoringForRegion:desiredAccuracy: suggests that application:didFinishLaunchingWithOptions: is in fact called:
If you begin monitoring a region and your application is subsequently
terminated, the system automatically relaunches it into the background
if the region boundary is crossed. In such a case, the options
dictionary passed to the application:didFinishLaunchingWithOptions:
method of your application delegate contains the key
UIApplicationLaunchOptionsLocationKey to indicate that your
application was launched because of a location-related event.
Although I'm using startMonitoringForRegion: and not startMonitoringForRegion:desiredAccuracy: (deprecated), I'm assuming that both call application:didFinishLaunchingWithOptions:. I then read a note in the Flurry documentation about startSession: (emphasis mine):
This method serves as the entry point to Flurry Analytics collection.
It must be called in the scope of applicationDidFinishLaunching. The
session will continue for the period the app is in the foreground
until your app is backgrounded for the time specified in
setSessionContinueSeconds:. If the app is resumed in that period the
session will continue, otherwise a new session will begin.
Note:
If testing on a simulator, please be sure to send App to background via home button. Flurry depends on the iOS lifecycle to be complete for full reporting.
So, my suspicion is that even though I am testing on a real device, the app never gets "sent to the background" because when it launches it never enters the foreground to begin with. Can anyone clarify whether this is the reason for my logged events never showing up, or whether there is perhaps some other reason? And, is there a workaround for this?

So I contacted Flurry support and this is what I heard back:
So, at present its not possible to record / log events while the app is in the background.
Our engineering team is working on a solution to this and this should be available in one of the future versions of our SDK, in probably a months time.
So I guess we'll wait and see.

Related

Implementing Periodic Location Updates in iOS even if app gets terminated

My application requires periodic location updates (every 10 minutes). In foreground and background (app not terminated) the application is working correctly. But the problem starts to occur when the app is terminated by the user.
I tried using this tutorial http://mobileoop.com/getting-location-updates-for-ios-7-and-8-when-the-app-is-killedterminatedsuspended .
It works only when user's location is changing because of startMonitoringSignificantLocationChanges. But I need locations in terminated state even if user is not changing its location.
Also, I have tried most of the stackoverflow questions but most of them gets satisfied with startMonitoringSignificantLocationChanges. But in my case it won't be enough to fulfil the application needs.
If a user terminates the app the system no longer grants it the same privileges. Background fetch operations and background location will not get executed until the user decides to start up your app again. The system recognizes this a user choice to not have this app running in any way again.
This isn't like the world of Android where an app can do as it pleases. Apple prefers user choice over what an app developer wants. This is of course good and bad as a developer. You need to provide the user with useful information about what your app is doing in the background so that they will allow it to run without terminating it. If they do terminate it, there is nothing that you can do.

How does the Navita TEM app get call log information?

How does Navita https://itunes.apple.com/us/app/navita-t.e.m.-personal/id590228620?mt=8
manage to display a call log?
If I swipe the app out of the task manager then it misses the calls, this indicates that it must presumably be using CTCallCenter's callEventHandler and is creating its own call log by saving the time/duration in response to the callEventHandler callbacks.
However if that is the case then how does it manage to do this in the background? I was under the impression that callEventHandler can only be used by apps in the foreground and not in the background?
The app is using location services, however even after disabling this it was still able to get information about the calls (provided the app isn't suspended). I though it might be using background location updates to keep itself primed to receive callEventHandler callbacks but apparently not.
The Navita app is additionally able to display call time and call duration.
The bounty will be awarded to an answer which contains sufficient, accurate and detailed information that enables me to emulate the behavior of the Navita app, specifically I must be able to write an app that can obtain the time and duration of a phone call that occurred while the app was not in the foreground, while the device's location services was turned off, and after the app had been in the background longer than the ~3 minutes granted by using beginBackgroundTaskWithExpirationHandler:
Here is what I observe with the Navita app that I want to be able to reproduce:
1) Run app
2) Task away from app
3) Go to device settings, privacy, and turn off Location Services.
4) Go to device settings, privacy, background app refresh and turn off for the app
5) Wait > 10 minutes to make sure the app is not still in the background as a consequence of using beginBackgroundTaskWithExpirationHandler:
6) Call the device from another phone, answer the phone call, then hang up.
7) Launch the app again and display the call time and duration
(This is iOS7 and unjailbroken)
Here is what I've found from Navita TEM disassembly and it's resources.
Application uses two background modes - location and audio. You can see it in the Info.plist file. When you enable phone calls logging application will also enable "alerts" and "Real-time" switches. When "alerts" enabled application infinitely loops in background "bg-sound.mp3" file which has no sound, it's just silence. Because of that it doesn't use hacks like this one How to get a call event using CTCallCenter:setCallEventHandler: that occurred while the app was suspended? . It's similar trick to location used in order to keep the app running in background and receive phone call events. Somehow this was not rejected from the AppStore.
If you are observing the call center while the app is in the background you get a set of updates when the app is brought back to the foreground. This set of data may not be as accurate as if the app had been mostly in the foreground but it does include quite a bit of info.

iOS how to detect when app was removed from process

What is the delegate method for detecting when application was closed.
I mean when user tap this button:
I know about method below:
- (void)applicationDidEnterBackground:(UIApplication *)application;
- (void)applicationWillEnterForeground:(UIApplication *)application;
But they work not as I expected in my case. For example I have used my app and I have navigated to some screen. In case when I lock screen and go back to app the app calls applicationWillEnterForeground but I don't need this, because I am still on this view (for example Test Screen View)and I don't need to check any changes. But in case if my app closed I begin to navigate from start app for example Home Screen. So if my app was closed and I am on Home Screen I need to check if in previous time I had some actions (for example if I passed test on Test Screen View) and present this view controller (ONLY IN CASE IF I CLOSED APP NOT JUST LOCKED IT OR ENTER BACKGROUND).
Thanks for help.
You can't detect this. From the iOS App Programming Guide ("App Termination" heading):
Important: The applicationWillTerminate: method is not called if your app is currently suspended.
Even if you develop your app using iOS SDK 4 and later, you must still
be prepared for your app to be killed without any notification. The
user can kill apps explicitly using the multitasking UI. In addition,
if memory becomes constrained, the system might remove apps from
memory to make more room. Suspended apps are not notified of
termination but if your app is currently running in the background
state (and not suspended), the system calls the
applicationWillTerminate: method of your app delegate. Your app cannot
request additional background execution time from this method.
You can't. When your app is killed in this manner, it is not told anything. The app is killed by the OS with no warning of any kind.
When your app enters the background, you have no way to know if will be started fresh or simply return to the foreground. Therefore you must properly handle things when the app enters the background.
When the app starts again, restore whatever state you need.
On iOS, you cannot check for that. That is: the process is SIGKILL'ed. One way I know that might be able to work relies on the fact that to kill an app, one has to suspend it first by pressing the home button.
Hence, you can gather your actions as the user uses the app, commit it to a saved place when the user suspends the app. If the user resumes, reset the list and start gathering info again. However, if the user suspends the app and you never get a resume, on the next app start, you can read the list and recover from there.
HTH
You can implement the -applicationWillTerminate: method of your UIApplicationDelegate delegate to respond to termination events. However, it's not guaranteed to be called in all cases, so you should not rely on it being called. According to the iOS App Programming Guide:
If your app is running (either in the foreground or background) at termination time, the system calls your app delegate’s applicationWillTerminate: method so that you can perform any required cleanup. You can use this method to save user data or app state information that you would use to restore your app to its current state on a subsequent launch. Your method has approximately 5 seconds to perform any tasks and return. If it does not return in time, the app is killed and removed from memory.
Important: The applicationWillTerminate: method is not called if your app is currently suspended.

Will ios terminate the app running in background after a specific time?

I am using core location framework inside my application and I set the location string in UIBackgroundMode or Required background modes(in Xcode 4.2) for getting the updated location from didUpdateToLocation method when app is running in background and also sending this updated location to server by hitting the specific link inside didUpdateToLocation method of core location framework.
My question is that will the app be terminated after some time when running in background or not?
No, there is no specific time defined for this.But app will definitely terminate based upon certain parameter - battery drain, memory footprint issue etc.
In developer documentation it is clearly mentioned - "The system keeps suspended apps in memory for as long as possible, removing them only when the amount of free memory gets low. Remaining in memory means that subsequent launches of your app are much faster."
Go through this for complete details -
http://developer.apple.com/library/ios/#DOCUMENTATION/iPhone/Conceptual/iPhoneOSProgrammingGuide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html
I am sure it is not useful for the author because the question was asked in June 2012 and I am giving an answer in June 2019. This answer maybe is useful for other users.
I am posting this answer because Everyone is said that it is OS default behaviour, We can not change it....bla....bla.
Recently, I was working with the same requirement. After 2-3 week hard
work, I did it. For other users, I create a helper class for it. My
app will never be killed by OS until the location tracking enabled.
You can also verify that OS will never kill this app tracking app
Use HSLocationManager for infinite location tracking in the active and inactive state.
Refer my app which is available in the app store(App will never kill by OS if location tracking is enabled)
Location manager that allows getting background location updates every
n seconds with desired location accuracy.
Advantage:
OS will never kill our app if the location manager is currently
running.
Give periodically location update when it required(range is between 2 -
170 seconds (limited by max allowed background task time))
Customizable location accuracy and time period.
Low memory consumption(Singleton class)
iOS app may get terminated due to following reasons:
Watchdog Timeout
As you’re probably aware, since iOS 4.x, most of the time when you
quit an iOS app, the app isn’t terminated – instead, it’s sent to
the background.
However, there are times when the OS will terminate your app and
generate a crash log if the app didn’t respond fast enough. These
events correspond with the implementation of the following
UIApplicationDelegate methods:
- application:didFinishLaunchingWithOptions:
- applicationWillResignActive:
- applicationDidEnterBackground:
- applicationWillEnterForeground:
- applicationDidBecomeActive:
- applicationWillTerminate:
In all of the above methods, the app gets a limited amount of time
to finish its processing. If the app takes too long, the OS will
terminate the app.
User Force-Quit
iOS 4.x supports multitasking. If an app blocks the UI and stops
responding, the user can double-tap the Home button from the Home
screen and terminate the app.
Note: You may have noticed that when you double-tap the Home button,
you also get a list of all the applications you’ve run in the past.
Those apps are not necessarily running, nor are they necessarily
suspended.
Usually an app gets about 10 minutes to stay in the background once
the user hits the Home button, and then it gets terminated
automatically by the OS. So the list of apps that you see by
double-tapping the Home button is only a list of past app runs.
Low Memory Termination
When subclassing UIViewController, you may have noticed the
didReceiveMemoryWarning method.
Any app that is running in the foreground has the highest priority in
terms of accessing and using memory. However, that does not mean the
app gets all the available memory on the device – each app gets a
portion of the available memory.
When total memory consumption hits a certain level, the OS sends out a
UIApplicationDidReceiveMemoryWarningNotification notification. At the
same time, didReceiveMemoryWarning is invoked for the app.
At this point, so that your app continues to run properly, the OS
begins terminating apps in the background to free some memory. Once
all background apps are terminated, if your app still needs more
memory, the OS terminates your app.
I have seen that the background location updates will work for several hours. But if I go to a place without reception the device will stop to send GPS updates it wont start when I go to a place with reception. This occurs after approximately 30min.
But if I add this, in iOS6, the app won't terminate
[locationManager setPausesLocationUpdatesAutomatically:NO];
Quick answer is pretty much no. Read below though for in depth.
Since multitasking has been enabled on iOS devices that a)your app gets allocated amount of memory and b)the device limits the amount of tasks, that is applications using memory, that occur at any given time. If you take an iOS device and open several apps you'll begin to notice that the app you opened first may have been terminated and reload from the viewDidLoad.
Generally it's safe to say if your app is a recently opened app (or even on a phone where someone clears the multitasking menu often) that the device will not terminate your application in the background.

If background applications can't launch automatically how does Cardcase launch on a location change?

The Cardcase application lets you know if you approach a shop which you have a previous relationship with (if you've set up a tab for payments there etc.).
If background running applications cannot be started automatically on device boot, how does this app therefore work?
Edited to make my question clearer: I am not asking how to monitor for location changes or how to monitor for location changes in the background. My question is, if the user install this app, then adds some tabs for some locations, then they reboot their iPhone, then how can this app subsequently notify them when they approach a location if application launch on boot is not supported?
Must this application (and indeed any other application) be dependent upon it being launched explicitly by the user following every device reboot?
You can do this with region monitoring. You register regions that you would like to monitor with this method on CLLocationManager:
- (void)startMonitoringForRegion:(CLRegion *)region desiredAccuracy:(CLLocationAccuracy)accuracy
Then even if your app is not running, it will be launched in the background as the user enters or leaves the region.
From Apple's docs:
If you begin monitoring a region and your application is subsequently
terminated, the system automatically relaunches it into the background
if the region boundary is crossed. In such a case, the options
dictionary passed to the application:didFinishLaunchingWithOptions:
method of your application delegate contains the key
UIApplicationLaunchOptionsLocationKey to indicate that your
application was launched because of a location-related event. In
addition, creating a new location manager and assigning a delegate
results in the delivery of the corresponding region messages.
EDIT
Just tested this with my own app. Rebooted my phone before leaving the office, and the app was launched on my drive home as usual. So yes, this definitely survives a reboot.
Hope that helps.
This works for geo-fencing apps (apps that use startMonitoringForRegion).
My guess is that when you install apps using this class, the responsible iOS framework automatically registers an launchd script for the app background service startup inside iOS.
Of course this is all done automatically as you don't have fine control on iOS launch services unless you're jailbroken.
You can use the startMonitoringForRegion on your app, jailbreak your device and check on launchd to check how this works under the hood.

Resources