Firebase Analytics in Xamarin Forms

Ashish Kumar picture Ashish Kumar · Feb 13, 2018 · Viewed 9k times · Source

Can we get custom events such as say Button 1 was pressed using Firebase Analytics in a Xamarin Forms Project ?

Answer

GiampaoloGabba picture GiampaoloGabba · Jun 8, 2018

Answer Updated for the new version of Xamarin Firebase components and to fix various issues

Sure, you need to DI (dependency injection) to call the platform code.

  • Configure your Firebase App: https://firebase.google.com/docs/projects/learn-more
  • Reference the proper nuget packages for Firebase Analytics:

    Android Project

    • Xamarin.FireBase.Analytics
    • Xamarin.FireBase.Analytics.Impl
    • Plugin.CurrentActivity (used to get the current context as Forms.Context is deprecated)

    iOS Project

    • Xamarin.FireBase.iOS.Analytics (iOS project)
  • In your PCL (or .NETStandard) project create the interface

  • In the Android and iOS project write the plaftorm specific code
  • In your viewmodels, use DI in the PCL (or .NETStandard) project to call the LogEvent method to store your event

Note: Custom events are slow to appear in firebase, in my experience they need 24 hours to appear in the web console. If you want to properly test the custom logging, use your phone and activate the analytics debug (so you can see your events in the debugView in firebase console)*


Note2: watch out for the eventId property: names can be up to 40 characters long, may only contain alphanumeric characters and underscores (""), and must start with an alphabetic character. The "firebase", "google_" and "ga_" prefixes are reserved and should not be used. I have included a smal utility function to automatically fix eventId, you can skip it if you want


PCL or .NETStandard project

using System.Collections.Generic;

namespace MobileApp.Services
{
    public interface IAnalyticsService
    {
        void LogEvent(string eventId);
        void LogEvent(string eventId, string paramName, string value);
        void LogEvent(string eventId, IDictionary<string, string> parameters);
    }
}

Android

Make sure to have the INTERNET permission in your manifest.

Import your google-services.json (generated from your firebase account) with compilation action set to "GoogleServicesJson"

Remember to call CrossCurrentActivity init method in your AppDelegate OnCreate:

CrossCurrentActivity.Current.Init(this, bundle);

This is the Android platform service code:

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Android.OS;
using Firebase.Analytics;
using Plugin.CurrentActivity;
using MobileApp.Services;

namespace MobileApp.Droid.Services
{
    [assembly: Dependency (typeof(AnalyticsServiceDroid))]
    public class AnalyticsServiceDroid : IAnalyticsService
    {

        public void LogEvent(string eventId)
        {
            LogEvent(eventId, null);
        }

        public void LogEvent(string eventId, string paramName, string value)
        {
            LogEvent(eventId, new Dictionary<string, string>
            {
                {paramName, value}
            });
        }

        public void LogEvent(string eventId, IDictionary<string, string> parameters)
        {

            //utility method to fix eventId, you can skip it if you are sure to always pass valid eventIds
            eventId = FixEventId(eventId);

            var fireBaseAnalytics = FirebaseAnalytics.GetInstance(CrossCurrentActivity.Current.AppContext);

            if (parameters == null)
            {
                fireBaseAnalytics.LogEvent(eventId, null);
                return;
            }

            var bundle = new Bundle();

            foreach (var item in parameters)
            {
                bundle.PutString(item.Key, item.Value);
            }

            fireBaseAnalytics.LogEvent(eventId, bundle);
        }

        //utility method to fix eventId, you can skip it if you are sure to always pass valid eventIds
        private string FixEventId(string eventId)
        {
            if (string.IsNullOrWhiteSpace(eventId))
                return "unknown";

            //remove unwanted characters
            eventId = Regex.Replace(eventId, @"[^a-zA-Z0-9_]+", "_", RegexOptions.Compiled);

            //trim to 40 if needed
            return eventId.Substring(0, Math.Min(40, eventId.Length));
        }

    }
}

Debug View in Android

To enable the debugView in the firebase run this command from your adb console command prompt (usually is c:\WINDOWS\System32, but you can reach it through Visual Studio in tools --> android --> android adb command prompt):

adb shell setprop debug.firebase.analytics.app <package_name>

To disable the debugView use:

adb shell setprop debug.firebase.analytics.app .none.

Verbose logging

Verbose logging is usefyk to monitor logging of events by the SDK to help verify that events are being logged properly. This includes both automatically and manually logged events.

You can enable verbose logging with a series of adb commands:

adb shell setprop log.tag.FA VERBOSE
adb shell setprop log.tag.FA-SVC VERBOSE
adb logcat -v time -s FA FA-SVC

Important note

Some external libraries (Like MS AppCenter) are already including Firebase and explicitly disabling analytics in teir manifest.

In these cases you need to modify your AndroidManifest.xml adding this line just before the </application> tag:

<meta-data android:name="firebase_analytics_collection_deactivated" android:value="false" tools:replace="android:value"/>

Also make sure to have this property inside your <manifest> tag:

xmlns:tools="http://schemas.android.com/tools"

iOS

Make sure to test the event logging on your phone! This is not going to work anymore on emulators

Initialize the component in your AppDelegate, just before base.FinishedLaunching:

Firebase.Core.App.Configure();

Then import your GoogleService-Info.plist (generated from your firebase account) with compilation action set to "BundleResource" .

This is the iOS platform service code:

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Firebase.Analytics;
using Firebase.Core;
using Foundation;
using MobileApp.Services;

namespace MobileApp.iOS.Services
{
    [assembly: Dependency (typeof(AnalyticsServiceIOS))]
    public class AnalyticsServiceIOS : IAnalyticsService
    {

        public void LogEvent(string eventId)
        {
            LogEvent(eventId, (IDictionary<string, string>)null);
        }

        public void LogEvent(string eventId, string paramName, string value)
        {
            LogEvent(eventId, new Dictionary<string, string>
            {
                { paramName, value }
            });
        }

        public void LogEvent(string eventId, IDictionary<string, string> parameters)
        {

            //utility method to fix eventId, you can skip it if you are sure to always pass valid eventIds
            eventId = FixEventId(eventId);

            if (parameters == null)
            {
                Analytics.LogEvent(eventId, parameters: null);
                return;
            }

            var keys = new List<NSString>();
            var values = new List<NSString>();
            foreach (var item in parameters)
            {
                keys.Add(new NSString(item.Key));
                values.Add(new NSString(item.Value));
            }

            var parametersDictionary =
                NSDictionary<NSString, NSObject>.FromObjectsAndKeys(values.ToArray(), keys.ToArray(), keys.Count);
            Analytics.LogEvent(eventId, parametersDictionary);

        }

        //utility method to fix eventId, you can skip it if you are sure to always pass valid eventIds
        private string FixEventId(string eventId)
        {
            if (string.IsNullOrWhiteSpace(eventId))
                return "unknown";

            //remove unwanted characters
            eventId = Regex.Replace(eventId, @"[^a-zA-Z0-9_]+", "_", RegexOptions.Compiled);

            //trim to 40 if needed
            return eventId.Substring(0, Math.Min(40, eventId.Length));
        }
    }
}

Debug View in iOS

To enable the debugView in the firebase console add the following argument to Extra mlaunch Arguments in your iOS project properties:

--argument=-FIRDebugEnabled

To disable the debugView use:

--argument=-FIRDebugDisabled

Important note (thanks to Ken for pointing out this)

If you get an exception calling Firebase.Core.App.Configure(); in your AppDelegate, modify your GoogleService-Info.plist settings IS_ANALYTICS_ENABLED to true

In your ViewModel you can track any event you want

For Example:

public class MenuPageViewModel{
    public MenuPageViewModel(){
         var analyticsService= DependencyService.Get<IAnalyticsService>();
         //You can use any of the LogEvent Overloads, for example:
         analyticsService.LogEvent("Event");

    }
}