Xamarin Insights is a product offered by Xamarin that provides both analytics and crash reporting in a single toolset. It is by far one of the best and most feature-rich tools on the market, and because it's made by Xamarin, it's very easy to use with apps built on the Xamarin platform. For the purposes of this book, we will leverage the Xamarin Insights tool to add analytics and crash reporting capabilities to our TripLog app. However, due to the loosely coupled nature we have implemented in our app, the concepts used in this chapter to use Xamarin Insights could be used for pretty much any other analytic or crash reporting tool that supports .NET.
Using Xamarin Insights in your mobile app is pretty straightforward. You just need to include the Xamarin.Insights
NuGet package in each of your projects and set your app up in the Xamarin Insights web-based dashboard at http://insights.xamarin.com/. When you set your app up, you will be given an API key that you need to include in your code when you initialize the Insights library. Fortunately, if you're using Xamarin Studio, Xamarin has made all of this extremely easy by building it right into the options dialog for iOS and Android projects.
In order to set up Xamarin Insights, perform the following steps:
TripLog.Droid
project.Xamarin.Insights
NuGet package to the TripLog core project.With Xamarin Insights all set up and configured for each platform project, we can start using it immediately to send crash reports and usage data. However, just like the other platform specific capabilities we implemented earlier in the book, we want to decouple the analytics implementation from the rest of the app. In the next section, we will create an analytics service that can be used in our app through dependency, keeping the architecture flexible and easy to test.
In order to use Xamarin Insights in our TripLog app, we will want to abstract it into a service, like we did for geo-location. As we have seen multiple times in previous chapters, there are numerous benefits to this approach, namely, it loosely couples our ViewModels from the actual code that uses the Xamarin Insights API, making unit testing our ViewModels much simpler and cleaner.
In order to create an analytics service, perform the following steps:
IAnalyticsService
in the Services
folder in core library:public interface IAnalyticsService { }
IAnalyticsService
interface with methods to send crash reports and track usage events:public interface IAnalyticsService { void SendCrashReport(Exception exception); void SendCrashReport(Exception exception, IDictionary<string, string> additionalData); void TrackEvent(string @event); void TrackEvent(string @event, IDictionary<string, string> additionalData); void RegisterUser(string userId, IDictionary<string, string> additionalData); }
Notice that the methods in this service are not necessarily specific to Xamarin Insights—they represent pretty generic functionality when it comes to error and event tracking. This leads to yet another benefit of the loosely coupled architecture that we have put in place: if, for some reason, you needed to stop using Xamarin Insights and use another app analytics toolset instead, you would simply write a new implementation of this interface, and your ViewModels will automatically be ready to use the new implementation, since they use it through the IAnalyticsService
interface.
For now, we will of course use Xamarin Insights in the concrete implementation of the IAnalyticsService
interface. The Xamarin Insights API is pretty simple and straightforward, and so the implementation for each of the methods in the interface is no more than a couple of lines. Specifically, the Xamarin.Insights.Report
method allows us to send Exception
data to the Xamarin Insights dashboard, and the Xamarin.Insights.Track
method allows us to send user events to the dashboard.
The purpose of this chapter is to show how an analytics library can be integrated into a Xamarin.Forms mobile app using the patterns implemented in this book. For more information about the Xamarin Insights toolset and the capabilities of its SDK, checkout the documentation at http://insights.xamarin.com/.
In order to create the Xamarin Insights implementation of IAnalyticsService
, perform the following steps:
XamarinInsightsAnalyticsService
in the Services
folder in the core library that implements IAnalyticsService
:public class XamarinInsightsAnalyticsService : IAnalyticsService { }
IAnalyticsService
within the XamarinInsightsAnalyticsService
:public class XamarinInsightsAnalyticsService : IAnalyticsService { #region IAnalyticsService implementation public void SendCrashReport(Exception exception) { Insights.Report(exception, Insights.Severity.Error); } public void SendCrashReport(Exception exception, IDictionary<string, string> additionalData) { Insights.Report(exception, new Dictionary<string, string>(additionalData), Insights.Severity.Error); } public void TrackEvent(string @event) { Insights.Track(@event); } public void TrackEvent(string @event, IDictionary<string, string> additionalData) { Insights.Track(@event, additionalData); } public void RegisterUser(string userId, IDictionary<string, string> additionalData) { Insights.Identify(userId, additionalData); } #endregion }
TripLogCoreModule
in the core library to register the XamarinInsightsAnalyticsService
implementation into the IoC:public class TripLogCoreModule : NinjectModule { public override void Load () { // ViewModels // ... // Core Services // ... Bind<IAnalyticsService> () .To<XamarinInsightsAnalyticsService> () .InSingletonScope (); } }
Next, we need to be able to use this new analytics service within the logic of our app, specifically the ViewModels. Because we will likely need to report analytic data from all of our ViewModels, it would be best to just include an instance of IAnalyticsService
as a property of the BaseViewModel
, similar to the INavService
property, and include it in the constructor's parameter list:
public abstract class BaseViewModel : INotifyPropertyChanged { protected INavService NavService { get; private set; } protected IAnalyticsService AnalyticsService { get; private set; } // ... protected BaseViewModel (INavService navService, IAnalyticsService analyticsService) { NavService = navService; AnalyticsService = analyticsService; } // ... }
We also need to update the constructor of the BaseViewModel<TParameter>
class that subclasses the BaseViewModel
class to take an IAnalyticsService
parameter, which it simply passes to its base class:
public abstract class BaseViewModel<TParameter> : BaseViewModel { protected BaseViewModel (INavService navService, IAnalyticsService analyticsService) : base (navService, analyticsService) { } // ... }
Finally, we need to update the constructors of each of the ViewModels that inherit from BaseViewModel
to take an IAnalyticsService
parameter, which is just passed to its BaseViewModel
base class.
Now that we have an IAnalyticsService
property in all of our ViewModels, we can update all of our try
/catch
blocks to pass exceptions to Xamarin Insights. For example, in MainViewModel
, we have a try
/finally
block in the LoadEntries
method that is currently not catching exceptions.
Update this try
block with a catch
block and then pass the caught Exception
off to the analytics service via the SendCrashReport
method:
void LoadEntries() { if (IsBusy) return; IsBusy = true; try { // ... } catch (Exception e) { AnalyticsService.SendCrashReport (e); } finally { IsBusy = false; } }
We can also start tracking user events throughout the application. For example, if we wanted to know how often users went to the New Entry page in our app, we could call the TrackEvent
method of our IAnalyticsService
within the Init
method of NewEntryViewModel
to log that in Xamarin Insights:
public class NewEntryViewModel : BaseViewModel
{
// ...
public NewEntryViewModel (INavService navService, ILocationService locService, IPhotoService photoService, ITripLogDataService tripLogService, IAnalyticsService analyticsService)
: base (navService, analyticsService)
{
// ...
}
public override async Task Init ()
{
AnalyticsService.TrackEvent ("New Entry Page");
// ...
}
// ...
}
3.144.35.122