I want to track when the user closes the app. For this I send an event to google analytics in applicationWillTerminate. However this event never reaches the server. However the documentation states:
If a user loses network access or quits your app while there are still hits waiting to be dispatched, those hits are persisted in local storage. They will be dispatched the next time your app is running and dispatch is called.
Hence I would assume, that even if it does not manage to dispatch the tracked event in applicationWillTerminate it would do so on restart, after some time. Unfortunately it does not.
Next I tried to call GAI.sharedInstance().dispatch() to force Google Analytics to dispatch the event, but it also did not.
Do I miss something, or is it simply not possible to track events in applicationWillTerminate?
If your application terminates, there is simply no time to make a network connection. applicationWillTerminate is for frontend uses for most occurrences.
You might store a variable in UserDefaults when the application terminates and send the request with the data stored there after the next app launch.
Related
I'm working with the Flurry API for iOS and I've come across a use case that doesn't seem to be supported:
I'm starting a timed event with -logEvent:timed: to track how long a user spends on a view. While the user is on that view a few parameters are being tracked that I plan to pass along to -endTimedEvent:withParameters: when the user navigates away from the view).
Here is the tricky part, if the user backgrounds the app while on the view, Flurry will automatically end the timed event after 10s without setting any parameters. One solution of course is to observe UIApplicationWillResignActiveNotification and call -endTimedEvent:withParameters: myself. However, I'd like to respect Flurry's setSessionContinueSeconds property and not end the event until the session is over. This way if the user returns to the app within 10s they are still under the same event that is tracking their time on the view.
Is there a way to do this?
For instance, is there a delegate method called when the session willEnd/didEnd where I could manually call -endTimedEvent:withParameters: before Flurry does? or alternatively is there a way to append parameters to a timed event while it is active (without ending it). That way when Flurry ends the session, the event already has the parameters set.
1) Flurry has a feature (only on iOS) to allow sessions to continue into the background that you can try for this use case.
[Flurry setBackgroundSessionEnabled:Yes]
You can find more details about these and other methods in the Analytics readme document that is included with our SDK.
[Flurry setBackgroundSessionEnabled:(BOOL)backgroundSessionEnabled];
This option is disabled by default. When enabled, Flurry will not finish the session if the app is paused for longer than the session expiration timeout. The session report will not be sent when the application is paused and will only be
sent when the application is terminated. This allows for applications that run in the background to keep collecting events data. The time application spends in the background contributes to the length of the application session reported when the application terminates.
[Flurry pauseBackgroundSession];
This method is useful if setBackgroundSessionEnabled: is set to YES. It can be called when application finishes all background tasks (such as playing music) to pause the session. A session report is sent if setSessionReportsOnPauseEnabled is set to YES. If the app is resumed before the session expiration timeout, the session will continue, otherwise a new session will begin.
2) You can keep the data in an array and place the parameters into a separate event that triggers after the timed event instead.
In my app I need to call an API service when there is significant change in the user's location. So I'm using startMonitoringSignificantLocationChanges method and handling the API call in the corelocationdelegate method(locationManagerdidUpdateLocations). When app is in background or active state I can call API without any hesitation.
The problem comes when app is in suspended state. I know when SignificantLocationChange is triggered iOS wakeup the terminated app gives small amount of time to manually restart location services and process the location data and in this case we get call back to the delegate method, do I need to use background task to call the API or API call should be made as before(as incase of active state). Currently the API call takes around 6-7 seconds. If it takes more than 10 seconds how do I handle the API call?
One more question, is there any problem if I don't call stopMonitoringSignificantLocationChanges? as my app always need to call the API when there is significantLocation change in user's location.
When you say "...I need to call an API service..." are you talking about making a network call to a server? If so, then yes, you should ask for background time.
I seem to remember you only have about 30 seconds of background time, and network calls can take unpredictable amounts of time.
You want to make the call beginBackgroundTaskWithExpirationHandler, and then call endBackgroundTask once your server call is complete.
In my app I use background services so the method applicationWillTerminate: will not get called when the user terminated the app. Instead the method applicationDidEnterBackground: gets called when the user pushed the app into to background and when the user terminates the app completely.
The problem I am having is that I need to be able to distinguish between when the user has pushed the app into the background and when he actually quits the app because I have different code that needs to be fired for both events.
Is this possible in my case?
The -applicationWillTerminate: method is called when the system is "nicely" terminating the application in an orderly fashion (ie, it's not being backgrounded for pending tasks or it told the OS those tasks are completed). This is distinctly different from "the user forcibly terminated the app", in which case your app won't receive any messages because it's just been summarily executed by a bullet to the head.
Are you certain you're correctly / fully participating in the background services? That is, are you certain you're correctly telling the system you've finished? You should edit your question and post the relevant backgrounding code. For example, if you're using -beginBackgroundTaskWithExpirationHandler:, the docs say:
If you do not call endBackgroundTask: for each task before time expires, the system kills the app.
...could this be your issue?
This is maybe not possible, but the only way I can imagine to distinguish between both of them is waiting to the next event.
When the next event is a "start", you know that the last event was a kill.
When the next event is a "foreground", you know that the last event was a background.
This implies some processing at server, I know.
Hope this helps.
I've written a geo-fencing iOS app that uses startmonitoringsignificantlocationchanges to trigger an action that requires network query. It does not work reliably because sometimes the network delay causes the app to be terminated. I do realize that the documentation says, iOS may terminate the app if I try to do network query that takes too long:
"If you leave this service running and your application is subsequently suspended or terminated, the service automatically wakes up your application when new location data arrives. At wake-up time, your application is put into the background and given a small amount of time to process the location data. Because your application is in the background, it should do minimal work and avoid any tasks (such as querying the network) that might prevent it from returning before the allocated time expires. If it does not, your application may be terminated."
Is there an alternative way to start network query in the background when iOS launches my app as a result of entering a region?
Yes, you have to call beginBackgroundTaskWithExpirationHandler. See here:
http://www.mindsizzlers.com/2011/07/ios-background-location/
I have seen several ways to "make sure that my app is shown again after a phone call which my app has initiated has ended" however that isn't what I want -> what I am looking for is a way to, say my app is currently running in the background doing network communications and someone calls me, I would like my app to either be able to "detect when the phone call has ended and resume my network communications" and/or "launch/resume my app back into the foreground when the phone call has ended". Is there any way to accomplish something like this and how?
This is unsupported within iOS.
From the docs:
http://developer.apple.com/iphone/library/documentation/iphone/conceptual/iphoneosprogrammingguide/BackgroundExecution/BackgroundExecution.html
http://developer.apple.com/iphone/library/documentation/NetworkingInternet/Reference/CTCallCenter/Reference/Reference.html#//apple_ref/doc/uid/TP40009604
If your application is active when a call event takes place, the system dispatches the event to your handler immediately. However, call events can also take place while your application is suspended. While it is suspended, your application does not receive call events. When your application resumes the active state, it receives a single call event for each call that changed state—no matter how many state changes the call experienced while your application was suspended. The single call event sent to your handler, upon your application returning to the active state, describes the call’s state at that time.
The best you can do is detect phone calls while your app is open.
applicationWillResignActive is called when the app is about move from active to inactive state. So if you get a call, this method is called before your app is backgrounded.
Use this method to pause any ongoing tasks and save any settings you need.
applicationDidBecomeActive is called when you app becomes active again.
Use this method to resume any tasks that were suspended. Example would be resuming your network communications