简体   繁体   中英

How do we dispatch Google Analytics events when iOS app goes to the background?

My iOS app has links to Apple's App Store in it and I am trying to track those as events.

The problem is that we can't get my app to properly dispatch the GA events before it goes into the background. We are using iOS SDK v2beta4.

Here is an overview of the code we are using. You can see we've put in a lot of what I call "insurance policy" code because what we think is the correct way is not working. But even the insurance policy code does not always dispatch the events before my app goes into the background. It only works about 50% of the time and the rest of the time I have to return to the app to get the events to dispatch.

We believe the correct way is to dispatch the event in "applicationDidEnterBackground" and to ask the iOS for extra time to do this via "beginBackgroundTaskWithExpirationHandler". We've tried this code on its own without my "insurance policy" code. At least I believe we commented out every line of insurance code correctly.

Note that we set the global variable UIBackgroundTaskIdentifier bgTask; in the AppDelegate.h header file with the code

UIBackgroundTaskIdentifier  bgTask;

Here is the code that we think is the correct way to do this:

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    UIApplication *app = [UIApplication sharedApplication];

    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        [[GAI sharedInstance] dispatch];

        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    });
}

The above code is what we think should work but does not. Note: The App Store is not a usual app, but a website inside an app if that makes a difference.

As an insurance policy we've done a few other things which dispatch the event about 50% of the time:

The first [[GAI sharedInstance] dispatch] is called immediately in the function where tracking has been set

Source code:

- (IBAction)goToAppStore:(id)sender
{    
    ...
    // Tracking
    // Using events (pressing on buttons)

    id <GAITracker> tracker = [[GAI sharedInstance] defaultTracker];

    [tracker sendEventWithCategory:@"App Checkout"
                        withAction:@"Checkout Button Pressed"
                        withLabel:nameApp.text
                        withValue:nil];

    [[GAI sharedInstance] dispatch];
    ...
}

We also put it in "applicationWillResignActive"

- (void)applicationWillResignActive:(UIApplication *)application
{
    ...  
    [[GAI sharedInstance] dispatch];
}

And finally when you completely close the app another GA dispatch is called

- (void)applicationWillTerminate:(UIApplication *)application
{
    [[GAI sharedInstance] dispatch];
}

None of this works 100% of the time. Only about 50% of the time. So we did this: When you re-enter the app (it doesn't matter if from the background or the app has been completely closed) we send a dispatch

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    [[GAI sharedInstance] dispatch];
}

With this last bit the events are dispatched but only if a user returns to my app. Although I am not 100% sure if it is this code that is dispatching the events when I return to the app or a GA default dispatch when I go back to the app.

Use [[GANTracker sharedTracker] dispatchSynchronous:]

dispatch method will perform an async operation. Therefore it will return immediately without waiting for the dispatch operation to be completed. Your app is probably suspended before actual dispatch operation finishes.

-- EDIT --

It looks like dispatchSynchronous: method is gone in the latest version of Google Analytics library. Since GANTrackerDelegate is also gone, as far as I can see, there is no way to find out when a dispatch operation finishes. Therefore I suggest calling endBackgroundTask: method after a predefined timeout. It is not perfect but it is better than calling it immediately after dispatch .

Your code should look like this:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  [[GAI sharedInstance] dispatch];

  double dispatchTimeout = 10.0;  // 10 seconds timeout
  dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(dispatchTimeout * NSEC_PER_SEC));
  dispatch_after(popTime, dispatch_get_current_queue(), ^(void){
    [app endBackgroundTask:bgTask];
    bgTask = UIBackgroundTaskInvalid;
  });
});

as 'dispatch_get_current_queue()' is currently deprecated as of iOS 6, you can now use the following code:

UIApplication *app = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier bgTask;

bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
    [app endBackgroundTask:bgTask];
    bgTask = UIBackgroundTaskInvalid;
}];

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [[GAI sharedInstance] dispatch];

    double dispatchTimeout = 10.0;  // 10 seconds timeout
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(dispatchTimeout * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    });
});

In GoogleAnalytics 3.14 there's dispatchWithCompletionHandler: I'm using it like this:

//track any event here as usual and then call:

GAI.sharedInstance().dispatchWithCompletionHandler({ (_) -> Void in
    UIApplication.sharedApplication().openURL(URL)
})

And it seems to work properly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM