AnalyticsHelper.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. using System;
  2. using UnityEditor;
  3. using UnityEditor.Build.Reporting;
  4. using UnityEngine;
  5. using UnityEngine.Analytics;
  6. namespace Unity.Play.Publisher.Editor
  7. {
  8. /// <summary>
  9. /// Options for representing the result of the upload process
  10. /// </summary>
  11. public enum UploadResult
  12. {
  13. /// <summary>
  14. /// The upload process was manually interrupted by the user
  15. /// </summary>
  16. Cancelled,
  17. /// <summary>
  18. /// The upload process was automatically interrupted by an error
  19. /// </summary>
  20. Failed,
  21. /// <summary>
  22. /// The upload process succeeded
  23. /// </summary>
  24. Succeeded
  25. }
  26. class AnalyticsHelper : ScriptableObject
  27. {
  28. const int MaxEventsPerHour = 1000;
  29. const int MaxNumberOfElements = 1000;
  30. const string VendorKey = "unity.webglPublisher"; // the format needs to be "unity.xxx"
  31. const string EventBuildStarted = "webglPublisher_buildStarted";
  32. const string EventBuildCompleted = "webglPublisher_buildCompleted";
  33. const string EventUploadStarted = "webglPublisher_uploadStarted";
  34. const string EventUploadCompleted = "webglPublisher_uploadCompleted";
  35. const string EventButtonClicked = "webglPublisher_buttonClicked";
  36. static string ProjectID
  37. {
  38. get
  39. {
  40. //we use a combination of company name + product name to reduce the chance of clash with other projects
  41. return string.IsNullOrEmpty(CloudProjectSettings.projectId) ? string.Format("{0}_{1}", PlayerSettings.companyName, PlayerSettings.productName)
  42. : CloudProjectSettings.projectId;
  43. }
  44. }
  45. DateTime lastBuildStartTime;
  46. DateTime lastUploadStartTime;
  47. /// <summary>
  48. /// The instance of the analytics helper
  49. /// </summary>
  50. public static AnalyticsHelper Instance
  51. {
  52. get
  53. {
  54. if (!s_Instance)
  55. {
  56. var instance = Resources.FindObjectsOfTypeAll<AnalyticsHelper>();
  57. if (instance.Length == 0)
  58. {
  59. s_Instance = CreateInstance<AnalyticsHelper>();
  60. s_Instance.hideFlags = HideFlags.HideAndDontSave;
  61. }
  62. else
  63. {
  64. s_Instance = instance[0] as AnalyticsHelper;
  65. }
  66. }
  67. return s_Instance;
  68. }
  69. }
  70. static AnalyticsHelper s_Instance;
  71. static void DebugWarning(string message, params object[] args)
  72. {
  73. #if DEBUG_TUTORIALS
  74. Debug.LogWarningFormat(message, args);
  75. #endif
  76. }
  77. static void DebugLog(string message, params object[] args)
  78. {
  79. #if DEBUG_TUTORIALS
  80. Debug.LogFormat(message, args);
  81. #endif
  82. }
  83. static void DebugError(string message, params object[] args)
  84. {
  85. #if DEBUG_TUTORIALS
  86. Debug.LogErrorFormat(message, args);
  87. #endif
  88. }
  89. internal static void BuildStarted(bool fromTool)
  90. {
  91. Instance.lastBuildStartTime = DateTime.UtcNow;
  92. SendBuildStartedEvent(ProjectID, fromTool);
  93. }
  94. internal static void BuildCompleted(BuildResult result)
  95. {
  96. BuildCompleted(result, DateTime.UtcNow - Instance.lastBuildStartTime);
  97. }
  98. internal static void BuildCompleted(BuildResult result, TimeSpan lastBuildDuration)
  99. {
  100. SendBuildCompletedEvent(ProjectID, lastBuildDuration, result);
  101. }
  102. internal static void UploadStarted()
  103. {
  104. Instance.lastUploadStartTime = DateTime.UtcNow;
  105. SendUploadStartedEvent(ProjectID);
  106. }
  107. internal static void UploadCompleted(UploadResult result)
  108. {
  109. TimeSpan lastUploadDuration = DateTime.UtcNow - Instance.lastUploadStartTime;
  110. SendUploadCompletedEvent(ProjectID, lastUploadDuration, result);
  111. }
  112. /// <summary>
  113. /// Tracks the click on a specific button
  114. /// </summary>
  115. /// <param name="buttonID"></param>
  116. internal static void ButtonClicked(string buttonID)
  117. {
  118. SendButtonClickedEvent(ProjectID, buttonID);
  119. }
  120. #region Events Structure
  121. public struct BuildStartedEventData
  122. {
  123. public int ts; // timestamp
  124. public string id;
  125. public bool fromTool;
  126. }
  127. public struct BuildCompletedEventData
  128. {
  129. public int ts; // timestamp
  130. public string id;
  131. public int duration;
  132. public int result;
  133. }
  134. public struct UploadStartedEventData
  135. {
  136. public int ts; // timestamp
  137. public string id;
  138. }
  139. public struct UploadCompletedEventData
  140. {
  141. public int ts; // timestamp
  142. public string id;
  143. public int duration;
  144. public int result;
  145. }
  146. public struct ButtonClickedEventData
  147. {
  148. public int ts; // timestamp
  149. public string id;
  150. public string buttonID;
  151. }
  152. public static AnalyticsResult SendBuildCompletedEvent(string projectID, TimeSpan duration, BuildResult result)
  153. {
  154. if (!EditorAnalytics.enabled || !RegisterEvent(EventBuildCompleted)) { return AnalyticsResult.AnalyticsDisabled; }
  155. var data = new BuildCompletedEventData
  156. {
  157. ts = DateTime.UtcNow.Millisecond,
  158. id = projectID,
  159. duration = (int)duration.TotalSeconds,
  160. result = (int)result
  161. };
  162. return SendEvent(EventBuildCompleted, data);
  163. }
  164. public static AnalyticsResult SendBuildStartedEvent(string projectID, bool fromTool)
  165. {
  166. if (!EditorAnalytics.enabled || !RegisterEvent(EventBuildStarted)) { return AnalyticsResult.AnalyticsDisabled; }
  167. var data = new BuildStartedEventData
  168. {
  169. ts = DateTime.UtcNow.Millisecond,
  170. id = projectID,
  171. fromTool = fromTool
  172. };
  173. return SendEvent(EventBuildStarted, data);
  174. }
  175. public static AnalyticsResult SendUploadCompletedEvent(string projectID, TimeSpan duration, UploadResult result)
  176. {
  177. if (!EditorAnalytics.enabled || !RegisterEvent(EventUploadCompleted)) { return AnalyticsResult.AnalyticsDisabled; }
  178. var data = new UploadCompletedEventData
  179. {
  180. ts = DateTime.UtcNow.Millisecond,
  181. id = projectID,
  182. duration = (int)duration.TotalSeconds,
  183. result = (int)result
  184. };
  185. return SendEvent(EventUploadCompleted, data);
  186. }
  187. public static AnalyticsResult SendUploadStartedEvent(string projectID)
  188. {
  189. if (!EditorAnalytics.enabled || !RegisterEvent(EventUploadStarted)) { return AnalyticsResult.AnalyticsDisabled; }
  190. var data = new UploadStartedEventData
  191. {
  192. ts = DateTime.UtcNow.Millisecond,
  193. id = projectID
  194. };
  195. return SendEvent(EventUploadStarted, data);
  196. }
  197. public static AnalyticsResult SendButtonClickedEvent(string projectID, string buttonID)
  198. {
  199. if (!EditorAnalytics.enabled || !RegisterEvent(EventButtonClicked)) { return AnalyticsResult.AnalyticsDisabled; }
  200. var data = new ButtonClickedEventData
  201. {
  202. ts = DateTime.UtcNow.Millisecond,
  203. id = projectID,
  204. buttonID = buttonID
  205. };
  206. return SendEvent(EventButtonClicked, data);
  207. }
  208. #endregion
  209. static bool RegisterEvent(string name)
  210. {
  211. AnalyticsResult result = EditorAnalytics.RegisterEventWithLimit(name, MaxEventsPerHour, MaxNumberOfElements, VendorKey);
  212. if (result != AnalyticsResult.Ok)
  213. {
  214. DebugError("Error in RegisterEvent: {0}", result);
  215. return false;
  216. }
  217. return true;
  218. }
  219. static AnalyticsResult SendEvent(string eventName, object parameters)
  220. {
  221. AnalyticsResult result = EditorAnalytics.SendEventWithLimit(eventName, parameters);
  222. if (result != AnalyticsResult.Ok)
  223. {
  224. DebugError("Error in {0}: {1}", eventName, result);
  225. }
  226. return result;
  227. }
  228. }
  229. }