-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathEasyTracker.cs
132 lines (113 loc) · 4.28 KB
/
EasyTracker.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
using System;
using System.Net.NetworkInformation;
using System.Threading.Tasks;
using System.Windows;
using System.Xml;
using MonoTouch.UIKit;
using System.IO;
using MonoTouch.Foundation;
using System.Reflection;
namespace GoogleAnalytics
{
public sealed partial class EasyTracker
{
private EasyTracker()
{
ConfigPath = "analytics.xml";
}
System.Threading.Timer networkStatusUpdateTimer;
private void InitConfig(string configPath)
{
var absolutePath = Path.Combine(NSBundle.MainBundle.ResourcePath, configPath);
using (var stream = File.OpenRead(absolutePath))
{
using (var reader = XmlReader.Create(stream))
{
InitConfig(reader);
}
}
}
void Init()
{
if (Config == null) InitConfig(ConfigPath);
PopulateMissingConfig();
if (Config.AutoTrackNetworkConnectivity)
{
UpdateConnectionStatus();
networkStatusUpdateTimer = new System.Threading.Timer(_OnTimer, this, 0, 30000);
}
InitTracker();
}
void PopulateMissingConfig()
{
if (string.IsNullOrEmpty(Config.AppName))
{
var infoDictionary = NSBundle.MainBundle.InfoDictionary;
var appname = infoDictionary.ObjectForKey(new NSString("CFBundleDisplayName"));
Config.AppName = appname != null ? appname.ToString() : Assembly.GetEntryAssembly().GetName().Name;
}
if (string.IsNullOrEmpty(Config.AppVersion))
{
var infoDictionary = NSBundle.MainBundle.InfoDictionary;
var shortVersionString = infoDictionary.ObjectForKey(new NSString("CFBundleShortVersionString"));
Config.AppVersion = shortVersionString != null ? shortVersionString.ToString() : "0.0";
}
}
public void OnApplicationActivated(object sender)
{
if (suspended.HasValue && Config.SessionTimeout.HasValue)
{
var suspendedAgo = DateTime.UtcNow.Subtract(suspended.Value);
if (suspendedAgo > Config.SessionTimeout.Value)
{
tracker.SetStartSession(true);
}
}
}
public async void OnApplicationDeactivated(object sender)
{
if (Config.AutoAppLifetimeTracking)
{
tracker.SendEvent("app", "suspend", null, 0);
}
suspended = DateTime.UtcNow;
await Dispatch(); // there is no way to get a deferral in WP so this will not actually happen until after we return to the app
}
static void _OnTimer(object state)
{
NSThread.Current.InvokeOnMainThread(() => ((EasyTracker)state).OnTimer());
}
void OnTimer()
{
UpdateConnectionStatus();
}
private async static void UpdateConnectionStatus()
{
GAServiceManager.Current.IsConnected = await Reachability.IsHostReachableAsync("www.google.com");
}
bool reportingException = false;
async public Task OnApplicationUnhandledException(Exception ex)
{
if (!reportingException)
{
reportingException = true;
try
{
tracker.SendException(ex.ToString(), true);
await Dispatch();
// rethrow the exception now that we're done logging it. wrap in another exception in order to prevent stack trace from getting reset.
throw new Exception("Tracked exception rethrown", ex);
}
finally
{
// we have to do some trickery in order to make sure the flag is reset only after the new exception has passed all the way through the UE pipeline. Otherwise we would have an infinite loop.
NSThread.Current.InvokeOnMainThread(async () =>
{
await Task.Yield();
reportingException = false;
});
}
}
}
}
}