From 10cdf0e85c535d4fcef0ef6f023d114b6b2a20a8 Mon Sep 17 00:00:00 2001 From: Emmanuelle Date: Tue, 5 Aug 2014 16:58:12 -0700 Subject: [PATCH] Measurement Protocol file --- .../GoogleAnalyticsV3/GoogleAnalyticsMPV3.cs | 385 ++++++++++++++++++ 1 file changed, 385 insertions(+) create mode 100644 source/Plugins/GoogleAnalyticsV3/GoogleAnalyticsMPV3.cs diff --git a/source/Plugins/GoogleAnalyticsV3/GoogleAnalyticsMPV3.cs b/source/Plugins/GoogleAnalyticsV3/GoogleAnalyticsMPV3.cs new file mode 100644 index 0000000..4f815ff --- /dev/null +++ b/source/Plugins/GoogleAnalyticsV3/GoogleAnalyticsMPV3.cs @@ -0,0 +1,385 @@ +/* + Copyright 2014 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +using UnityEngine; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; + +/* + GoogleAnalyticsMPV3 handles building hits using the Measurement Protocol. + Developers should call the methods in GoogleAnalyticsV3, which will call the + appropriate methods in this class if the application is built for platforms + other than Android and iOS. +*/ +public class GoogleAnalyticsMPV3 { + private string trackingCode; + private string bundleIdentifier; + private string appName; + private string appVersion; + private GoogleAnalyticsV3.DebugMode logLevel; + private bool anonymizeIP; + private bool dryRun; + private bool optOut; + private int sessionTimeout; + private string screenRes; + private string clientId; + private string url; + private float timeStarted; + private Dictionary trackerValues; + private bool startSessionOnNextHit = false; + private bool endSessionOnNextHit = false; + + public void InitializeTracker() { + if (GoogleAnalyticsV3.belowThreshold(logLevel, GoogleAnalyticsV3.DebugMode.INFO)) { + Debug.Log("Platform is not Android or iOS - " + + "hits will be sent using measurement protocol."); + } + screenRes = Screen.width + "x" + Screen.height; + clientId = SystemInfo.deviceUniqueIdentifier; + trackerValues = new Dictionary(); + string language = Application.systemLanguage.ToString(); + optOut = false; +#if !UNITY_WP8 + CultureInfo[] cultureInfos = CultureInfo.GetCultures(CultureTypes.AllCultures); + foreach (CultureInfo info in cultureInfos) { + if (info.EnglishName == Application.systemLanguage.ToString()) { + language = info.Name; + } + } +#endif + try { + url = "http://www.google-analytics.com/collect?v=1" + + AddRequiredMPParameter(Fields.LANGUAGE, language) + + AddRequiredMPParameter(Fields.SCREEN_RESOLUTION, screenRes) + + AddRequiredMPParameter(Fields.APP_NAME, appName) + + AddRequiredMPParameter(Fields.TRACKING_ID, trackingCode) + + AddRequiredMPParameter(Fields.APP_ID, bundleIdentifier) + + AddRequiredMPParameter(Fields.CLIENT_ID, clientId) + + AddRequiredMPParameter(Fields.APP_VERSION, appVersion); + if(anonymizeIP){ + url += AddOptionalMPParameter(Fields.ANONYMIZE_IP, 1); + } + if (GoogleAnalyticsV3.belowThreshold(logLevel, GoogleAnalyticsV3.DebugMode.VERBOSE)) { + Debug.Log("Base URL for hits: " + url); + } + } catch (Exception) { + if (GoogleAnalyticsV3.belowThreshold(logLevel, GoogleAnalyticsV3.DebugMode.WARNING)) { + Debug.Log("Error building url."); + } + } + } + + public void SetTrackerVal(Field field, object value) { + trackerValues[field] = value; + } + + private string AddTrackerVals() { + string vals = ""; + foreach (KeyValuePair pair in trackerValues){ + vals += AddOptionalMPParameter(pair.Key, pair.Value); + } + return vals; + } + + internal void StartSession() { + startSessionOnNextHit = true; + } + + internal void StopSession() { + endSessionOnNextHit = true; + } + + private void SendGaHitWithMeasurementProtocol(string url) { + if (dryRun || optOut) { + if (GoogleAnalyticsV3.belowThreshold(logLevel, GoogleAnalyticsV3.DebugMode.WARNING)) { + Debug.Log("Dry run or opt out enabled - hits will not be sent."); + } + return; + } + if (startSessionOnNextHit) { + url += AddOptionalMPParameter(Fields.SESSION_CONTROL, "start"); + startSessionOnNextHit = false; + } else if (endSessionOnNextHit) { + url += AddOptionalMPParameter(Fields.SESSION_CONTROL, "end"); + endSessionOnNextHit = false; + } + // Add random z to avoid caching + string newUrl = url + "&z=" + UnityEngine.Random.Range(0, 500); + if (GoogleAnalyticsV3.belowThreshold(logLevel, GoogleAnalyticsV3.DebugMode.VERBOSE)) { + Debug.Log(newUrl); + } + WWW request = new WWW(newUrl); + while (!request.isDone) { + } + if (request.responseHeaders.ContainsKey("STATUS")) { + if (request.responseHeaders["STATUS"] == "HTTP/1.1 200 OK") { + if (GoogleAnalyticsV3.belowThreshold(logLevel, GoogleAnalyticsV3.DebugMode.INFO)) { + Debug.Log("Successfully sent Google Analytics hit."); + } + } else { + if (GoogleAnalyticsV3.belowThreshold(logLevel, GoogleAnalyticsV3.DebugMode.WARNING)) { + Debug.LogWarning("Google Analytics hit request rejected with" + + "status code " + request.responseHeaders["STATUS"]); + } + } + } else { + if (GoogleAnalyticsV3.belowThreshold(logLevel, GoogleAnalyticsV3.DebugMode.WARNING)) { + Debug.LogWarning("Google Analytics hit request failed with error " + + request.error); + } + } + } + + private string AddRequiredMPParameter(Field parameter, object value) { + if (value == null) { + if (GoogleAnalyticsV3.belowThreshold(logLevel, GoogleAnalyticsV3.DebugMode.WARNING)) { + Debug.LogWarning("Value was null for required parameter " + parameter + ". Hit cannot be sent"); + } + throw new ArgumentNullException(); + } else { + return parameter + "=" + WWW.EscapeURL(value.ToString()); + } + } + + private string AddRequiredMPParameter(Field parameter, string value) { + if (value == null) { + if (GoogleAnalyticsV3.belowThreshold(logLevel, GoogleAnalyticsV3.DebugMode.WARNING)) { + Debug.LogWarning("Value was null for required parameter " + parameter + ". Hit cannot be sent"); + } + throw new ArgumentNullException(); + } else { + return parameter + "=" + WWW.EscapeURL(value); + } + } + + private string AddOptionalMPParameter(Field parameter, object value) { + if (value == null) { + return ""; + } else { + return parameter + "=" + WWW.EscapeURL(value.ToString()); + } + } + + private string AddOptionalMPParameter(Field parameter, string value) { + if (String.IsNullOrEmpty(value)) { + return ""; + } else { + return parameter + "=" + WWW.EscapeURL(value); + } + } + + private string AddCustomVariables(HitBuilder builder) { + String url = ""; + foreach(KeyValuePair entry in builder.GetCustomDimensions()) + { + if (entry.Value != null) { + url += Fields.CUSTOM_DIMENSION.ToString() + entry.Key + "=" + + WWW.EscapeURL(entry.Value.ToString()); + } + } + foreach(KeyValuePair entry in builder.GetCustomMetrics()) + { + if (entry.Value != null) { + url += Fields.CUSTOM_METRIC.ToString() + entry.Key + "=" + + WWW.EscapeURL(entry.Value.ToString()); + } + } + + if(!String.IsNullOrEmpty(url)){ + if (GoogleAnalyticsV3.belowThreshold(logLevel, GoogleAnalyticsV3.DebugMode.VERBOSE)) { + Debug.Log("Added custom variables to hit."); + } + } + return url; + } + + + private string AddCampaignParameters(HitBuilder builder) { + String url = ""; + url += AddOptionalMPParameter(Fields.CAMPAIGN_NAME, builder.GetCampaignName()); + url += AddOptionalMPParameter(Fields.CAMPAIGN_SOURCE, builder.GetCampaignSource()); + url += AddOptionalMPParameter(Fields.CAMPAIGN_MEDIUM, builder.GetCampaignMedium()); + url += AddOptionalMPParameter(Fields.CAMPAIGN_KEYWORD, builder.GetCampaignKeyword()); + url += AddOptionalMPParameter(Fields.CAMPAIGN_CONTENT, builder.GetCampaignContent()); + url += AddOptionalMPParameter(Fields.CAMPAIGN_ID, builder.GetCampaignID()); + url += AddOptionalMPParameter(Fields.GCLID, builder.GetGclid()); + url += AddOptionalMPParameter(Fields.DCLID, builder.GetDclid()); + + if(!String.IsNullOrEmpty(url)){ + if (GoogleAnalyticsV3.belowThreshold(logLevel, GoogleAnalyticsV3.DebugMode.VERBOSE)) { + Debug.Log("Added campaign parameters to hit. url:" + url); + } + } + return url; + } + + public void LogScreen(AppViewHitBuilder builder) { + trackerValues[Fields.SCREEN_NAME] = null; + + SendGaHitWithMeasurementProtocol(url + + AddRequiredMPParameter(Fields.HIT_TYPE, "appview") + + AddRequiredMPParameter(Fields.SCREEN_NAME, builder.GetScreenName()) + + AddCustomVariables(builder) + + AddCampaignParameters(builder) + + AddTrackerVals()); + } + + public void LogEvent(EventHitBuilder builder) { + trackerValues[Fields.EVENT_CATEGORY] = null; + trackerValues[Fields.EVENT_ACTION] = null; + trackerValues[Fields.EVENT_LABEL] = null; + trackerValues[Fields.EVENT_VALUE] = null; + + SendGaHitWithMeasurementProtocol(url + + AddRequiredMPParameter(Fields.HIT_TYPE, "event") + + AddOptionalMPParameter(Fields.EVENT_CATEGORY, builder.GetEventCategory()) + + AddOptionalMPParameter(Fields.EVENT_ACTION, builder.GetEventAction()) + + AddOptionalMPParameter(Fields.EVENT_LABEL, builder.GetEventLabel()) + + AddOptionalMPParameter(Fields.EVENT_VALUE, builder.GetEventValue()) + + AddCustomVariables(builder) + + AddCampaignParameters(builder) + + AddTrackerVals()); + } + + public void LogTransaction(TransactionHitBuilder builder) { + trackerValues[Fields.TRANSACTION_ID] = null; + trackerValues[Fields.TRANSACTION_AFFILIATION] = null; + trackerValues[Fields.TRANSACTION_REVENUE] = null; + trackerValues[Fields.TRANSACTION_SHIPPING] = null; + trackerValues[Fields.TRANSACTION_TAX] = null; + trackerValues[Fields.CURRENCY_CODE] = null; + + SendGaHitWithMeasurementProtocol(url + + AddRequiredMPParameter(Fields.HIT_TYPE, "transaction") + + AddRequiredMPParameter(Fields.TRANSACTION_ID, builder.GetTransactionID()) + + AddOptionalMPParameter(Fields.TRANSACTION_AFFILIATION, builder.GetAffiliation()) + + AddOptionalMPParameter(Fields.TRANSACTION_REVENUE, builder.GetRevenue()) + + AddOptionalMPParameter(Fields.TRANSACTION_SHIPPING, builder.GetShipping()) + + AddOptionalMPParameter(Fields.TRANSACTION_TAX, builder.GetTax()) + + AddOptionalMPParameter(Fields.CURRENCY_CODE, builder.GetCurrencyCode()) + + AddCustomVariables(builder) + + AddCampaignParameters(builder) + + AddTrackerVals()); + } + + public void LogItem(ItemHitBuilder builder) { + + trackerValues[Fields.TRANSACTION_ID] = null; + trackerValues[Fields.ITEM_NAME] = null; + trackerValues[Fields.ITEM_SKU] = null; + trackerValues[Fields.ITEM_CATEGORY] = null; + trackerValues[Fields.ITEM_PRICE] = null; + trackerValues[Fields.ITEM_QUANTITY] = null; + trackerValues[Fields.CURRENCY_CODE] = null; + + SendGaHitWithMeasurementProtocol(url + + AddRequiredMPParameter(Fields.HIT_TYPE, "item") + + AddRequiredMPParameter(Fields.TRANSACTION_ID, builder.GetTransactionID()) + + AddRequiredMPParameter(Fields.ITEM_NAME, builder.GetName()) + + AddOptionalMPParameter(Fields.ITEM_SKU, builder.GetSKU()) + + AddOptionalMPParameter(Fields.ITEM_CATEGORY, builder.GetCategory()) + + AddOptionalMPParameter(Fields.ITEM_PRICE, builder.GetPrice()) + + AddOptionalMPParameter(Fields.ITEM_QUANTITY, builder.GetQuantity()) + + AddOptionalMPParameter(Fields.CURRENCY_CODE, builder.GetCurrencyCode()) + + AddCustomVariables(builder) + + AddCampaignParameters(builder) + + AddTrackerVals()); + } + + public void LogException(ExceptionHitBuilder builder) { + + trackerValues[Fields.EX_DESCRIPTION] = null; + trackerValues[Fields.EX_FATAL] = null; + + SendGaHitWithMeasurementProtocol(url + + AddRequiredMPParameter(Fields.HIT_TYPE, "exception") + + AddOptionalMPParameter(Fields.EX_DESCRIPTION, builder.GetExceptionDescription()) + + AddOptionalMPParameter(Fields.EX_FATAL, builder.IsFatal()) + + AddTrackerVals()); + } + + public void LogSocial(SocialHitBuilder builder) { + + trackerValues[Fields.SOCIAL_NETWORK] = null; + trackerValues[Fields.SOCIAL_ACTION] = null; + trackerValues[Fields.SOCIAL_TARGET] = null; + + SendGaHitWithMeasurementProtocol(url + + AddRequiredMPParameter(Fields.HIT_TYPE, "social") + + AddRequiredMPParameter(Fields.SOCIAL_NETWORK, builder.GetSocialNetwork()) + + AddRequiredMPParameter(Fields.SOCIAL_ACTION, builder.GetSocialAction()) + + AddRequiredMPParameter(Fields.SOCIAL_TARGET, builder.GetSocialTarget()) + + AddCustomVariables(builder) + + AddCampaignParameters(builder) + + AddTrackerVals()); + } + + public void LogTiming(TimingHitBuilder builder) { + + trackerValues[Fields.TIMING_CATEGORY] = null; + trackerValues[Fields.TIMING_VALUE] = null; + trackerValues[Fields.TIMING_LABEL] = null; + trackerValues[Fields.TIMING_VAR] = null; + + SendGaHitWithMeasurementProtocol(url + + AddRequiredMPParameter(Fields.HIT_TYPE, "timing") + + AddOptionalMPParameter(Fields.TIMING_CATEGORY, builder.GetTimingCategory()) + + AddOptionalMPParameter(Fields.TIMING_VALUE, builder.GetTimingInterval()) + + AddOptionalMPParameter(Fields.TIMING_LABEL, builder.GetTimingLabel()) + + AddOptionalMPParameter(Fields.TIMING_VAR, builder.GetTimingName()) + + AddCustomVariables(builder) + + AddCampaignParameters(builder) + + AddTrackerVals()); + } + + public void ClearUserIDOverride() { + SetTrackerVal(Fields.USER_ID, null); + } + + public void SetTrackingCode(string trackingCode) { + this.trackingCode = trackingCode; + } + + public void SetBundleIdentifier(string bundleIdentifier) { + this.bundleIdentifier = bundleIdentifier; + } + + public void SetAppName(string appName) { + this.appName = appName; + } + + public void SetAppVersion(string appVersion) { + this.appVersion = appVersion; + } + + public void SetLogLevelValue(GoogleAnalyticsV3.DebugMode logLevel) { + this.logLevel = logLevel; + } + + public void SetAnonymizeIP(bool anonymizeIP) { + this.anonymizeIP = anonymizeIP; + } + + public void SetDryRun(bool dryRun) { + this.dryRun = dryRun; + } + + public void SetOptOut(bool optOut) { + this.optOut = optOut; + } +}