Support for use in Background Agents like ScheduledTask and AudioPlayerAgent

Jun 25, 2013 at 9:19 AM
Hi,

I'm currently working on an app that uses both ScheduleTask and AudioPlayer. I think it would be helpful to enable to track things that are going on in those as well.

Right now I can't add the dll to Background Agents, because of the usage of "MessageBox" and also the ApplicationService class that are used.

Maybe you could (with help if required), split the project in two. One that enables the automatic things like Exception Tracking and Resume Suspend logging things (and probably some other things as well). And another project that can be used from background agents, and as such provides the basic implementation where the other project builds on.

Does this sound interesting to you, or not?

Best,

Mark Monster
Coordinator
Jun 25, 2013 at 4:05 PM
Thanks Mark for reporting this! Do hitting these APIs from a background agent trigger runtime errors or are you seeing compile or cert issues?

Assuming that the issue is simply that these APIs must be avoided at runtime, the use of MessageBox should be easy to avoid as it is only invoked when calling Tracker.RequestAppOptOutAsync directly from your app.

PhoneApplicationService is harder to avoid since it is called directly from EasyTracker. Perhaps I can make this conditional; I will investigate.

Regarding your suggestion, this is actually already architected in the way you suggest where the EasyTracker class adds all the extra "helper" features and builds on the core tracker functionality (implemented in other classes which have no knowledge of EasyTracker). The only difference is they happen to be in the same project. Therefore, as an immediate solution, you could avoid using EasyTracker altogether and create your own Tracker object instance to use directly.
Coordinator
Jul 4, 2013 at 10:14 PM
Mark, I just released an update (v.1.0.17) that may solve this issue. In analytics.xml you can now set:
<autoAppLifetimeTracking>false</autoAppLifetimeTracking>
<autoAppLifetimeMonitoring>false</autoAppLifetimeMonitoring>

This will prevent the code path that uses the ApplicationService class. Let me know if you still encounter issues getting it to work.
Jul 5, 2013 at 7:58 AM
Hi Tim,

I will give it a try next week (no time this weekend). Though I'm not sure what the static analysis will say. Because code that's in the dll but not used will still cause the certification scan to fail.

I will let you know!

Thanks,

Mark Monster
Nov 18, 2013 at 12:22 PM
Hi,

I tried to set the autoAppLifetimeTracking and autoAppLifetimeMonitoring to false and tracking worked perfectly from a background agent :)

Thanks for that tip. You should maybe put it in the description/documentation, cause I had a hard time finding this page.
Nov 18, 2013 at 12:30 PM
Please be aware that you won't be able to submit this to the store. Your background agent references code that's not allowed on the background agent. I made a pull-request ( https://googleanalyticssdk.codeplex.com/SourceControl/network/forks/mkamonster/agentsupport/contribution/5549 ) that should tackle this. It uses a separate assembly to reference for background agents.

Hope this helps.
Nov 18, 2013 at 12:38 PM
Whats the difference in code for exactly that situation, can you explain a little more on why it won't pass submission? I can't see why it works now, but will not work when submitting to the store... I tried your fork, but I had a hard time getting it to work. Should I replace your source with all the other places or only in the BackgroundAgent? Problems with multiple dlls with the same name etc.
Nov 18, 2013 at 12:50 PM
The code is slightly different, the code that normally is excluded by the configuration that's mentioned above is eliminated in those assemblies.

During submission your code is checked against the use of unsupported APIs (http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh202962(v=vs.105).aspx#BKMK_UnsupportedAPIs).

You can run this check locally on your machine as wel: http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh394032(v=vs.105).aspx
Coordinator
Mar 23, 2014 at 11:59 PM
Hi Mark, I went with your original idea to "split the project in two". All the core functionality is now included in it's own assembly "GoogleAnalytics.Core" that you can use by itself in a background agent project. This core assembly should definitely pass all cert tests for background agents as it does not contain any platform or UI specific APIs found on the unsupported APIs list.

The nice part (besides support for background agents) is that this approach also opened the door for the core assembly to be distributed as a PCL (portable class library) that can be used on other platforms such as WPF, Silverlight, or Xamarin.

The down-side is that there is more work to be done during initialization since PCL compatibility doesn't support loading local resources or determining things like screen size.

Hoping everyone is happy with this decision. Overall, this felt like the right long term approach to solve this issue.

To set this up in your project:
1) Add the nuget package to your project same as before.
2) Remove the "GoogleAnalytics" project reference and the analytics.* files BUT leave just the project reference for "GoogleAnalytics.Core".
3) Add the following class (for WP8) to your project to help provide platform specific info required by GA.
4) Create and initialize a tracker object that you can call the same way you would in a regular project. For example:
static Tracker tracker;

static ScheduledAgent()
{
    tracker = new Tracker("UA-39959863-1", new PlatformInfoProvider(), GAServiceManager.Current);
    tracker.AppName = "My agent";
    tracker.AppVersion = "1.0";

    Deployment.Current.Dispatcher.BeginInvoke(delegate
    {
        Application.Current.UnhandledException += UnhandledException;
    });
}

private static void UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
    tracker.SendException(e.ExceptionObject.ToString(), true);

    if (Debugger.IsAttached)
    {
        // An unhandled exception has occurred; break into the debugger
        Debugger.Break();
    }
}

protected override void OnInvoke(ScheduledTask task)
{
    tracker.SendEvent("OnInvoke", "action", "label", 0);

    NotifyComplete();
}
Jul 1, 2014 at 3:35 AM
Edited Jul 1, 2014 at 3:35 AM
This looks great. I was able to call "SendView" or "SendEvent" method without exception but looks like it doesn't come into GA. Not sure if this work?
Jul 1, 2014 at 8:33 AM
Did you try watching the traffic by using Fiddler or similar tool?
Jul 2, 2014 at 4:48 AM
Ok I made it work now. I forgot to put this class into my project. But I also need to put another class as well.

I monitor "real time" user in GA and it works!

Thanks guys a lot.
Jan 5, 2015 at 12:24 AM
Edited Jan 5, 2015 at 1:11 AM
I was trying to do like you explained but it is not working for me. First of all I needed to put Tracker initialization into Dispatcher because PlatformInforProvider needed it (I think it can be because on WP8.1 devices WP8.0 backgroud agents are executed in other thread). After all nothing is happening when I am sending event or exception. Do you know what I am doing wrong?

My Code:
        static Tracker tracker;
        static ScheduledAgent()
        {
            // Subscribe to the managed exception handler
            Deployment.Current.Dispatcher.BeginInvoke(delegate
            {
                var platformProvider = new GoogleAnalytics.PlatformInfoProvider();
                tracker = new Tracker("MYKEY", platformProvider, GAServiceManager.Current);
                tracker.AppName = "APPNAME";
                tracker.AppVersion = "1.0";

                Application.Current.UnhandledException += UnhandledException;
            });
        }

        private static void UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            if(tracker != null)
            {
                tracker.SendException("Background Agent Unhandled Exception: " + e.ExceptionObject.ToString(), true);
            }

            if (Debugger.IsAttached)
            {
                // An unhandled exception has occurred; break into the debugger
                Debugger.Break();
            }
        }

        protected override void OnInvoke(ScheduledTask task)
        {
                if (tracker != null)
                {
                    tracker.SendEvent("OnAgentInvoke", "AgentInvoked", "Background Agent Invoked", 0);
                }

                NotifyComplete();
        }