diff --git a/packages/expo-firebase-analytics/CHANGELOG.md b/packages/expo-firebase-analytics/CHANGELOG.md index 6a294c6841ff4..6cfd778faca6d 100644 --- a/packages/expo-firebase-analytics/CHANGELOG.md +++ b/packages/expo-firebase-analytics/CHANGELOG.md @@ -7,3 +7,5 @@ ### 🎉 New features ### 🐛 Bug fixes + +- Fix `expo-firebase-analytics` not recording events on the Expo client running on certain Android devices. ([#7192](https://github.com/expo/expo/pull/7679) by [@IjzerenHein](https://github.com/IjzerenHein)) diff --git a/packages/expo-firebase-analytics/build/ExpoFirebaseAnalytics.js b/packages/expo-firebase-analytics/build/ExpoFirebaseAnalytics.js index c951b90c0506b..5459c6e560143 100644 --- a/packages/expo-firebase-analytics/build/ExpoFirebaseAnalytics.js +++ b/packages/expo-firebase-analytics/build/ExpoFirebaseAnalytics.js @@ -31,6 +31,11 @@ function callAnalyticsModule(funcName, ...args) { strictNativeEmulation: true, appName: Constants.manifest?.name || 'Unnamed Expo project', appVersion: Constants.nativeAppVersion || undefined, + headers: { + // Google Analaytics seems to ignore certain user-agents. (e.g. "okhttp/3.12.1") + // Set a user-agent that clearly identifies the Expo client. + 'user-agent': `Expo/${Constants.nativeAppVersion}`, + }, }); } if (pureJSAnalyticsTracker) { diff --git a/packages/expo-firebase-analytics/build/ExpoFirebaseAnalytics.js.map b/packages/expo-firebase-analytics/build/ExpoFirebaseAnalytics.js.map index acdfac325eaa6..36cdb56e78984 100644 --- a/packages/expo-firebase-analytics/build/ExpoFirebaseAnalytics.js.map +++ b/packages/expo-firebase-analytics/build/ExpoFirebaseAnalytics.js.map @@ -1 +1 @@ -{"version":3,"file":"ExpoFirebaseAnalytics.js","sourceRoot":"","sources":["../src/ExpoFirebaseAnalytics.ts"],"names":[],"mappings":"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","sourcesContent":["import { NativeModulesProxy, UnavailabilityError, CodedError } from '@unimodules/core';\nimport Constants from 'expo-constants';\nimport { DEFAULT_APP_NAME, DEFAULT_APP_OPTIONS, DEFAULT_WEB_APP_OPTIONS } from 'expo-firebase-core';\nimport { Platform } from 'react-native';\n\nimport FirebaseAnalyticsJS from './FirebaseAnalyticsJS';\nconst { ExpoFirebaseAnalytics } = NativeModulesProxy;\n\nif (!ExpoFirebaseAnalytics) {\n console.warn(\n \"No native ExpoFirebaseAnalytics module found, are you sure the expo-firebase-analytics's module is linked properly?\"\n );\n}\n\nlet pureJSAnalyticsTracker: FirebaseAnalyticsJS | void;\nlet isUnavailabilityLoggingEnabled = true;\nlet isUnavailabilityWarningLogged = false;\n\nfunction callAnalyticsModule(funcName: string, ...args) {\n if (!ExpoFirebaseAnalytics[funcName]) {\n throw new UnavailabilityError('expo-firebase-analytics', funcName);\n }\n if (!DEFAULT_APP_OPTIONS) {\n throw new CodedError(\n 'ERR_FIREBASE_NOTCONFIGURED',\n `Firebase is not configured. Ensure that you have configured '${Platform.select({\n ios: 'GoogleService-Info.plist',\n android: 'google-services.json',\n })}' correctly.`\n );\n }\n\n // Analytics is only available for the [DEFAULT] app. On the Expo client\n // a sandboxed app is returned which does not support analytics.\n // In that case we show a warning and log the analytics events to the console.\n // The user can disable these by calling `setUnavailabilityLogging(false)`.\n if (DEFAULT_APP_NAME !== '[DEFAULT]') {\n if (DEFAULT_WEB_APP_OPTIONS && !pureJSAnalyticsTracker) {\n pureJSAnalyticsTracker = new FirebaseAnalyticsJS(DEFAULT_WEB_APP_OPTIONS, {\n clientId: Constants.sessionId,\n strictNativeEmulation: true,\n appName: Constants.manifest?.name || 'Unnamed Expo project',\n appVersion: Constants.nativeAppVersion || undefined,\n });\n }\n if (pureJSAnalyticsTracker) {\n return pureJSAnalyticsTracker[funcName].call(pureJSAnalyticsTracker, ...args);\n }\n if (isUnavailabilityLoggingEnabled) {\n if (!isUnavailabilityWarningLogged) {\n console.warn(\n `Firebase Analytics is not available in the Expo client. See \"https://docs.expo.io/versions/latest/sdk/firebase-analytics\" on more information on setting up Firebase Analytics with the standard Expo client.`\n );\n isUnavailabilityWarningLogged = true;\n }\n console.info(`ExpoFirebaseAnalytics.${funcName}: ${JSON.stringify(args)}`);\n }\n return;\n }\n\n // Make the call\n return ExpoFirebaseAnalytics[funcName].call(ExpoFirebaseAnalytics, ...args);\n}\n\nexport default {\n get name(): string {\n return 'ExpoFirebaseAnalytics';\n },\n async logEvent(name: string, properties?: { [key: string]: any }): Promise {\n return callAnalyticsModule('logEvent', name, properties);\n },\n async setAnalyticsCollectionEnabled(isEnabled: boolean): Promise {\n return callAnalyticsModule('setAnalyticsEnabled', isEnabled);\n },\n async setCurrentScreen(screenName?: string, screenClassOverride?: string): Promise {\n return callAnalyticsModule('setCurrentScreen', screenName, screenClassOverride);\n },\n async setSessionTimeoutDuration(sessionTimeoutInterval: number): Promise {\n return callAnalyticsModule('setSessionTimeoutDuration', sessionTimeoutInterval);\n },\n async setUserId(userId: string | null): Promise {\n return callAnalyticsModule('setUserId', userId);\n },\n async setUserProperties(properties: { [key: string]: any }): Promise {\n return callAnalyticsModule('setUserProperties', properties);\n },\n async resetAnalyticsData(): Promise {\n return callAnalyticsModule('resetAnalyticsData');\n },\n setUnavailabilityLogging(isEnabled: boolean): void {\n isUnavailabilityLoggingEnabled = isEnabled;\n },\n};\n"]} \ No newline at end of file +{"version":3,"file":"ExpoFirebaseAnalytics.js","sourceRoot":"","sources":["../src/ExpoFirebaseAnalytics.ts"],"names":[],"mappings":"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","sourcesContent":["import { NativeModulesProxy, UnavailabilityError, CodedError } from '@unimodules/core';\nimport Constants from 'expo-constants';\nimport { DEFAULT_APP_NAME, DEFAULT_APP_OPTIONS, DEFAULT_WEB_APP_OPTIONS } from 'expo-firebase-core';\nimport { Platform } from 'react-native';\n\nimport FirebaseAnalyticsJS from './FirebaseAnalyticsJS';\nconst { ExpoFirebaseAnalytics } = NativeModulesProxy;\n\nif (!ExpoFirebaseAnalytics) {\n console.warn(\n \"No native ExpoFirebaseAnalytics module found, are you sure the expo-firebase-analytics's module is linked properly?\"\n );\n}\n\nlet pureJSAnalyticsTracker: FirebaseAnalyticsJS | void;\nlet isUnavailabilityLoggingEnabled = true;\nlet isUnavailabilityWarningLogged = false;\n\nfunction callAnalyticsModule(funcName: string, ...args) {\n if (!ExpoFirebaseAnalytics[funcName]) {\n throw new UnavailabilityError('expo-firebase-analytics', funcName);\n }\n if (!DEFAULT_APP_OPTIONS) {\n throw new CodedError(\n 'ERR_FIREBASE_NOTCONFIGURED',\n `Firebase is not configured. Ensure that you have configured '${Platform.select({\n ios: 'GoogleService-Info.plist',\n android: 'google-services.json',\n })}' correctly.`\n );\n }\n\n // Analytics is only available for the [DEFAULT] app. On the Expo client\n // a sandboxed app is returned which does not support analytics.\n // In that case we show a warning and log the analytics events to the console.\n // The user can disable these by calling `setUnavailabilityLogging(false)`.\n if (DEFAULT_APP_NAME !== '[DEFAULT]') {\n if (DEFAULT_WEB_APP_OPTIONS && !pureJSAnalyticsTracker) {\n pureJSAnalyticsTracker = new FirebaseAnalyticsJS(DEFAULT_WEB_APP_OPTIONS, {\n clientId: Constants.sessionId,\n strictNativeEmulation: true,\n appName: Constants.manifest?.name || 'Unnamed Expo project',\n appVersion: Constants.nativeAppVersion || undefined,\n headers: {\n // Google Analaytics seems to ignore certain user-agents. (e.g. \"okhttp/3.12.1\")\n // Set a user-agent that clearly identifies the Expo client.\n 'user-agent': `Expo/${Constants.nativeAppVersion}`,\n },\n });\n }\n if (pureJSAnalyticsTracker) {\n return pureJSAnalyticsTracker[funcName].call(pureJSAnalyticsTracker, ...args);\n }\n if (isUnavailabilityLoggingEnabled) {\n if (!isUnavailabilityWarningLogged) {\n console.warn(\n `Firebase Analytics is not available in the Expo client. See \"https://docs.expo.io/versions/latest/sdk/firebase-analytics\" on more information on setting up Firebase Analytics with the standard Expo client.`\n );\n isUnavailabilityWarningLogged = true;\n }\n console.info(`ExpoFirebaseAnalytics.${funcName}: ${JSON.stringify(args)}`);\n }\n return;\n }\n\n // Make the call\n return ExpoFirebaseAnalytics[funcName].call(ExpoFirebaseAnalytics, ...args);\n}\n\nexport default {\n get name(): string {\n return 'ExpoFirebaseAnalytics';\n },\n async logEvent(name: string, properties?: { [key: string]: any }): Promise {\n return callAnalyticsModule('logEvent', name, properties);\n },\n async setAnalyticsCollectionEnabled(isEnabled: boolean): Promise {\n return callAnalyticsModule('setAnalyticsEnabled', isEnabled);\n },\n async setCurrentScreen(screenName?: string, screenClassOverride?: string): Promise {\n return callAnalyticsModule('setCurrentScreen', screenName, screenClassOverride);\n },\n async setSessionTimeoutDuration(sessionTimeoutInterval: number): Promise {\n return callAnalyticsModule('setSessionTimeoutDuration', sessionTimeoutInterval);\n },\n async setUserId(userId: string | null): Promise {\n return callAnalyticsModule('setUserId', userId);\n },\n async setUserProperties(properties: { [key: string]: any }): Promise {\n return callAnalyticsModule('setUserProperties', properties);\n },\n async resetAnalyticsData(): Promise {\n return callAnalyticsModule('resetAnalyticsData');\n },\n setUnavailabilityLogging(isEnabled: boolean): void {\n isUnavailabilityLoggingEnabled = isEnabled;\n },\n};\n"]} \ No newline at end of file diff --git a/packages/expo-firebase-analytics/build/FirebaseAnalyticsJS.js b/packages/expo-firebase-analytics/build/FirebaseAnalyticsJS.js index 56651cb9ba108..afc4e46f7cf3e 100644 --- a/packages/expo-firebase-analytics/build/FirebaseAnalyticsJS.js +++ b/packages/expo-firebase-analytics/build/FirebaseAnalyticsJS.js @@ -44,7 +44,7 @@ class FirebaseAnalyticsJS { ...options.customArgs, v: 2, tid: config.measurementId, - cid: this.options.clientId, + cid: options.clientId, }; if (options.userLanguage) queryArgs.ul = options.userLanguage; @@ -73,11 +73,15 @@ class FirebaseAnalyticsJS { }; } const args = encodeQueryArgs(queryArgs); - if (body) - console.log(`FirebaseAnalyticsJS body: ${body}...`); - await fetch(`${this.url}?${args}`, { + const url = `${this.url}?${args}`; + await fetch(url, { method: 'POST', cache: 'no-cache', + ...(options.headers + ? { + headers: options.headers, + } + : {}), body, }); } diff --git a/packages/expo-firebase-analytics/build/FirebaseAnalyticsJS.js.map b/packages/expo-firebase-analytics/build/FirebaseAnalyticsJS.js.map index 5c61013c70d1c..43d7597998943 100644 --- a/packages/expo-firebase-analytics/build/FirebaseAnalyticsJS.js.map +++ b/packages/expo-firebase-analytics/build/FirebaseAnalyticsJS.js.map @@ -1 +1 @@ -{"version":3,"file":"FirebaseAnalyticsJS.js","sourceRoot":"","sources":["../src/FirebaseAnalyticsJS.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n FirebaseAnalyticsJSCodedEvent,\n FirebaseAnalyticsJSConfig,\n FirebaseAnalyticsJSOptions,\n} from './FirebaseAnalyticsJS.types';\n\n/**\n * A pure JavaScript Google Firebase Analytics implementation that uses\n * the HTTPS Measurement API 2 to send events to Google Analytics.\n *\n * This class provides an alternative for the Firebase Analytics module\n * shipped with the Firebase JS SDK. That library uses the gtag.js dependency\n * and requires certain browser features. This prevents the use\n * analytics on other platforms, such as Node-js and react-native.\n *\n * FirebaseAnalyticsJS provides a bare-bone implementation of the new\n * HTTPS Measurement API 2 protocol (which is undocumented), with an API\n * that follows the Firebase Analytics JS SDK.\n */\nclass FirebaseAnalyticsJS {\n public readonly url: string;\n private enabled: boolean;\n public readonly config: FirebaseAnalyticsJSConfig;\n private userId?: string;\n private userProperties?: { [key: string]: any };\n private screenName?: string;\n private eventQueue = new Set();\n private options: FirebaseAnalyticsJSOptions;\n private flushEventsPromise: Promise = Promise.resolve();\n private flushEventsTimer: any;\n\n constructor(config: FirebaseAnalyticsJSConfig, options: FirebaseAnalyticsJSOptions) {\n // Verify the measurement- & client Ids\n if (!config.measurementId)\n throw new Error(\n 'No valid measurementId. Make sure to provide a valid measurementId with a G-XXXXXXXXXX format.'\n );\n if (!options.clientId)\n throw new Error(\n 'No valid clientId. Make sure to provide a valid clientId with a UUID (v4) format.'\n );\n\n // Initialize\n this.url = 'https://www.google-analytics.com/g/collect';\n this.enabled = true;\n this.config = config;\n this.options = {\n customArgs: {},\n maxCacheTime: 5000,\n strictNativeEmulation: false,\n origin: 'firebase',\n ...options,\n };\n }\n\n /**\n * Sends 1 or more coded-events to the back-end.\n * When only 1 event is provided, it is send inside the query URL.\n * When more than 1 event is provided, the event-data is send in\n * the body of the POST request.\n */\n private async send(events: Set): Promise {\n const { config, options } = this;\n let queryArgs: any = {\n ...options.customArgs,\n v: 2,\n tid: config.measurementId,\n cid: this.options.clientId,\n };\n if (options.userLanguage) queryArgs.ul = options.userLanguage;\n if (options.appName) queryArgs.an = options.appName;\n if (options.appVersion) queryArgs.av = options.appVersion;\n if (options.docTitle) queryArgs.dt = options.docTitle;\n if (options.docLocation) queryArgs.dl = options.docLocation;\n if (options.screenRes) queryArgs.sr = options.screenRes;\n let body;\n\n if (events.size > 1) {\n body = '';\n events.forEach(event => {\n body += encodeQueryArgs(event) + '\\n';\n });\n } else if (events.size === 1) {\n const event = events.values().next().value;\n queryArgs = {\n ...event,\n ...queryArgs,\n };\n }\n const args = encodeQueryArgs(queryArgs);\n if (body) console.log(`FirebaseAnalyticsJS body: ${body}...`);\n await fetch(`${this.url}?${args}`, {\n method: 'POST',\n cache: 'no-cache',\n body,\n });\n }\n\n private async addEvent(event: FirebaseAnalyticsJSCodedEvent) {\n const { userId, userProperties, screenName } = this;\n\n // Extend the event with the currently set User-id\n if (userId) event.uid = userId;\n if (screenName) event['ep.screen_name'] = screenName;\n\n // Add user-properties\n if (userProperties) {\n for (const name in userProperties) {\n event[name] = userProperties[name];\n }\n\n // Reset user-properties after the first event. This is what gtag.js seems\n // to do as well, although I couldn't find any docs explaining this behavior.\n this.userProperties = undefined;\n }\n\n // Add the event to the queue\n this.eventQueue.add(event);\n\n // Start debounce timer\n if (!this.flushEventsTimer) {\n this.flushEventsTimer = setTimeout(async () => {\n this.flushEventsTimer = undefined;\n try {\n await this.flushEventsPromise;\n } catch (err) {\n // nop\n }\n this.flushEventsPromise = this.flushEvents();\n }, this.options.maxCacheTime);\n }\n }\n\n private async flushEvents() {\n if (!this.eventQueue.size) return;\n const events = new Set(this.eventQueue);\n await this.send(events);\n events.forEach(event => this.eventQueue.delete(event));\n }\n\n /**\n * Clears any queued events and cancels the flush timer.\n */\n clearEvents() {\n this.eventQueue.clear();\n if (this.flushEventsTimer) {\n clearTimeout(this.flushEventsTimer);\n this.flushEventsTimer = 0;\n }\n }\n\n /**\n * Parses an event (as passed to logEvent) and throws an error when the\n * event-name or parameters are invalid.\n *\n * Upon success, returns the event in encoded format, ready to be send\n * through the Google Measurement API v2.\n */\n static parseEvent(\n options: FirebaseAnalyticsJSOptions,\n eventName: string,\n eventParams?: { [key: string]: any }\n ): FirebaseAnalyticsJSCodedEvent {\n if (\n !eventName ||\n !eventName.length ||\n eventName.length > 40 ||\n eventName[0] === '_' ||\n !eventName.match(/^[A-Za-z_]+$/) ||\n eventName.startsWith('firebase_') ||\n eventName.startsWith('google_') ||\n eventName.startsWith('ga_')\n ) {\n throw new Error(\n 'Invalid event-name specified. Should contain 1 to 40 alphanumeric characters or underscores. The name must start with an alphabetic character.'\n );\n }\n const params: FirebaseAnalyticsJSCodedEvent = {\n en: eventName,\n _et: Date.now(),\n 'ep.origin': options.origin,\n };\n if (eventParams) {\n for (const key in eventParams) {\n const paramKey =\n SHORT_EVENT_PARAMS[key] ||\n (typeof eventParams[key] === 'number' ? `epn.${key}` : `ep.${key}`);\n params[paramKey] = eventParams[key];\n }\n }\n return params;\n }\n\n /**\n * Parses user-properties (as passed to setUserProperties) and throws an error when\n * one of the user properties is invalid.\n *\n * Upon success, returns the user-properties in encoded format, ready to be send\n * through the Google Measurement API v2.\n */\n static parseUserProperty(\n options: FirebaseAnalyticsJSOptions,\n userPropertyName: string,\n userPropertyValue: any\n ): string {\n if (\n !userPropertyName.length ||\n userPropertyName.length > 24 ||\n userPropertyName[0] === '_' ||\n !userPropertyName.match(/^[A-Za-z_]+$/) ||\n userPropertyName === 'user_id' ||\n userPropertyName.startsWith('firebase_') ||\n userPropertyName.startsWith('google_') ||\n userPropertyName.startsWith('ga_')\n ) {\n throw new Error(\n 'Invalid user-property name specified. Should contain 1 to 24 alphanumeric characters or underscores. The name must start with an alphabetic character.'\n );\n }\n if (\n userPropertyValue !== undefined &&\n userPropertyValue !== null &&\n options.strictNativeEmulation &&\n (typeof userPropertyValue !== 'string' || userPropertyValue.length > 36)\n ) {\n throw new Error(\n 'Invalid user-property value specified. Value should be a string of up to 36 characters long.'\n );\n }\n return typeof userPropertyValue === 'number'\n ? `upn.${userPropertyName}`\n : `up.${userPropertyName}`;\n }\n\n /**\n * https://firebase.google.com/docs/reference/js/firebase.analytics.Analytics#log-event\n */\n async logEvent(eventName: string, eventParams?: { [key: string]: any }): Promise {\n const event = FirebaseAnalyticsJS.parseEvent(this.options, eventName, eventParams);\n if (!this.enabled) return;\n return this.addEvent(event);\n }\n\n /**\n * https://firebase.google.com/docs/reference/js/firebase.analytics.Analytics#set-analytics-collection-enabled\n */\n async setAnalyticsCollectionEnabled(isEnabled: boolean): Promise {\n this.enabled = isEnabled;\n }\n\n /**\n * https://firebase.google.com/docs/reference/js/firebase.analytics.Analytics#set-current-screen\n */\n async setCurrentScreen(screenName?: string, screenClassOverride?: string): Promise {\n if (screenName && screenName.length > 100) {\n throw new Error(\n 'Invalid screen-name specified. Should contain 1 to 100 characters. Set to undefined to clear the current screen name.'\n );\n }\n if (!this.enabled) return;\n this.screenName = screenName || undefined;\n\n // On native, calling `setCurrentScreen` automatically records a screen_view event.\n // Mimimic that behavior when native emulation is enabled.\n // https://firebase.google.com/docs/analytics/screenviews#manually_track_screens\n if (screenName && this.options.strictNativeEmulation) {\n await this.logEvent('screen_view', {\n screen_name: screenName,\n });\n }\n }\n\n /**\n * https://firebase.google.com/docs/reference/js/firebase.analytics.Analytics#set-user-id\n */\n async setUserId(userId: string | null): Promise {\n if (!this.enabled) return;\n this.userId = userId || undefined;\n }\n\n /**\n * https://firebase.google.com/docs/reference/js/firebase.analytics.Analytics#set-user-properties\n */\n async setUserProperties(userProperties: { [key: string]: any }): Promise {\n if (!this.enabled) return;\n for (const name in userProperties) {\n const val = userProperties[name];\n const key = FirebaseAnalyticsJS.parseUserProperty(this.options, name, val);\n if (val === null || val === undefined) {\n if (this.userProperties) {\n delete this.userProperties[key];\n }\n } else {\n this.userProperties = this.userProperties || {};\n this.userProperties[key] = val;\n }\n }\n }\n\n /**\n * Clears all analytics data for this instance.\n */\n async resetAnalyticsData() {\n this.clearEvents();\n this.screenName = undefined;\n this.userId = undefined;\n this.userProperties = undefined;\n }\n}\n\nfunction encodeQueryArgs(queryArgs: FirebaseAnalyticsJSCodedEvent): string {\n const now = Date.now();\n return Object.keys(queryArgs)\n .map(key => {\n return `${key}=${encodeURIComponent(\n key === '_et' ? Math.max(now - queryArgs[key], 0) : queryArgs[key]\n )}`;\n })\n .join('&');\n}\n\nconst SHORT_EVENT_PARAMS = {\n currency: 'cu',\n};\n\nexport default FirebaseAnalyticsJS;\n"]} \ No newline at end of file +{"version":3,"file":"FirebaseAnalyticsJS.js","sourceRoot":"","sources":["../src/FirebaseAnalyticsJS.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n FirebaseAnalyticsJSCodedEvent,\n FirebaseAnalyticsJSConfig,\n FirebaseAnalyticsJSOptions,\n} from './FirebaseAnalyticsJS.types';\n\n/**\n * A pure JavaScript Google Firebase Analytics implementation that uses\n * the HTTPS Measurement API 2 to send events to Google Analytics.\n *\n * This class provides an alternative for the Firebase Analytics module\n * shipped with the Firebase JS SDK. That library uses the gtag.js dependency\n * and requires certain browser features. This prevents the use\n * analytics on other platforms, such as Node-js and react-native.\n *\n * FirebaseAnalyticsJS provides a bare-bone implementation of the new\n * HTTPS Measurement API 2 protocol (which is undocumented), with an API\n * that follows the Firebase Analytics JS SDK.\n */\nclass FirebaseAnalyticsJS {\n public readonly url: string;\n private enabled: boolean;\n public readonly config: FirebaseAnalyticsJSConfig;\n private userId?: string;\n private userProperties?: { [key: string]: any };\n private screenName?: string;\n private eventQueue = new Set();\n private options: FirebaseAnalyticsJSOptions;\n private flushEventsPromise: Promise = Promise.resolve();\n private flushEventsTimer: any;\n\n constructor(config: FirebaseAnalyticsJSConfig, options: FirebaseAnalyticsJSOptions) {\n // Verify the measurement- & client Ids\n if (!config.measurementId)\n throw new Error(\n 'No valid measurementId. Make sure to provide a valid measurementId with a G-XXXXXXXXXX format.'\n );\n if (!options.clientId)\n throw new Error(\n 'No valid clientId. Make sure to provide a valid clientId with a UUID (v4) format.'\n );\n\n // Initialize\n this.url = 'https://www.google-analytics.com/g/collect';\n this.enabled = true;\n this.config = config;\n this.options = {\n customArgs: {},\n maxCacheTime: 5000,\n strictNativeEmulation: false,\n origin: 'firebase',\n ...options,\n };\n }\n\n /**\n * Sends 1 or more coded-events to the back-end.\n * When only 1 event is provided, it is send inside the query URL.\n * When more than 1 event is provided, the event-data is send in\n * the body of the POST request.\n */\n private async send(events: Set): Promise {\n const { config, options } = this;\n let queryArgs: any = {\n ...options.customArgs,\n v: 2,\n tid: config.measurementId,\n cid: options.clientId,\n };\n if (options.userLanguage) queryArgs.ul = options.userLanguage;\n if (options.appName) queryArgs.an = options.appName;\n if (options.appVersion) queryArgs.av = options.appVersion;\n if (options.docTitle) queryArgs.dt = options.docTitle;\n if (options.docLocation) queryArgs.dl = options.docLocation;\n if (options.screenRes) queryArgs.sr = options.screenRes;\n let body;\n\n if (events.size > 1) {\n body = '';\n events.forEach(event => {\n body += encodeQueryArgs(event) + '\\n';\n });\n } else if (events.size === 1) {\n const event = events.values().next().value;\n queryArgs = {\n ...event,\n ...queryArgs,\n };\n }\n const args = encodeQueryArgs(queryArgs);\n const url = `${this.url}?${args}`;\n await fetch(url, {\n method: 'POST',\n cache: 'no-cache',\n ...(options.headers\n ? {\n headers: options.headers,\n }\n : {}),\n body,\n });\n }\n\n private async addEvent(event: FirebaseAnalyticsJSCodedEvent) {\n const { userId, userProperties, screenName } = this;\n\n // Extend the event with the currently set User-id\n if (userId) event.uid = userId;\n if (screenName) event['ep.screen_name'] = screenName;\n\n // Add user-properties\n if (userProperties) {\n for (const name in userProperties) {\n event[name] = userProperties[name];\n }\n\n // Reset user-properties after the first event. This is what gtag.js seems\n // to do as well, although I couldn't find any docs explaining this behavior.\n this.userProperties = undefined;\n }\n\n // Add the event to the queue\n this.eventQueue.add(event);\n\n // Start debounce timer\n if (!this.flushEventsTimer) {\n this.flushEventsTimer = setTimeout(async () => {\n this.flushEventsTimer = undefined;\n try {\n await this.flushEventsPromise;\n } catch (err) {\n // nop\n }\n this.flushEventsPromise = this.flushEvents();\n }, this.options.maxCacheTime);\n }\n }\n\n private async flushEvents() {\n if (!this.eventQueue.size) return;\n const events = new Set(this.eventQueue);\n await this.send(events);\n events.forEach(event => this.eventQueue.delete(event));\n }\n\n /**\n * Clears any queued events and cancels the flush timer.\n */\n clearEvents() {\n this.eventQueue.clear();\n if (this.flushEventsTimer) {\n clearTimeout(this.flushEventsTimer);\n this.flushEventsTimer = 0;\n }\n }\n\n /**\n * Parses an event (as passed to logEvent) and throws an error when the\n * event-name or parameters are invalid.\n *\n * Upon success, returns the event in encoded format, ready to be send\n * through the Google Measurement API v2.\n */\n static parseEvent(\n options: FirebaseAnalyticsJSOptions,\n eventName: string,\n eventParams?: { [key: string]: any }\n ): FirebaseAnalyticsJSCodedEvent {\n if (\n !eventName ||\n !eventName.length ||\n eventName.length > 40 ||\n eventName[0] === '_' ||\n !eventName.match(/^[A-Za-z_]+$/) ||\n eventName.startsWith('firebase_') ||\n eventName.startsWith('google_') ||\n eventName.startsWith('ga_')\n ) {\n throw new Error(\n 'Invalid event-name specified. Should contain 1 to 40 alphanumeric characters or underscores. The name must start with an alphabetic character.'\n );\n }\n const params: FirebaseAnalyticsJSCodedEvent = {\n en: eventName,\n _et: Date.now(),\n 'ep.origin': options.origin,\n };\n if (eventParams) {\n for (const key in eventParams) {\n const paramKey =\n SHORT_EVENT_PARAMS[key] ||\n (typeof eventParams[key] === 'number' ? `epn.${key}` : `ep.${key}`);\n params[paramKey] = eventParams[key];\n }\n }\n return params;\n }\n\n /**\n * Parses user-properties (as passed to setUserProperties) and throws an error when\n * one of the user properties is invalid.\n *\n * Upon success, returns the user-properties in encoded format, ready to be send\n * through the Google Measurement API v2.\n */\n static parseUserProperty(\n options: FirebaseAnalyticsJSOptions,\n userPropertyName: string,\n userPropertyValue: any\n ): string {\n if (\n !userPropertyName.length ||\n userPropertyName.length > 24 ||\n userPropertyName[0] === '_' ||\n !userPropertyName.match(/^[A-Za-z_]+$/) ||\n userPropertyName === 'user_id' ||\n userPropertyName.startsWith('firebase_') ||\n userPropertyName.startsWith('google_') ||\n userPropertyName.startsWith('ga_')\n ) {\n throw new Error(\n 'Invalid user-property name specified. Should contain 1 to 24 alphanumeric characters or underscores. The name must start with an alphabetic character.'\n );\n }\n if (\n userPropertyValue !== undefined &&\n userPropertyValue !== null &&\n options.strictNativeEmulation &&\n (typeof userPropertyValue !== 'string' || userPropertyValue.length > 36)\n ) {\n throw new Error(\n 'Invalid user-property value specified. Value should be a string of up to 36 characters long.'\n );\n }\n return typeof userPropertyValue === 'number'\n ? `upn.${userPropertyName}`\n : `up.${userPropertyName}`;\n }\n\n /**\n * https://firebase.google.com/docs/reference/js/firebase.analytics.Analytics#log-event\n */\n async logEvent(eventName: string, eventParams?: { [key: string]: any }): Promise {\n const event = FirebaseAnalyticsJS.parseEvent(this.options, eventName, eventParams);\n if (!this.enabled) return;\n return this.addEvent(event);\n }\n\n /**\n * https://firebase.google.com/docs/reference/js/firebase.analytics.Analytics#set-analytics-collection-enabled\n */\n async setAnalyticsCollectionEnabled(isEnabled: boolean): Promise {\n this.enabled = isEnabled;\n }\n\n /**\n * https://firebase.google.com/docs/reference/js/firebase.analytics.Analytics#set-current-screen\n */\n async setCurrentScreen(screenName?: string, screenClassOverride?: string): Promise {\n if (screenName && screenName.length > 100) {\n throw new Error(\n 'Invalid screen-name specified. Should contain 1 to 100 characters. Set to undefined to clear the current screen name.'\n );\n }\n if (!this.enabled) return;\n this.screenName = screenName || undefined;\n\n // On native, calling `setCurrentScreen` automatically records a screen_view event.\n // Mimimic that behavior when native emulation is enabled.\n // https://firebase.google.com/docs/analytics/screenviews#manually_track_screens\n if (screenName && this.options.strictNativeEmulation) {\n await this.logEvent('screen_view', {\n screen_name: screenName,\n });\n }\n }\n\n /**\n * https://firebase.google.com/docs/reference/js/firebase.analytics.Analytics#set-user-id\n */\n async setUserId(userId: string | null): Promise {\n if (!this.enabled) return;\n this.userId = userId || undefined;\n }\n\n /**\n * https://firebase.google.com/docs/reference/js/firebase.analytics.Analytics#set-user-properties\n */\n async setUserProperties(userProperties: { [key: string]: any }): Promise {\n if (!this.enabled) return;\n for (const name in userProperties) {\n const val = userProperties[name];\n const key = FirebaseAnalyticsJS.parseUserProperty(this.options, name, val);\n if (val === null || val === undefined) {\n if (this.userProperties) {\n delete this.userProperties[key];\n }\n } else {\n this.userProperties = this.userProperties || {};\n this.userProperties[key] = val;\n }\n }\n }\n\n /**\n * Clears all analytics data for this instance.\n */\n async resetAnalyticsData() {\n this.clearEvents();\n this.screenName = undefined;\n this.userId = undefined;\n this.userProperties = undefined;\n }\n}\n\nfunction encodeQueryArgs(queryArgs: FirebaseAnalyticsJSCodedEvent): string {\n const now = Date.now();\n return Object.keys(queryArgs)\n .map(key => {\n return `${key}=${encodeURIComponent(\n key === '_et' ? Math.max(now - queryArgs[key], 0) : queryArgs[key]\n )}`;\n })\n .join('&');\n}\n\nconst SHORT_EVENT_PARAMS = {\n currency: 'cu',\n};\n\nexport default FirebaseAnalyticsJS;\n"]} \ No newline at end of file diff --git a/packages/expo-firebase-analytics/build/FirebaseAnalyticsJS.types.d.ts b/packages/expo-firebase-analytics/build/FirebaseAnalyticsJS.types.d.ts index ec59fd30bc5e4..c2a3f0f2b115b 100644 --- a/packages/expo-firebase-analytics/build/FirebaseAnalyticsJS.types.d.ts +++ b/packages/expo-firebase-analytics/build/FirebaseAnalyticsJS.types.d.ts @@ -87,4 +87,20 @@ export interface FirebaseAnalyticsJSOptions { customArgs?: { [key: string]: any; }; + /** + * HTTP headers that are appended to the POST request. + * + * @example + * ``` + * const analytics = new FirebaseAnalyticsJS(config, { + * appName: 'My Awesome App', + * headers: { + * 'user-agent': 'MyAwesomeHTTPClient/1.2.3' + * } + * }); + * ``` + */ + headers?: { + [key: string]: any; + }; } diff --git a/packages/expo-firebase-analytics/build/FirebaseAnalyticsJS.types.js.map b/packages/expo-firebase-analytics/build/FirebaseAnalyticsJS.types.js.map index e097c3fadd75a..bd24d398c93fd 100644 --- a/packages/expo-firebase-analytics/build/FirebaseAnalyticsJS.types.js.map +++ b/packages/expo-firebase-analytics/build/FirebaseAnalyticsJS.types.js.map @@ -1 +1 @@ -{"version":3,"file":"FirebaseAnalyticsJS.types.js","sourceRoot":"","sources":["../src/FirebaseAnalyticsJS.types.ts"],"names":[],"mappings":"","sourcesContent":["export type FirebaseAnalyticsJSCodedEvent = { [key: string]: any };\n\nexport interface FirebaseAnalyticsJSConfig {\n /**\n * **(Required)** Measurement-Id as found in the web Firebase-config.\n * The format is G-XXXXXXXXXX.\n */\n measurementId: string;\n}\n\nexport interface FirebaseAnalyticsJSOptions {\n /**\n * **(Required)** Anonymously identifies a particular user, device, or browser instance.\n * For the web, this is generally stored as a first-party cookie with a two-year expiration.\n * For mobile apps, this is randomly generated for each particular instance of an application install.\n * The value of this field should be a random UUID (version 4) as described in http://www.ietf.org/rfc/rfc4122.txt.\n * https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#cid\n */\n clientId: string;\n\n /**\n * Max cache time in msec (default = 5000).\n * Caches events fired within a certain time-frame and then\n * sends them to the Google Measurement API in a single batch.\n */\n maxCacheTime?: number;\n\n /**\n * Enables strict data format checks for logEvent and setUserProperties.\n * When enabled, causes `logEvent` and `setUserProperties` to strictly check\n * whether any event- names & values and user-properties conform to the\n * native SDK requirements.\n */\n strictNativeEmulation?: boolean;\n\n /**\n * Document title (e.g. \"My Awesome Page\").\n * This is a browser specific field.\n * https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#dt\n */\n docTitle?: string;\n\n /**\n * Document location URL (e.g. \"https://myawesomeapp.com\").\n * This is a browser specific field.\n * https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#dl\n */\n docLocation?: string;\n\n /**\n * Screen-resolution in the format \"WxH\" (e.g \"2000x1440\").\n * This is a browser specific field.\n * https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#sr\n */\n screenRes?: string;\n\n /**\n * Application name (e.g. \"My Awesome App\").\n * This is a mobile app specific field.\n * https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#an\n */\n appName?: string;\n\n /**\n * Application version (e.g. \"1.2\").\n * This is a mobile app specific field.\n * https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#av\n */\n appVersion?: string;\n\n /**\n * User language (e.g. \"en-us\").\n * https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#ul\n */\n userLanguage?: string;\n\n /**\n * Origin (default = \"firebase\").\n */\n origin?: string;\n\n /**\n * Custom query arguments that are appended to the POST request that is send to the\n * Google Measurement API v2.\n *\n * @example\n * ```\n * const analytics = new FirebaseAnalyticsJS(config, {\n * appName: 'My Awesome App',\n * customArg: {\n * vp: '123x456', // Add viewport-size\n * sd: '24-bits' // Add screen-colors\n * }\n * });\n * ```\n */\n customArgs?: { [key: string]: any };\n}\n"]} \ No newline at end of file +{"version":3,"file":"FirebaseAnalyticsJS.types.js","sourceRoot":"","sources":["../src/FirebaseAnalyticsJS.types.ts"],"names":[],"mappings":"","sourcesContent":["export type FirebaseAnalyticsJSCodedEvent = { [key: string]: any };\n\nexport interface FirebaseAnalyticsJSConfig {\n /**\n * **(Required)** Measurement-Id as found in the web Firebase-config.\n * The format is G-XXXXXXXXXX.\n */\n measurementId: string;\n}\n\nexport interface FirebaseAnalyticsJSOptions {\n /**\n * **(Required)** Anonymously identifies a particular user, device, or browser instance.\n * For the web, this is generally stored as a first-party cookie with a two-year expiration.\n * For mobile apps, this is randomly generated for each particular instance of an application install.\n * The value of this field should be a random UUID (version 4) as described in http://www.ietf.org/rfc/rfc4122.txt.\n * https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#cid\n */\n clientId: string;\n\n /**\n * Max cache time in msec (default = 5000).\n * Caches events fired within a certain time-frame and then\n * sends them to the Google Measurement API in a single batch.\n */\n maxCacheTime?: number;\n\n /**\n * Enables strict data format checks for logEvent and setUserProperties.\n * When enabled, causes `logEvent` and `setUserProperties` to strictly check\n * whether any event- names & values and user-properties conform to the\n * native SDK requirements.\n */\n strictNativeEmulation?: boolean;\n\n /**\n * Document title (e.g. \"My Awesome Page\").\n * This is a browser specific field.\n * https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#dt\n */\n docTitle?: string;\n\n /**\n * Document location URL (e.g. \"https://myawesomeapp.com\").\n * This is a browser specific field.\n * https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#dl\n */\n docLocation?: string;\n\n /**\n * Screen-resolution in the format \"WxH\" (e.g \"2000x1440\").\n * This is a browser specific field.\n * https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#sr\n */\n screenRes?: string;\n\n /**\n * Application name (e.g. \"My Awesome App\").\n * This is a mobile app specific field.\n * https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#an\n */\n appName?: string;\n\n /**\n * Application version (e.g. \"1.2\").\n * This is a mobile app specific field.\n * https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#av\n */\n appVersion?: string;\n\n /**\n * User language (e.g. \"en-us\").\n * https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#ul\n */\n userLanguage?: string;\n\n /**\n * Origin (default = \"firebase\").\n */\n origin?: string;\n\n /**\n * Custom query arguments that are appended to the POST request that is send to the\n * Google Measurement API v2.\n *\n * @example\n * ```\n * const analytics = new FirebaseAnalyticsJS(config, {\n * appName: 'My Awesome App',\n * customArg: {\n * vp: '123x456', // Add viewport-size\n * sd: '24-bits' // Add screen-colors\n * }\n * });\n * ```\n */\n customArgs?: { [key: string]: any };\n\n /**\n * HTTP headers that are appended to the POST request.\n *\n * @example\n * ```\n * const analytics = new FirebaseAnalyticsJS(config, {\n * appName: 'My Awesome App',\n * headers: {\n * 'user-agent': 'MyAwesomeHTTPClient/1.2.3'\n * }\n * });\n * ```\n */\n headers?: { [key: string]: any };\n}\n"]} \ No newline at end of file diff --git a/packages/expo-firebase-analytics/src/ExpoFirebaseAnalytics.ts b/packages/expo-firebase-analytics/src/ExpoFirebaseAnalytics.ts index 80e60061a3465..e229e68f231c2 100644 --- a/packages/expo-firebase-analytics/src/ExpoFirebaseAnalytics.ts +++ b/packages/expo-firebase-analytics/src/ExpoFirebaseAnalytics.ts @@ -41,6 +41,11 @@ function callAnalyticsModule(funcName: string, ...args) { strictNativeEmulation: true, appName: Constants.manifest?.name || 'Unnamed Expo project', appVersion: Constants.nativeAppVersion || undefined, + headers: { + // Google Analaytics seems to ignore certain user-agents. (e.g. "okhttp/3.12.1") + // Set a user-agent that clearly identifies the Expo client. + 'user-agent': `Expo/${Constants.nativeAppVersion}`, + }, }); } if (pureJSAnalyticsTracker) { diff --git a/packages/expo-firebase-analytics/src/FirebaseAnalyticsJS.ts b/packages/expo-firebase-analytics/src/FirebaseAnalyticsJS.ts index 5a5534818aac5..387872b030c6a 100644 --- a/packages/expo-firebase-analytics/src/FirebaseAnalyticsJS.ts +++ b/packages/expo-firebase-analytics/src/FirebaseAnalyticsJS.ts @@ -65,7 +65,7 @@ class FirebaseAnalyticsJS { ...options.customArgs, v: 2, tid: config.measurementId, - cid: this.options.clientId, + cid: options.clientId, }; if (options.userLanguage) queryArgs.ul = options.userLanguage; if (options.appName) queryArgs.an = options.appName; @@ -88,10 +88,15 @@ class FirebaseAnalyticsJS { }; } const args = encodeQueryArgs(queryArgs); - if (body) console.log(`FirebaseAnalyticsJS body: ${body}...`); - await fetch(`${this.url}?${args}`, { + const url = `${this.url}?${args}`; + await fetch(url, { method: 'POST', cache: 'no-cache', + ...(options.headers + ? { + headers: options.headers, + } + : {}), body, }); } diff --git a/packages/expo-firebase-analytics/src/FirebaseAnalyticsJS.types.ts b/packages/expo-firebase-analytics/src/FirebaseAnalyticsJS.types.ts index 26657e73174e8..4934e18eec4cb 100644 --- a/packages/expo-firebase-analytics/src/FirebaseAnalyticsJS.types.ts +++ b/packages/expo-firebase-analytics/src/FirebaseAnalyticsJS.types.ts @@ -95,4 +95,19 @@ export interface FirebaseAnalyticsJSOptions { * ``` */ customArgs?: { [key: string]: any }; + + /** + * HTTP headers that are appended to the POST request. + * + * @example + * ``` + * const analytics = new FirebaseAnalyticsJS(config, { + * appName: 'My Awesome App', + * headers: { + * 'user-agent': 'MyAwesomeHTTPClient/1.2.3' + * } + * }); + * ``` + */ + headers?: { [key: string]: any }; }