///---------------------------------------------- /// Flurry Analytics Plugin /// Copyright © 2016 Aleksei Kuzin ///---------------------------------------------- using UnityEngine; using System.Collections.Generic; using System.Text; #if UNITY_IOS using System.Runtime.InteropServices; #endif namespace KHD { public static class FlurryAnalyticsIOS { #if UNITY_IOS [DllImport("__Internal")] private static extern void FlurryAnalyticsStartSession(string apiKey, bool sendCrashReports); [DllImport("__Internal")] private static extern void FlurryAnalyticsSetDebugLogEnabled(bool enabled); [DllImport("__Internal")] private static extern void FlurryAnalyticsSetAppVersion(string version); [DllImport("__Internal")] private static extern void FlurryAnalyticsSetSessionContinueSeconds(int seconds); [DllImport("__Internal")] private static extern void FlurryAnalyticsSetUserId(string userId); [DllImport("__Internal")] private static extern void FlurryAnalyticsSetAge(int age); [DllImport("__Internal")] private static extern void FlurryAnalyticsSetGender(int genderType); [DllImport("__Internal")] private static extern void FlurryAnalyticsLogEvent(string eventName, bool isTimed); [DllImport("__Internal")] private static extern void FlurryAnalyticsLogEventWithParameters(string eventName, string parameters, bool isTimed); [DllImport("__Internal")] private static extern void FlurryAnalyticsEndTimedEvent(string eventName, string parameters); [DllImport("__Internal")] private static extern void FlurryAnalyticsSetSessionReportsOnCloseEnabled(bool enabled); [DllImport("__Internal")] private static extern void FlurryAnalyticsSetSessionReportsOnPauseEnabled(bool enabled); [DllImport("__Internal")] private static extern void FlurryAnalyticsSetPulseEnabled(bool enabled); [DllImport("__Internal")] private static extern void FlurryAnalyticsSetLatitude(float latitude, float longitude, float horizontalAccuracy, float verticalAccuracy); [DllImport("__Internal")] private static extern void FlurryAnalyticsSetIAPReportingEnabled(bool enabled); #endif #if UNITY_EDITOR /// /// Generates debug logs to Editor console. /// private static bool _editorDebugLogEnabled = false; #endif /// /// Start Flurry session. /// /// API key. /// If set to true send crash reports. public static void StartSession(string apiKey, bool sendCrashReports) { #if UNITY_IOS DebugLog("Session started with apiKey: " + apiKey + " send crash reports: " + sendCrashReports); if (!IsIPhonePlayer()) { return; } if (apiKey != null) { apiKey = apiKey.ToUpper(); } if (string.IsNullOrEmpty(apiKey)) { DebugLogError("iOS API key is null or empty, please provide valid API key"); } FlurryAnalyticsStartSession(apiKey, sendCrashReports); #endif } /// /// Enable/Disable Flurry SDK debug logs. /// /// By default logs are disabled. /// public static void SetDebugLogEnabled(bool enabled) { #if UNITY_EDITOR _editorDebugLogEnabled = enabled; #endif #if UNITY_IOS if (!IsIPhonePlayer()) { return; } FlurryAnalyticsSetDebugLogEnabled(enabled); #endif } /// /// Set app version. By default Flurry SDK use CFBundleVersion. /// Should be called before StartSession. /// /// App version. public static void SetAppVersion(string appVersion) { #if UNITY_IOS DebugLog("Application version changed to: " + appVersion); if (!IsIPhonePlayer()) { return; } FlurryAnalyticsSetAppVersion(appVersion); #endif } /// /// Sets the time the app may be in the background before starting a new session upon resume. /// Default value 10 seconds. /// /// Should be called before StartSession. /// public static void SetSessionContinueSeconds(int seconds) { #if UNITY_IOS DebugLog("Set continue session seconds to: " + seconds); if (!IsIPhonePlayer()) { return; } FlurryAnalyticsSetSessionContinueSeconds(seconds); #endif } /// /// Enables Flurry Pulse. /// Please see https://developer.yahoo.com/flurry-pulse/ for more details. /// /// Should be called before StartSession. /// public static void SetPulseEnabled(bool enabled) { #if UNITY_IOS DebugLog("Set Pulse enabled: " + enabled); if (!IsIPhonePlayer()) { return; } FlurryAnalyticsSetPulseEnabled(enabled); #endif } /// /// Enables implicit recording of Apple Store transactions. /// true to enable transaction logging, false to stop transaction logging. /// /// This method should be called after StartSession. /// public static void SetIAPReportingEnabled(bool enabled) { #if UNITY_IOS DebugLog("Set IAP reporting enabled: " + enabled); if (!IsIPhonePlayer()) { return; } FlurryAnalyticsSetIAPReportingEnabled(enabled); #endif } /// /// Assign a unique id for a user in your app. /// public static void SetUserId(string userId) { #if UNITY_IOS DebugLog("Set unique user id: " + userId); if (!IsIPhonePlayer()) { return; } FlurryAnalyticsSetUserId(userId); #endif } /// /// Use this method to capture the age of your user. /// public static void SetAge(int age) { #if UNITY_IOS DebugLog("Set user age: " + age); if (!IsIPhonePlayer()) { return; } FlurryAnalyticsSetAge(age); #endif } /// /// Set user's gender. /// public static void SetGender(FlurryAnalytics.Gender gender) { #if UNITY_IOS DebugLog("Set user gender: " + gender); if (!IsIPhonePlayer()) { return; } FlurryAnalyticsSetGender((int)gender); #endif } /// /// Set the location of the session. /// Only the last location entered is captured per session. /// Regardless of accuracy specified, the Flurry SDK will only report location at city level or higher. /// Location is aggregated across all users of your app and not available on a per user basis. /// This information should only be captured if it is germaine to the use of your app. /// public static void SetLocation(float latitude, float longitude, float horizontalAccuracy, float verticalAccuracy) { #if UNITY_IOS DebugLog("Set location: " + latitude + ", " + longitude); if (!IsIPhonePlayer()) { return; } FlurryAnalyticsSetLatitude( latitude, longitude, horizontalAccuracy, verticalAccuracy); #endif } /// /// Records a custom event specified by eventName. /// /// /// Name of the event. For maximum effectiveness, we recommend using a naming scheme /// that can be easily understood by non-technical people in your business domain. /// /// If set to true this will be a timed event. /// Call EndTimedEvent to stop timed event. public static void LogEvent(string eventName, bool isTimed = false) { #if UNITY_IOS DebugLog("Log event: " + eventName + " isTimed: " + isTimed); if (!IsIPhonePlayer()) { return; } FlurryAnalyticsLogEvent(eventName, isTimed); #endif } /// /// Log custom event with parameters. /// A maximum of 10 parameter names may be associated with any event. /// /// /// Name of the event. For maximum effectiveness, we recommend using a naming scheme /// that can be easily understood by non-technical people in your business domain. /// /// Parameters. /// If set to true this will be a timed event. /// Call EndTimedEvent to stop timed event. public static void LogEventWithParameters(string eventName, Dictionary parameters, bool isTimed = false) { #if UNITY_IOS DebugLog("Log event: " + eventName + " isTimed: " + isTimed + " with parameters"); if (!IsIPhonePlayer()) { return; } FlurryAnalyticsLogEventWithParameters(eventName, ConvertParameters(parameters), isTimed); #endif } /// /// Ends the timed event. /// /// /// Name of the event. For maximum effectiveness, we recommend using a naming scheme /// that can be easily understood by non-technical people in your business domain. /// /// Parameters. public static void EndTimedEvent(string eventName, Dictionary parameters = null) { #if UNITY_IOS DebugLog("End timed event: " + eventName); if (!IsIPhonePlayer()) { return; } FlurryAnalyticsEndTimedEvent(eventName, ConvertParameters(parameters)); #endif } /// /// Sets the session reports on close enabled. /// Enabled by default. /// public static void SetSessionReportsOnCloseEnabled(bool enabled) { #if UNITY_IOS DebugLog("Set session reports on close: " + enabled); if (!IsIPhonePlayer()) { return; } FlurryAnalyticsSetSessionReportsOnCloseEnabled(enabled); #endif } /// /// Sets the session reports on pause enabled. /// Enabled by default. /// public static void SetSessionReportsOnPauseEnabled(bool enabled) { #if UNITY_IOS DebugLog("Set session reports on pause: " + enabled); if (!IsIPhonePlayer()) { return; } FlurryAnalyticsSetSessionReportsOnPauseEnabled(enabled); #endif } /// /// Converts the parameters to json. /// private static string ConvertParameters(Dictionary parameters) { if (parameters == null) { return null; } StringBuilder builder = new StringBuilder(); builder.Append("{\n"); var first = true; foreach (var pair in parameters) { if (!first) { builder.Append(','); } SerializeString(builder, pair.Key); builder.Append(":"); SerializeString(builder, pair.Value); first = false; } builder.Append("}\n"); return builder.ToString(); } /// /// Serialize string to json string. /// private static void SerializeString(StringBuilder builder, string str) { builder.Append('\"'); var charArray = str.ToCharArray(); foreach (var c in charArray) { switch (c) { case '"': builder.Append("\\\""); break; case '\\': builder.Append("\\\\"); break; case '\b': builder.Append("\\b"); break; case '\f': builder.Append("\\f"); break; case '\n': builder.Append("\\n"); break; case '\r': builder.Append("\\r"); break; case '\t': builder.Append("\\t"); break; default: var codepoint = System.Convert.ToInt32(c); if ((codepoint >= 32) && (codepoint <= 126)) { builder.Append(c); } else { builder.Append("\\u" + System.Convert.ToString(codepoint, 16).PadLeft(4, '0')); } break; } } builder.Append('\"'); } /// true if is iPhone player. private static bool IsIPhonePlayer() { return Application.platform == RuntimePlatform.IPhonePlayer; } private static bool EditorDebugLogEnabled() { #if UNITY_EDITOR return _editorDebugLogEnabled; #else return false; #endif } private static void DebugLog(string log) { if (!EditorDebugLogEnabled()) { return; } Debug.Log("[FlurryAnalyticsPlugin]: " + log); } private static void DebugLogError(string error) { Debug.Log("[FlurryAnalyticsPlugin]: " + error); } } }