I've been working with Google's Analytics SDK v2beta3 and have everything working except I can't get manual dispatch to work when the app leaves the active state. (fyi, for my app I need to reserve battery power so am only using '[[GAI sharedinstance] dispatch]' to dispatch my event data when the user is finished with the app.)
I've tried several things, but while the dispatch call is reached and run during tracing, it doesn't seem to do anything... no log output (I have debug mode on) and no data uploaded. It should minimally report "GoogleAnalytics 2.0b3 -[GAIDispatcher initiateDispatch:retryNumber:] (GAIDispatcher.m:479) DEBUG: No pending hits." or something of that sort I would think. But nothing in the log and no data sent.
Instead, when the app resumes from background, the hits are then transmitted and I see all the debug statements on my console and data is sent successfully to my Google Analytics account.
Below is my code...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
// set up Google Analytics tracker
[GAI sharedInstance].trackUncaughtExceptions = YES; // automatically track uncaught exceptions with Google Analytics - sent with stack trace.
[GAI sharedInstance].dispatchInterval = -1; // set Google Analytics dispatch off, will do manually when app goes into background.
[GAI sharedInstance].debug = YES; // set debug to YES for extra debugging information.
id<GAITracker> tracker = [[GAI sharedInstance] trackerWithTrackingId:GOOGLE_ANALYTICS_TRACKING_ID_FOR_TEST]; // Create tracker instance.
[tracker setSessionTimeout:600]; // set min time between sessions to be 10 minutes
[GAI sharedInstance].defaultTracker = tracker; // reset the default tracker if needed
[[GAI sharedInstance] setOptOut:NO];
...
}
- (void)applicationWillResignActive:(UIApplication *)application
{
UIDevice * device = [UIDevice currentDevice];
BOOL backgroundTasksSupported = NO;
if ([device respondsToSelector:@selector(isMultitaskingSupported)]) {
backgroundTasksSupported = device.multitaskingSupported;
}
if (backgroundTasksSupported) {
self.uploadAnalyticsBackgroundTask = [application beginBackgroundTaskWithExpirationHandler:^{[self endBackgroundUploadTask];}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // put block on Global run queue...
[[GAI sharedInstance] dispatch]; // for dispatch of collected metric/analysis data...
[self endBackgroundUploadTask];
});
}
else {
[[GAI sharedInstance] dispatch];
}
}
- (void) endBackgroundUploadTask
{
if(self.uploadAnalyticsBackgroundTask != UIBackgroundTaskInvalid) { // if background task running, end it
[[UIApplication sharedApplication] endBackgroundTask: self.uploadAnalyticsBackgroundTask];
self.uploadAnalyticsBackgroundTask = UIBackgroundTaskInvalid;
}
}
The app reaches and executes the '[[GAI sharedInstance] dispatch];' line, but does nothing. I'm quite a newbie with background tasks when the app goes to the background so maybe I'm doing something wrong. But as part of my investigations I've even simplified applicationWillResignActive to this (which is/should be blocking)... but I get the same thing: no debug info and no transmitted data.
- (void)applicationWillResignActive:(UIApplication *)application
{
[[GAI sharedInstance] dispatch];
}
I've tried it with the dispatch interval non-negative (say 15 seconds) and I get regular transmission at the requested interval, but the call to manually dispatch doesn't work.
Calls to manual dispatch in other parts of my code do work. It just seems that it doesn't work when the app is closing down.
Any thoughts advice on what I might have done wrong and how I can fix this?
Unlike previous Google Analytics SDK versions, since v2 the manual dispatch mechanism doesn't run synchronously, i.e. instead of waiting for dispatching to be done, it returns immediately. So if you use dispatch right before becoming inactive, the dispatch won't happen since the application's run queue will be paused before the actual dispatch happens. As a workaround, I'm starting a background task which sleeps for a few seconds and keeps the app running long enough for the dispatch to complete.
Hopefully Google will re-add a dispatchSynchronously
method in future versions of the SDK.
Also, be aware that on applicationWillTerminate
, you only have 5 seconds until the application is killed, so don't wait too long.
- (void)dispatchAndWait:(NSTimeInterval)waitTime {
UIBackgroundTaskIdentifier backgroundTask = 0;
backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// GAI dispatch runs asynchronously and dispatches on the main
// thread, so we're giving it some time to dispatch and keep the
// app running in background by sleeping on a background thread
[[GAI sharedInstance] dispatch];
[NSThread sleepForTimeInterval:waitTime];
[[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
});
}
This, as of August 2013, is the correct answer.
As long as the app was closed normally, i.e. it received a UIApplicationWillResignActiveNotification
, then the hits will be dispatched when the app is next opened.
The reason you aren't seeing this is probably that quitting the app from Xcode does not close it normally. Pressing the home button, shortly followed by Xcode's stop, will close it normally, and it will work.
The issue here is that even though the hits are dispatched, they are discarded by Analytics if they arrive after 4am the following day in the timezone of the Analytics profile. That is a bit thorny, and might justify a solution like Andreas's.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With