More GA event tracking throughout. Added dispatch when ios app is backgrounded.

This commit is contained in:
Kyle Spearrin 2016-08-04 19:35:56 -04:00
parent dd633d4fc1
commit 7c29f8b77a
13 changed files with 106 additions and 14 deletions

View File

@ -87,9 +87,10 @@ namespace Bit.Android.Services
}
}
public void Dispatch()
public void Dispatch(Action completionHandler = null)
{
_instance.DispatchLocalHits();
completionHandler?.Invoke();
}
}
}

View File

@ -1,4 +1,6 @@
namespace Bit.App.Abstractions
using System;
namespace Bit.App.Abstractions
{
public interface IGoogleAnalyticsService
{
@ -8,6 +10,6 @@
void TrackExtensionEvent(string eventName, string label = null);
void TrackEvent(string category, string eventName, string label = null);
void TrackException(string message, bool fatal);
void Dispatch();
void Dispatch(Action completionHandler = null);
}
}

View File

@ -16,12 +16,14 @@ namespace Bit.App.Pages
private readonly IFolderService _folderService;
private readonly IUserDialogs _userDialogs;
private readonly IConnectivity _connectivity;
private readonly IGoogleAnalyticsService _googleAnalyticsService;
public SettingsAddFolderPage()
{
_folderService = Resolver.Resolve<IFolderService>();
_userDialogs = Resolver.Resolve<IUserDialogs>();
_connectivity = Resolver.Resolve<IConnectivity>();
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
Init();
}
@ -79,6 +81,7 @@ namespace Bit.App.Pages
{
await Navigation.PopModalAsync();
_userDialogs.Toast("New folder created.");
_googleAnalyticsService.TrackAppEvent("CreatedFolder");
}
else if(saveTask.Result.Errors.Count() > 0)
{

View File

@ -16,6 +16,7 @@ namespace Bit.App.Pages
private readonly IFolderService _folderService;
private readonly IUserDialogs _userDialogs;
private readonly IConnectivity _connectivity;
private readonly IGoogleAnalyticsService _googleAnalyticsService;
public SettingsEditFolderPage(string folderId)
{
@ -23,6 +24,7 @@ namespace Bit.App.Pages
_folderService = Resolver.Resolve<IFolderService>();
_userDialogs = Resolver.Resolve<IUserDialogs>();
_connectivity = Resolver.Resolve<IConnectivity>();
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
Init();
}
@ -93,6 +95,7 @@ namespace Bit.App.Pages
{
await Navigation.PopModalAsync();
_userDialogs.Toast("Folder updated.");
_googleAnalyticsService.TrackAppEvent("EditedFolder");
}
else if(saveTask.Result.Errors.Count() > 0)
{

View File

@ -1,13 +1,19 @@
using System;
using Bit.App.Controls;
using Xamarin.Forms;
using Bit.App.Abstractions;
using XLabs.Ioc;
namespace Bit.App.Pages
{
public class SettingsHelpPage : ExtendedContentPage
{
private readonly IGoogleAnalyticsService _googleAnalyticsService;
public SettingsHelpPage()
{
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
Init();
}
@ -103,16 +109,19 @@ namespace Bit.App.Pages
private void EmailCell_Tapped(object sender, EventArgs e)
{
_googleAnalyticsService.TrackAppEvent("HelpEmail");
Device.OpenUri(new Uri("mailto:hello@bitwarden.com"));
}
private void WebsiteCell_Tapped(object sender, EventArgs e)
{
_googleAnalyticsService.TrackAppEvent("HelpWebsite");
Device.OpenUri(new Uri("https://bitwarden.com"));
}
private void BugCell_Tapped(object sender, EventArgs e)
{
_googleAnalyticsService.TrackAppEvent("HelpBug");
Device.OpenUri(new Uri("https://github.com/bitwarden/mobile"));
}

View File

@ -17,6 +17,7 @@ namespace Bit.App.Pages
private readonly IUserDialogs _userDialogs;
private readonly IConnectivity _connectivity;
private readonly ISettings _settings;
private readonly IGoogleAnalyticsService _googleAnalyticsService;
public SettingsSyncPage()
{
@ -24,6 +25,7 @@ namespace Bit.App.Pages
_userDialogs = Resolver.Resolve<IUserDialogs>();
_connectivity = Resolver.Resolve<IConnectivity>();
_settings = Resolver.Resolve<ISettings>();
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
Init();
}
@ -88,6 +90,7 @@ namespace Bit.App.Pages
if(succeeded)
{
_userDialogs.Toast("Syncing complete.");
_googleAnalyticsService.TrackAppEvent("Synced");
}
else
{

View File

@ -6,6 +6,7 @@ using Bit.App.Models.Page;
using Plugin.Settings.Abstractions;
using Xamarin.Forms;
using XLabs.Ioc;
using Bit.App.Abstractions;
namespace Bit.App.Pages
{
@ -13,11 +14,13 @@ namespace Bit.App.Pages
{
private readonly IUserDialogs _userDialogs;
private readonly ISettings _settings;
private readonly IGoogleAnalyticsService _googleAnalyticsService;
public ToolsExtensionPage()
{
_userDialogs = Resolver.Resolve<IUserDialogs>();
_settings = Resolver.Resolve<ISettings>();
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
Model = new AppExtensionPageModel(_settings);
Init();
@ -59,7 +62,7 @@ namespace Bit.App.Pages
var notStartedButton = new Button
{
Text = "Enable App Extension",
Command = new Command(() => ShowExtension()),
Command = new Command(() => ShowExtension("NotStartedEnable")),
VerticalOptions = LayoutOptions.End,
HorizontalOptions = LayoutOptions.Fill,
Style = (Style)Application.Current.Resources["btn-primary"]
@ -108,7 +111,7 @@ namespace Bit.App.Pages
var notActivatedButton = new Button
{
Text = "Enable App Extension",
Command = new Command(() => ShowExtension()),
Command = new Command(() => ShowExtension("NotActivatedEnable")),
VerticalOptions = LayoutOptions.End,
HorizontalOptions = LayoutOptions.Fill,
Style = (Style)Application.Current.Resources["btn-primary"]
@ -167,7 +170,7 @@ namespace Bit.App.Pages
var activatedButtonReenable = new Button
{
Text = "Re-enable App Extension",
Command = new Command(() => ShowExtension()),
Command = new Command(() => ShowExtension("Re-enable")),
VerticalOptions = LayoutOptions.End,
HorizontalOptions = LayoutOptions.Fill,
Style = (Style)Application.Current.Resources["btn-primaryAccent"]
@ -200,13 +203,15 @@ namespace Bit.App.Pages
BindingContext = Model;
}
private void ShowExtension()
private void ShowExtension(string type)
{
_googleAnalyticsService.TrackAppEvent("ShowExtension", type);
MessagingCenter.Send(Application.Current, "ShowAppExtension", this);
}
public void EnabledExtension(bool enabled)
{
_googleAnalyticsService.TrackAppEvent("EnabledExtension", enabled.ToString());
Model.Started = true;
if(!Model.Activated && enabled)
{

View File

@ -18,6 +18,7 @@ namespace Bit.App.Pages
private readonly IFolderService _folderService;
private readonly IUserDialogs _userDialogs;
private readonly IConnectivity _connectivity;
private readonly IGoogleAnalyticsService _googleAnalyticsService;
public VaultAddSitePage()
{
@ -25,6 +26,7 @@ namespace Bit.App.Pages
_folderService = Resolver.Resolve<IFolderService>();
_userDialogs = Resolver.Resolve<IUserDialogs>();
_connectivity = Resolver.Resolve<IConnectivity>();
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
Init();
}
@ -139,6 +141,7 @@ namespace Bit.App.Pages
{
await Navigation.PopModalAsync();
_userDialogs.Toast("New site created.");
_googleAnalyticsService.TrackAppEvent("CreatedSite");
}
else if(saveTask.Result.Errors.Count() > 0)
{

View File

@ -18,6 +18,7 @@ namespace Bit.App.Pages
private readonly IFolderService _folderService;
private readonly IUserDialogs _userDialogs;
private readonly IConnectivity _connectivity;
private readonly IGoogleAnalyticsService _googleAnalyticsService;
public VaultEditSitePage(string siteId)
{
@ -26,6 +27,7 @@ namespace Bit.App.Pages
_folderService = Resolver.Resolve<IFolderService>();
_userDialogs = Resolver.Resolve<IUserDialogs>();
_connectivity = Resolver.Resolve<IConnectivity>();
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
Init();
}
@ -174,6 +176,7 @@ namespace Bit.App.Pages
{
await Navigation.PopModalAsync();
_userDialogs.Toast("Site updated.");
_googleAnalyticsService.TrackAppEvent("EditedSite");
}
else if(saveTask.Result.Errors.Count() > 0)
{
@ -241,6 +244,7 @@ namespace Bit.App.Pages
{
await Navigation.PopModalAsync();
_userDialogs.Toast("Site deleted.");
_googleAnalyticsService.TrackAppEvent("DeletedSite");
}
else if((await deleteTask).Errors.Count() > 0)
{

View File

@ -62,9 +62,12 @@ namespace Bit.iOS.Core.Services
_tracker.Send(dict);
}
public void Dispatch()
public void Dispatch(Action completionHandler = null)
{
Gai.SharedInstance.Dispatch();
Gai.SharedInstance.Dispatch((result) =>
{
completionHandler?.Invoke();
});
}
private void SetUserId()

View File

@ -228,7 +228,6 @@ namespace Bit.iOS.Extension
Constants.AppExtensionOldPasswordKey, password);
}
_googleAnalyticsService.TrackExtensionEvent("AutoFilled", _context.ProviderType);
CompleteRequest(itemData);
}
@ -240,7 +239,21 @@ namespace Bit.iOS.Extension
var resultsItem = new NSExtensionItem { Attachments = new NSItemProvider[] { resultsProvider } };
var returningItems = new NSExtensionItem[] { resultsItem };
ExtensionContext.CompleteRequest(returningItems, null);
if(itemData != null)
{
_googleAnalyticsService.TrackExtensionEvent("AutoFilled", _context.ProviderType);
}
else
{
_googleAnalyticsService.TrackExtensionEvent("Closed", _context.ProviderType);
}
_googleAnalyticsService.Dispatch(() =>
{
NSRunLoop.Main.BeginInvokeOnMainThread(() => {
ExtensionContext.CompleteRequest(returningItems, null);
});
});
}
private void SetIoc()
@ -296,7 +309,7 @@ namespace Bit.iOS.Extension
var dict = list as NSDictionary;
action(dict);
_googleAnalyticsService.TrackExtensionEvent("ProviderType", type);
_googleAnalyticsService.TrackExtensionEvent("ProcessItemProvider", type);
Debug.WriteLine("BW LOG, ProviderType: " + _context.ProviderType);
Debug.WriteLine("BW LOG, Url: " + _context.Url);

View File

@ -166,7 +166,7 @@ namespace Bit.iOS.Extension
if(saveTask.Result.Succeeded)
{
_googleAnalyticsService.TrackExtensionEvent("SiteCreated");
_googleAnalyticsService.TrackExtensionEvent("CreatedSite");
if(SiteListController != null)
{
SiteListController.DismissModal();

View File

@ -26,12 +26,15 @@ using Bit.App.Pages;
using PushNotification.Plugin.Abstractions;
using HockeyApp.iOS;
using Bit.iOS.Core;
using Google.Analytics;
namespace Bit.iOS
{
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
private GaiCompletionHandler _dispatchHandler = null;
public ISettings Settings { get; set; }
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
@ -138,8 +141,10 @@ namespace Bit.iOS
UIApplication.SharedApplication.SetStatusBarHidden(true, false);
// Log the date/time we last backgrounded
Settings.AddOrUpdateValue(App.Constants.SettingLastBackgroundedDate, DateTime.UtcNow);
Settings.AddOrUpdateValue(Bit.App.Constants.SettingLastBackgroundedDate, DateTime.UtcNow);
// Dispatch Google Analytics
SendGoogleAnalyticsHitsInBackground();
base.DidEnterBackground(uiApplication);
Debug.WriteLine("DidEnterBackground");
@ -176,6 +181,11 @@ namespace Bit.iOS
public override void WillEnterForeground(UIApplication uiApplication)
{
SendResumedMessage();
// Restores the dispatch interval because dispatchWithCompletionHandler
// has disabled automatic dispatching.
Gai.SharedInstance.DispatchInterval = 10;
base.WillEnterForeground(uiApplication);
Debug.WriteLine("WillEnterForeground");
}
@ -273,5 +283,38 @@ namespace Bit.iOS
Resolver.SetResolver(new UnityResolver(container));
}
/// <summary>
/// This method sends any queued hits when the app enters the background.
/// ref: https://developers.google.com/analytics/devguides/collection/ios/v3/dispatch
/// </summary>
private void SendGoogleAnalyticsHitsInBackground()
{
var taskExpired = false;
var taskId = UIApplication.SharedApplication.BeginBackgroundTask(() =>
{
taskExpired = true;
});
if(taskId == UIApplication.BackgroundTaskInvalid)
{
return;
}
_dispatchHandler = (result) =>
{
// Send hits until no hits are left, a dispatch error occurs, or the background task expires.
if(_dispatchHandler != null && result == DispatchResult.Good && !taskExpired)
{
Gai.SharedInstance.Dispatch(_dispatchHandler);
}
else
{
UIApplication.SharedApplication.EndBackgroundTask(taskId);
}
};
Gai.SharedInstance.Dispatch(_dispatchHandler);
}
}
}