diff --git a/README.md b/README.md
index 5205ce41..a58631ec 100644
--- a/README.md
+++ b/README.md
@@ -76,7 +76,10 @@ window.ga.trackEvent('Category', 'Action', 'Label', Value)// Label and Value are
window.ga.trackEvent('Category', 'Action', 'Label', Value, true)// Label, Value and newSession are optional, Value is numeric, newSession is true/false
//To track custom metrics:
-window.ga.trackMetric(key, Value)// Key and value are numeric type, Value is optional
+//(trackMetric doesn't actually send a hit, it's behaving more like the addCustomDimension() method.
+// The metric is afterwards added to every hit (view, event, error, etc...) sent, but the defined scope of the custom metric in analytics backend
+// (hit or product) will determine, at processing time, which hits are associated with the metric value.)
+window.ga.trackMetric(Key, Value) // Key and value are numeric type
//To track an Exception:
window.ga.trackException('Description', Fatal)//where Fatal is boolean
@@ -91,7 +94,9 @@ window.ga.addTransaction('ID', 'Affiliation', Revenue, Tax, Shipping, 'Currency
window.ga.addTransactionItem('ID', 'Name', 'SKU', 'Category', Price, Quantity, 'Currency Code')// where Price and Quantity are numeric
//To add a Custom Dimension
-window.ga.addCustomDimension('Key', 'Value', success, error)
+//(The dimension is afterwards added to every hit (view, event, error, etc...) sent, but the defined scope of the custom dimension in analytics backend
+// (hit or product) will determine, at processing time, which hits are associated with the dimension value.)
+window.ga.addCustomDimension(Key, 'Value', success, error)
//Key should be integer index of the dimension i.e. send `1` instead of `dimension1` for the first custom dimension you are tracking. e.g. `window.ga.addCustomDimension(1, 'Value', success, error)`
//To set a UserId:
@@ -125,7 +130,7 @@ window.ga.debugMode()
// set's dry run mode on Android and Windows platform, so that all hits are only echoed back by the google analytics service and no actual hit is getting tracked!
// **Android quirk**: verbose logging within javascript console is not supported. To see debug responses from analytics execute
// `adb shell setprop log.tag.GAv4 DEBUG` and then `adb logcat -v time -s GAv4` to list messages
-// (see [Android SDK Documentation on deprected Logger class](https://developers.google.com/android/reference/com/google/android/gms/analytics/Logger))
+// (see https://developers.google.com/android/reference/com/google/android/gms/analytics/Logger)
//To enable/disable automatic reporting of uncaught exceptions
window.ga.enableUncaughtExceptionReporting(Enable, success, error)// where Enable is boolean
@@ -157,6 +162,9 @@ import { Platform } from 'ionic-angular';
}
```
+**Issue for using trackMetric in Ionic 2**: currently `@ionic-native/google-analytics` defines the typescript signature with `trackMetric(key: string, value?: any)`.
+So be aware to pass the metric index as a string formatted integer and a non empty string as a value, like `window.ga.trackMetric('1', 'Value', success, error)`!
+
# Installing Without the CLI
Copy the files manually into your project and add the following to your config.xml files:
@@ -221,4 +229,7 @@ The following plugin methods are (currently) not supported by the UWP.SDKforGoog
Unexpected behaviour may occur on the following methods:
* `trackView()`: campaign details are currently not supported and therefore not tracked.
+* `trackMetric()`: there is currently a bug in version 1.5.2 of the [UWP.SDKforGoogleAnalytics.Native package via NuGet](http://nuget.org/packages/UWP.SDKforGoogleAnalytics.Native),
+that the wrong data specifier `cd` is taken for metrics, whereas `cm` should be the correct specifier.
+So as long as this bug is not fixed, trackMetrics will overwrite previous addCustomDimension with same index!!
diff --git a/android/UniversalAnalyticsPlugin.java b/android/UniversalAnalyticsPlugin.java
index 5e12ce31..606e976e 100644
--- a/android/UniversalAnalyticsPlugin.java
+++ b/android/UniversalAnalyticsPlugin.java
@@ -41,6 +41,7 @@ public class UniversalAnalyticsPlugin extends CordovaPlugin {
public Boolean trackerStarted = false;
public Boolean debugModeEnabled = false;
public HashMap customDimensions = new HashMap();
+ public HashMap customMetrics = new HashMap();
public Tracker tracker;
@@ -177,9 +178,9 @@ private void addCustomDimension(Integer key, String value, CallbackContext callb
callbackContext.success("custom dimension started");
}
- private void addCustomDimensionsToHitBuilder(T builder) {
+ private void addCustomDimensionsAndMetricsToHitBuilder(T builder) {
//unfortunately the base HitBuilders.HitBuilder class is not public, therefore have to use reflection to use
- //the common setCustomDimension (int index, String dimension) method
+ //the common setCustomDimension (int index, String dimension) and setCustomMetrics (int index, Float metric) methods
try {
Method builderMethod = builder.getClass().getMethod("setCustomDimension", Integer.TYPE, String.class);
@@ -196,6 +197,23 @@ private void addCustomDimensionsToHitBuilder(T builder) {
} catch (SecurityException e) {
} catch (NoSuchMethodException e) {
}
+
+ try {
+ Method builderMethod = builder.getClass().getMethod("setCustomMetric", Integer.TYPE, Float.TYPE);
+
+ for (Entry entry : customMetrics.entrySet()) {
+ Integer key = entry.getKey();
+ Float value = entry.getValue();
+ try {
+ builderMethod.invoke(builder, (key), value);
+ } catch (IllegalArgumentException e) {
+ } catch (IllegalAccessException e) {
+ } catch (InvocationTargetException e) {
+ }
+ }
+ } catch (SecurityException e) {
+ } catch (NoSuchMethodException e) {
+ }
}
private void trackView(String screenname, String campaignUrl, boolean newSession, CallbackContext callbackContext) {
@@ -208,7 +226,7 @@ private void trackView(String screenname, String campaignUrl, boolean newSession
tracker.setScreenName(screenname);
HitBuilders.ScreenViewBuilder hitBuilder = new HitBuilders.ScreenViewBuilder();
- addCustomDimensionsToHitBuilder(hitBuilder);
+ addCustomDimensionsAndMetricsToHitBuilder(hitBuilder);
if(!campaignUrl.equals("")){
hitBuilder.setCampaignParamsFromUrl(campaignUrl);
@@ -234,7 +252,7 @@ private void trackEvent(String category, String action, String label, long value
if (null != category && category.length() > 0) {
HitBuilders.EventBuilder hitBuilder = new HitBuilders.EventBuilder();
- addCustomDimensionsToHitBuilder(hitBuilder);
+ addCustomDimensionsAndMetricsToHitBuilder(hitBuilder);
if(!newSession){
tracker.send(hitBuilder
@@ -260,21 +278,26 @@ private void trackEvent(String category, String action, String label, long value
}
private void trackMetric(Integer key, String value, CallbackContext callbackContext) {
- if (!trackerStarted) {
- callbackContext.error("Tracker not started");
+ if (key <= 0) {
+ callbackContext.error("Expected positive integer argument for key.");
return;
}
- if (key >= 0) {
- HitBuilders.ScreenViewBuilder hitBuilder = new HitBuilders.ScreenViewBuilder();
- tracker.send(hitBuilder
- .setCustomMetric(key, Float.parseFloat(value))
- .build()
- );
- callbackContext.success("Track Metric: " + key + ", value: " + value);
- } else {
- callbackContext.error("Expected integer key: " + key + ", and string value: " + value);
+ if (null == value || value.length() == 0) {
+ callbackContext.error("Expected non-empty string argument for value.");
+ return;
}
+
+ Float floatValue;
+ try {
+ floatValue = Float.parseFloat(value);
+ } catch (NumberFormatException e) {
+ callbackContext.error("Expected string formatted number for value.");
+ return;
+ }
+
+ customMetrics.put(key, floatValue);
+ callbackContext.success("custom metric started");
}
private void trackException(String description, Boolean fatal, CallbackContext callbackContext) {
@@ -285,7 +308,7 @@ private void trackException(String description, Boolean fatal, CallbackContext c
if (null != description && description.length() > 0) {
HitBuilders.ExceptionBuilder hitBuilder = new HitBuilders.ExceptionBuilder();
- addCustomDimensionsToHitBuilder(hitBuilder);
+ addCustomDimensionsAndMetricsToHitBuilder(hitBuilder);
tracker.send(hitBuilder
.setDescription(description)
@@ -306,7 +329,7 @@ private void trackTiming(String category, long intervalInMilliseconds, String na
if (null != category && category.length() > 0) {
HitBuilders.TimingBuilder hitBuilder = new HitBuilders.TimingBuilder();
- addCustomDimensionsToHitBuilder(hitBuilder);
+ addCustomDimensionsAndMetricsToHitBuilder(hitBuilder);
tracker.send(hitBuilder
.setCategory(category)
@@ -329,7 +352,7 @@ private void addTransaction(String id, String affiliation, double revenue, doubl
if (null != id && id.length() > 0) {
HitBuilders.TransactionBuilder hitBuilder = new HitBuilders.TransactionBuilder();
- addCustomDimensionsToHitBuilder(hitBuilder);
+ addCustomDimensionsAndMetricsToHitBuilder(hitBuilder);
tracker.send(hitBuilder
.setTransactionId(id)
@@ -353,7 +376,7 @@ private void addTransactionItem(String id, String name, String sku, String categ
if (null != id && id.length() > 0) {
HitBuilders.ItemBuilder hitBuilder = new HitBuilders.ItemBuilder();
- addCustomDimensionsToHitBuilder(hitBuilder);
+ addCustomDimensionsAndMetricsToHitBuilder(hitBuilder);
tracker.send(hitBuilder
.setTransactionId(id)
diff --git a/windows/GoogleAnalyticsProxy.js b/windows/GoogleAnalyticsProxy.js
index b101a6d2..4623cb9c 100644
--- a/windows/GoogleAnalyticsProxy.js
+++ b/windows/GoogleAnalyticsProxy.js
@@ -3,12 +3,13 @@
var _supported = null; // set to null so we can check first time
var _tracker = null;
var _customDimensions = {};
+var _customMetrics = {};
function isSupported() {
// if not checked before, run check
if (_supported === null) {
_supported = (GoogleAnalytics && GoogleAnalytics.AnalyticsManager && GoogleAnalytics.AnalyticsManager.current &&
- GoogleAnalytics.HitBuilder);
+ GoogleAnalytics.HitBuilder);
}
return _supported;
}
@@ -66,12 +67,8 @@ function uncaughtExceptionHandler(err) {
try {
var hit = GoogleAnalytics.HitBuilder.createException(err.message, true);
- // add previously added custom dimensions
- for (var key in _customDimensions) {
- if (_customDimensions.hasOwnProperty(key)) {
- hit = hit.setCustomDimension(key, _customDimensions[key]);
- }
- }
+ // add previously added custom dimensions and metrics
+ hit = addCustomDimensionsAndMetrics(hit);
const data = hit.build();
getTracker().send(data);
@@ -81,9 +78,28 @@ function uncaughtExceptionHandler(err) {
return true;
}
+function addCustomDimensionsAndMetrics(hitBuilder) {
+ if (hitBuilder) {
+ // add previously added custom dimensions
+ for (var key in _customDimensions) {
+ if (_customDimensions.hasOwnProperty(key)) {
+ hitBuilder = hitBuilder.setCustomDimension(key, _customDimensions[key]);
+ }
+ }
+
+ // add previously added custom metrics
+ for (var key in _customMetrics) {
+ if (_customMetrics.hasOwnProperty(key)) {
+ hitBuilder = hitBuilder.setCustomMetric(key, _customMetrics[key]);
+ }
+ }
+ }
+ return hitBuilder;
+}
+
module.exports = {
- setOptOut: function(win, fail, args) {
+ setOptOut: function (win, fail, args) {
if (!args || args.length === 0 || typeof args[0] !== "boolean") {
fail("Expected boolean argument");
return;
@@ -93,7 +109,7 @@ module.exports = {
win();
},
- enableUncaughtExceptionReporting: function(win, fail, args) {
+ enableUncaughtExceptionReporting: function (win, fail, args) {
if (!args || args.length === 0 || typeof args[0] !== "boolean") {
fail("Expected boolean argument");
return;
@@ -114,23 +130,23 @@ module.exports = {
win();
},
- dispatch: function(win, fail, args) {
+ dispatch: function (win, fail, args) {
getAnalyticsManager().dispatchAsync().done(win, fail);
},
- debugMode: function(win, fail, args) {
+ debugMode: function (win, fail, args) {
const ga = getAnalyticsManager();
ga.isDebug = true;
// hook debug events
ga.addEventListener("hitfailed", onHitFailed);
ga.addEventListener("hitsent", onHitSent);
- ga.addEventListener("hitmailformed", onHitMalformed);
+ ga.addEventListener("hitmailformed", onHitMalformed);
win();
},
- startTrackerWithId: function(win, fail, args) {
+ startTrackerWithId: function (win, fail, args) {
if (!args || args.length === 0 || args[0] === "") {
fail("Expected non empty string argument");
return;
@@ -140,7 +156,7 @@ module.exports = {
fail("Expected numeric integer argument");
return;
}
-
+
if (isTrackerStarted()) {
fail("Tracker already started!");
return;
@@ -158,8 +174,8 @@ module.exports = {
_tracker = ga.createTracker(args[0]);
win();
},
-
- setUserId: function(win, fail, args) {
+
+ setUserId: function (win, fail, args) {
if (!args || args.length === 0 || args[0] === "") {
fail("Expected non empty string argument");
return;
@@ -169,7 +185,7 @@ module.exports = {
win();
},
- setAnonymizeIp: function(win, fail, args) {
+ setAnonymizeIp: function (win, fail, args) {
if (!args || args.length === 0 || typeof args[0] !== "boolean") {
fail("Expected boolean argument");
return;
@@ -179,12 +195,12 @@ module.exports = {
win();
},
- setAllowIDFACollection: function() {
+ setAllowIDFACollection: function () {
// not supported
fail("not supported on Windows platform");
},
- setAppVersion: function(win, fail, args) {
+ setAppVersion: function (win, fail, args) {
if (!args || args.length === 0 || args[0] === "") {
fail("Expected non empty string argument");
return;
@@ -194,58 +210,60 @@ module.exports = {
win();
},
- getVar: function(win, fail, args) {
+ getVar: function (win, fail, args) {
if (!args || args.length === 0 || args[0] === "") {
fail("Expected non empty string argument");
return;
}
-
+
const value = getTracker().get(args[0]);
win(value);
},
- setVar: function(win, fail, args) {
+ setVar: function (win, fail, args) {
if (!args || args.length === 0 || args[0] === "") {
fail("Expected non empty string argument");
return;
}
-
+
getTracker().set(args[0], args[1]);
win();
},
- trackMetric: function(win, fail, args) {
- if (!args || args.length === 0) {
- fail("Expected positive numeric integer argument");
- return;
- }
- const key = Number.parseInt(args[0]);
- if (Number.isNaN(key) || key < 0) {
+ trackMetric: function (win, fail, args) {
+ if (!args || args.length === 0 || !Number.isInteger(args[0]) || args[0] < 0) {
fail("Expected positive numeric integer argument");
return;
}
-
- var metric = Number.NaN;
- if (args.length >= 2) {
- metric = Number.parseFloat(String(args[1]));
- }
- if (Number.isNaN(metric)) {
- fail("Expected numeric integer argument");
+
+ if (args.length < 1) {
+ fail("Expected second argument");
return;
+ }
+ var value = args[1];
+ if (typeof args[1] !== "number") {
+ if (typeof args[1] !== "string") {
+ fail("Expected either numeric or string formatted number argument");
+ return;
+ }
+ value = Number.parseFloat(args[1]);
+ if (isNaN(value)) {
+ fail("Expected either numeric or string formatted number argument");
+ return;
+ }
}
- const data = GoogleAnalytics.HitBuilder.createScreenView().setCustomMetric(key, metric).build();
- getTracker().send(data);
+ _customMetrics[args[0]] = value;
win();
},
- addCustomDimension: function(win, fail, args) {
+ addCustomDimension: function (win, fail, args) {
if (!args || args.length === 0 || !Number.isInteger(args[0]) || args[0] < 0) {
fail("Expected positive numeric integer argument");
return;
}
- if (args.length < 1 || args[2] === "") {
+ if (args.length < 1 || args[1] === "") {
fail("Expected non empty string argument");
return;
}
@@ -254,30 +272,26 @@ module.exports = {
win();
},
- addTransaction: function(win, fail, args) {
+ addTransaction: function (win, fail, args) {
// not supported
fail("not supported on Windows platform");
},
- addTransactionItem: function(win, fail, args) {
+ addTransactionItem: function (win, fail, args) {
// not supported
fail("not supported on Windows platform");
},
- trackView: function(win, fail, args) {
+ trackView: function (win, fail, args) {
if (!args || args.length === 0 || args[0] === "") {
fail("Expected non empty string argument");
return;
}
var hit = GoogleAnalytics.HitBuilder.createScreenView(args[0]);
-
- // add previously added custom dimensions
- for (var key in _customDimensions) {
- if (_customDimensions.hasOwnProperty(key)) {
- hit = hit.setCustomDimension(key, _customDimensions[key]);
- }
- }
+
+ // add previously added custom dimensions and metrics
+ hit = addCustomDimensionsAndMetrics(hit);
if (args.length >= 2 && args[1] !== "" && getAnalyticsManager().isDebug === true) {
console.warn("Campaign details not supported on Windows platform!");
@@ -292,7 +306,7 @@ module.exports = {
win();
},
- trackEvent: function(win, fail, args) {
+ trackEvent: function (win, fail, args) {
if (!args || args.length < 2 || args[0] === "" || args[1] === "") {
fail("Expected non empty string argument");
return;
@@ -305,19 +319,15 @@ module.exports = {
var hit = GoogleAnalytics.HitBuilder.createCustomEvent(args[0], args[1], args[2] || null, args[3] || 0);
- // add previously added custom dimensions
- for (var key in _customDimensions) {
- if (_customDimensions.hasOwnProperty(key)) {
- hit = hit.setCustomDimension(key, _customDimensions[key]);
- }
- }
+ // add previously added custom dimensions and metrics
+ hit = addCustomDimensionsAndMetrics(hit);
const data = hit.build();
getTracker().send(data);
win();
},
- trackException: function(win, fail, args) {
+ trackException: function (win, fail, args) {
if (!args || args.length === 0 || args[0] === "") {
fail("Expected non empty string argument");
return;
@@ -326,19 +336,15 @@ module.exports = {
const fatal = ((args[1] || false) === true);
var hit = GoogleAnalytics.HitBuilder.createException(args[0], fatal);
- // add previously added custom dimensions
- for (var key in _customDimensions) {
- if (_customDimensions.hasOwnProperty(key)) {
- hit = hit.setCustomDimension(key, _customDimensions[key]);
- }
- }
+ // add previously added custom dimensions and metrics
+ hit = addCustomDimensionsAndMetrics(hit);
const data = hit.build();
getTracker().send(data);
win();
},
- trackTiming: function(win, fail, args) {
+ trackTiming: function (win, fail, args) {
if (!args || args.length === 0 || args[0] === "") {
fail("Expected non empty string argument");
return;
@@ -354,20 +360,16 @@ module.exports = {
return;
}
- var hit = GoogleAnalytics.HitBuilder.createTiming(args[0], args[2] || null,
- args[1] || 0, args[3] || null);
+ var hit = GoogleAnalytics.HitBuilder.createTiming(args[0], args[2] || null,
+ args[1] || 0, args[3] || null);
- // add previously added custom dimensions
- for (var key in _customDimensions) {
- if (_customDimensions.hasOwnProperty(key)) {
- hit = hit.setCustomDimension(key, _customDimensions[key]);
- }
- }
+ // add previously added custom dimensions and metrics
+ hit = addCustomDimensionsAndMetrics(hit);
const data = hit.build();
getTracker().send(data);
win();
}
-
+
};
require("cordova/exec/proxy").add("UniversalAnalytics", module.exports);
diff --git a/www/analytics.js b/www/analytics.js
index 03b4a9d4..b96f9b25 100644
--- a/www/analytics.js
+++ b/www/analytics.js
@@ -51,7 +51,24 @@ UniversalAnalyticsPlugin.prototype.debugMode = function(success, error) {
};
UniversalAnalyticsPlugin.prototype.trackMetric = function(key, value, success, error) {
- cordova.exec(success, error, 'UniversalAnalytics', 'trackMetric', [key, value]);
+ // as key was formerly documented to be of type string,
+ // we need to at least accept string formatted numbers and pass the converted number
+ var numberKey = key;
+ if (typeof key === "string") {
+ numberKey = Number.parseInt(key);
+ if (isNaN(numberKey)) {
+ throw Error("key must be a valid integer or string formatted integer");
+ }
+ }
+
+ // as value was formerly documented to be of type string
+ // and therefore platform implementations expect value parameter of type string,
+ // we need to cast the value parameter to string - although gathered metrics are infact number types.
+ var stringValue = value;
+ if (typeof value !== "string") {
+ stringValue = String(value);
+ }
+ cordova.exec(success, error, 'UniversalAnalytics', 'trackMetric', [numberKey, stringValue]);
};
UniversalAnalyticsPlugin.prototype.trackView = function(screen, campaignUrl, newSession, success, error) {