Skip to content

Commit 666c9b2

Browse files
Add cross client analytics tracking (#3176)
* Make analytics-settings-service getClientId public * Allow tracking for multiple Google Analytic Projects * Add cross client custom dimensions * Add npmVersion and dayFromFirstRun custom dimension values * Update cross client analytics google tracking id * Remove unnecessary custom dimensions from the cross client project * Add doc and public method test
1 parent b232fd5 commit 666c9b2

7 files changed

+73
-8
lines changed

PublicAPI.md

+22
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ const tns = require("nativescript");
3535
* [disableDebugging](#disableDebugging)
3636
* [getLiveSyncDeviceDescriptors](#getLiveSyncDeviceDescriptors)
3737
* [events](#events)
38+
* [analyticsSettingsService](#analyticsSettingsService)
39+
* [getClientId](#getClientId)
3840

3941

4042
## Module projectService
@@ -855,6 +857,26 @@ tns.liveSyncService.on("debuggerDetached", debugInfo => {
855857
console.log(`Detached debugger for device with id ${debugInfo.deviceIdentifier}`);
856858
});
857859
```
860+
## analyticsSettingsService
861+
Provides methods for accessing the analytics settings file data.
862+
863+
### getClientId
864+
The `getClientId` method allows retrieving the clientId used in the analytics tracking
865+
866+
* Definition:
867+
```TypeScript
868+
/**
869+
* Gets the clientId used for analytics tracking
870+
* @returns {Promise<string>} Client identifier in UUIDv4 standard.
871+
*/
872+
getClientId(): Promise<string>;
873+
```
874+
875+
* Usage:
876+
```JavaScript
877+
tns.analyticsSettingsService.getClientId()
878+
.then(clientId => console.log(clientId));
879+
```
858880
859881
## How to add a new method to Public API
860882
CLI is designed as command line tool and when it is used as a library, it does not give you access to all of the methods. This is mainly implementation detail. Most of the CLI's code is created to work in command line, not as a library, so before adding method to public API, most probably it will require some modification.

lib/bootstrap.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ $injector.require("iOSDebugService", "./services/ios-debug-service");
2929
$injector.require("androidDebugService", "./services/android-debug-service");
3030

3131
$injector.require("userSettingsService", "./services/user-settings-service");
32-
$injector.require("analyticsSettingsService", "./services/analytics-settings-service");
32+
$injector.requirePublic("analyticsSettingsService", "./services/analytics-settings-service");
3333
$injector.require("analyticsService", "./services/analytics/analytics-service");
3434
$injector.require("eqatecAnalyticsProvider", "./services/analytics/eqatec-analytics-provider");
3535
$injector.require("googleAnalyticsProvider", "./services/analytics/google-analytics-provider");

lib/services/analytics-settings-service.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { createGUID } from "../common/helpers";
2+
import { exported } from "../common/decorators";
23

34
class AnalyticsSettingsService implements IAnalyticsSettingsService {
45
private static SESSIONS_STARTED_KEY_PREFIX = "SESSIONS_STARTED_";
@@ -15,6 +16,7 @@ class AnalyticsSettingsService implements IAnalyticsSettingsService {
1516
return this.getSettingValueOrDefault("USER_ID");
1617
}
1718

19+
@exported("analyticsSettingsService")
1820
public getClientId(): Promise<string> {
1921
return this.getSettingValueOrDefault(this.$staticConfig.ANALYTICS_INSTALLATION_ID_SETTING_NAME);
2022
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Sync indexes with the custom dimensions of the cross client analytics project
2+
declare const enum GoogleAnalyticsCrossClientCustomDimensions {
3+
sessionId = "cd9",
4+
clientId = "cd10",
5+
crossClientId = "cd12",
6+
}

lib/services/analytics/google-analytics-custom-dimensions.ts renamed to lib/services/analytics/google-analytics-custom-dimensions.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const enum GoogleAnalyticsCustomDimensions {
1+
declare const enum GoogleAnalyticsCustomDimensions {
22
cliVersion = "cd1",
33
projectType = "cd2",
44
clientID = "cd3",

lib/services/analytics/google-analytics-provider.ts

+39-5
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,46 @@ import { AnalyticsClients } from "../../common/constants";
44

55
export class GoogleAnalyticsProvider implements IGoogleAnalyticsProvider {
66
private static GA_TRACKING_ID = "UA-111455-44";
7+
private static GA_CROSS_CLIENT_TRACKING_ID = "UA-111455-51";
78
private currentPage: string;
89

910
constructor(private clientId: string,
1011
private $staticConfig: IStaticConfig,
1112
private $hostInfo: IHostInfo,
12-
private $osInfo: IOsInfo) {
13+
private $osInfo: IOsInfo,
14+
private $logger: ILogger) {
1315
}
1416

1517
public async trackHit(trackInfo: IGoogleAnalyticsData): Promise<void> {
18+
const trackingIds = [GoogleAnalyticsProvider.GA_TRACKING_ID, GoogleAnalyticsProvider.GA_CROSS_CLIENT_TRACKING_ID];
19+
const sessionId = uuid.v4();
20+
21+
for (const gaTrackingId of trackingIds) {
22+
try {
23+
await this.track(gaTrackingId, trackInfo, sessionId);
24+
} catch (e) {
25+
this.$logger.trace("Analytics exception: ", e);
26+
}
27+
}
28+
}
29+
30+
private async track(gaTrackingId: string, trackInfo: IGoogleAnalyticsData, sessionId: string): Promise<void> {
1631
const visitor = ua({
17-
tid: GoogleAnalyticsProvider.GA_TRACKING_ID,
32+
tid: gaTrackingId,
1833
cid: this.clientId,
1934
headers: {
2035
["User-Agent"]: this.getUserAgentString()
2136
}
2237
});
2338

24-
this.setCustomDimensions(visitor, trackInfo.customDimensions);
39+
switch (gaTrackingId) {
40+
case GoogleAnalyticsProvider.GA_CROSS_CLIENT_TRACKING_ID:
41+
this.setCrossClientCustomDimensions(visitor, sessionId);
42+
break;
43+
default:
44+
this.setCustomDimensions(visitor, trackInfo.customDimensions, sessionId);
45+
break;
46+
}
2547

2648
switch (trackInfo.googleAnalyticsDataType) {
2749
case GoogleAnalyticsDataType.Page:
@@ -33,13 +55,13 @@ export class GoogleAnalyticsProvider implements IGoogleAnalyticsProvider {
3355
}
3456
}
3557

36-
private setCustomDimensions(visitor: ua.Visitor, customDimensions: IStringDictionary): void {
58+
private setCustomDimensions(visitor: ua.Visitor, customDimensions: IStringDictionary, sessionId: string): void {
3759
const defaultValues: IStringDictionary = {
3860
[GoogleAnalyticsCustomDimensions.cliVersion]: this.$staticConfig.version,
3961
[GoogleAnalyticsCustomDimensions.nodeVersion]: process.version,
4062
[GoogleAnalyticsCustomDimensions.clientID]: this.clientId,
4163
[GoogleAnalyticsCustomDimensions.projectType]: null,
42-
[GoogleAnalyticsCustomDimensions.sessionID]: uuid.v4(),
64+
[GoogleAnalyticsCustomDimensions.sessionID]: sessionId,
4365
[GoogleAnalyticsCustomDimensions.client]: AnalyticsClients.Unknown
4466
};
4567

@@ -50,6 +72,18 @@ export class GoogleAnalyticsProvider implements IGoogleAnalyticsProvider {
5072
});
5173
}
5274

75+
private async setCrossClientCustomDimensions(visitor: ua.Visitor, sessionId: string): Promise<void> {
76+
const customDimensions: IStringDictionary = {
77+
[GoogleAnalyticsCrossClientCustomDimensions.sessionId]: sessionId,
78+
[GoogleAnalyticsCrossClientCustomDimensions.clientId]: this.clientId,
79+
[GoogleAnalyticsCrossClientCustomDimensions.crossClientId]: this.clientId,
80+
};
81+
82+
_.each(customDimensions, (value, key) => {
83+
visitor.set(key, value);
84+
});
85+
}
86+
5387
private trackEvent(visitor: ua.Visitor, trackInfo: IGoogleAnalyticsEventData): Promise<void> {
5488
return new Promise<void>((resolve, reject) => {
5589
visitor.event(trackInfo.category, trackInfo.action, trackInfo.label, trackInfo.value, { p: this.currentPage }, (err: Error) => {

test/nativescript-cli-lib.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ describe("nativescript-cli-lib", () => {
2121
npm: ["install", "uninstall", "view", "search"],
2222
extensibilityService: ["loadExtensions", "loadExtension", "getInstalledExtensions", "installExtension", "uninstallExtension"],
2323
liveSyncService: ["liveSync", "stopLiveSync", "enableDebugging", "disableDebugging", "attachDebugger"],
24-
debugService: ["debug"]
24+
debugService: ["debug"],
25+
analyticsSettingsService: ["getClientId"]
2526
};
2627

2728
const pathToEntryPoint = path.join(__dirname, "..", "lib", "nativescript-cli-lib.js").replace(/\\/g, "\\\\");

0 commit comments

Comments
 (0)