Skip to content

Commit 74efc84

Browse files
fix(analytics): Type defs (#8363)
* Type defs fix * Test for function definition * feat(analytics): Get CID * feat(analytics): e2e tests for getCid() * fix: ensure method is exposed * test(other): install async-storage for Other e2e analytics testing also implements the modular API definition for setReactNativeAsyncStorage * fix(analytics, other): bind getAppInstanceId to _getCid in web module this correctly binds the Other platform analytics implementation of _getCid to the getAppInstanceId exported method and exposes it so it works, verified in testing * fix(analytics): use more compatible multi-line string format the previous triple-backtick style was registering as an error on some platforms * test(analytics): modular test suite is now deprecation-clean * fix(auth, other): reformat persistence warning for wide compatibility --------- Co-authored-by: Mike Hardy <[email protected]>
1 parent c26253c commit 74efc84

File tree

11 files changed

+140
-54
lines changed

11 files changed

+140
-54
lines changed

packages/analytics/__tests__/analytics.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
firebase,
55
getAnalytics,
66
initializeAnalytics,
7+
getGoogleAnalyticsClientId,
78
logEvent,
89
setAnalyticsCollectionEnabled,
910
setSessionTimeoutDuration,
@@ -711,6 +712,10 @@ describe('Analytics', function () {
711712
expect(initializeAnalytics).toBeDefined();
712713
});
713714

715+
it('`getGoogleAnalyticsClientId` function is properly exposed to end user', function () {
716+
expect(getGoogleAnalyticsClientId).toBeDefined();
717+
});
718+
714719
it('`logEvent` function is properly exposed to end user', function () {
715720
expect(logEvent).toBeDefined();
716721
});

packages/analytics/e2e/analytics.e2e.js

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,23 @@
1414
* limitations under the License.
1515
*
1616
*/
17-
18-
describe('analytics() modular', function () {
17+
describe('analytics()', function () {
1918
beforeEach(async function () {
20-
await firebase.analytics().logEvent('screen_view');
19+
const { getAnalytics, logEvent } = analyticsModular;
20+
await logEvent(getAnalytics(), 'screen_view');
2121
});
2222

2323
describe('firebase v8 compatibility', function () {
24+
beforeEach(async function beforeEachTest() {
25+
// @ts-ignore
26+
globalThis.RNFB_SILENCE_MODULAR_DEPRECATION_WARNINGS = true;
27+
});
28+
29+
afterEach(async function afterEachTest() {
30+
// @ts-ignore
31+
globalThis.RNFB_SILENCE_MODULAR_DEPRECATION_WARNINGS = false;
32+
});
33+
2434
describe('logEvent()', function () {
2535
it('log an event without parameters', async function () {
2636
await firebase.analytics().logEvent('invertase_event');
@@ -549,9 +559,10 @@ describe('analytics() modular', function () {
549559
describe('modular', function () {
550560
describe('getAnalytics', function () {
551561
it('pass app as argument', function () {
562+
const { getApp } = modular;
552563
const { getAnalytics } = analyticsModular;
553564

554-
const analytics = getAnalytics(firebase.app());
565+
const analytics = getAnalytics(getApp());
555566

556567
analytics.constructor.name.should.be.equal('FirebaseAnalyticsModule');
557568
});
@@ -1133,5 +1144,29 @@ describe('analytics() modular', function () {
11331144
await setConsent(getAnalytics(), consentSettings);
11341145
});
11351146
});
1147+
1148+
describe('getGoogleAnalyticsClientId()', function () {
1149+
it('Error for getGoogleAnalyticsClientId() on non-other platforms', async function () {
1150+
if (Platform.other) {
1151+
this.skip();
1152+
}
1153+
try {
1154+
const { getAnalytics, getGoogleAnalyticsClientId } = analyticsModular;
1155+
await getGoogleAnalyticsClientId(getAnalytics());
1156+
fail('Should have thrown an error');
1157+
} catch (e) {
1158+
e.message.should.equal('getGoogleAnalyticsClientId is web-only.');
1159+
}
1160+
});
1161+
1162+
it('getGoogleAnalyticsClientId() works on other platform', async function () {
1163+
const { getAnalytics, getGoogleAnalyticsClientId } = analyticsModular;
1164+
if (!Platform.other) {
1165+
this.skip();
1166+
}
1167+
let cid = await getGoogleAnalyticsClientId(getAnalytics());
1168+
cid.should.not.be.empty;
1169+
});
1170+
});
11361171
});
11371172
});

packages/analytics/lib/modular/index.d.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ export declare function initializeAnalytics(
2323
options?: FirebaseAnalyticsTypes.AnalyticsSettings,
2424
): Analytics;
2525

26+
/**
27+
* Retrieves a unique Google Analytics identifier for the web client.
28+
*
29+
* @param analyticsInstance - Instance of analytics (web - only)
30+
*
31+
*/
32+
export declare function getGoogleAnalyticsClientId(analyticsInstance: Analytics): Promise<string>;
33+
2634
/**
2735
* Log a custom event with optional params. Note that there are various limits that applied
2836
* to event parameters (total parameter count, etc), but analytics applies the limits during
@@ -605,10 +613,14 @@ export function getAppInstanceId(analytics: Analytics): Promise<string | null>;
605613
* Gives a user a unique identification.
606614
*
607615
* @param analytics Analytics instance.
608-
* @param id Set to null to remove a previously assigned ID from analytics
609-
* events
616+
* @param id Set to null to remove a previously assigned ID from analytics events
617+
* @param options Additional options that can be passed to Analytics method calls such as logEvent, etc.
610618
*/
611-
export function setUserId(analytics: Analytics, id: string | null): Promise<void>;
619+
export function setUserId(
620+
analytics: Analytics,
621+
id: string | null,
622+
options?: AnalyticsCallOptions,
623+
): Promise<void>;
612624

613625
/**
614626
* Sets a key/value pair of data on the current user. Each Firebase project can have up to 25 uniquely named (case-sensitive) user properties.

packages/analytics/lib/modular/index.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { getApp } from '@react-native-firebase/app';
2+
import { Platform } from 'react-native';
23

34
/**
45
* @typedef {import('@firebase/app').FirebaseApp} FirebaseApp
@@ -64,6 +65,20 @@ export function initializeAnalytics(app, options) {
6465
return getApp(app.name).analytics();
6566
}
6667

68+
/**
69+
* Retrieves a unique Google Analytics identifier for the web client.
70+
*
71+
* @param {FirebaseAnalytics} analytics - Instance of analytics (web - only)
72+
* @returns {Promise<string>}
73+
*/
74+
export async function getGoogleAnalyticsClientId(analytics) {
75+
if (Platform.OS === 'android' || Platform.OS === 'ios') {
76+
throw new Error('getGoogleAnalyticsClientId is web-only.');
77+
} else {
78+
return getAppInstanceId(analytics);
79+
}
80+
}
81+
6782
/**
6883
* Log a custom event with optional params.
6984
* @param {FirebaseAnalytics} analytics - Analytics instance.

packages/analytics/lib/web/RNFBAnalyticsModule.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { AnalyticsApi } from './api';
55

66
let analyticsInstances = {};
77

8-
function getAnalyticsApi() {
9-
const app = getApp('[DEFAULT]');
8+
function getAnalyticsApi(appName) {
9+
const app = getApp(appName);
1010
const measurementId = app.options.measurementId;
1111
if (!measurementId) {
1212
// eslint-disable-next-line no-console
@@ -104,9 +104,9 @@ export default {
104104
},
105105

106106
getAppInstanceId() {
107-
// Unsupported for web.
108107
return guard(async () => {
109-
return null;
108+
const api = getAnalyticsApi('[DEFAULT]');
109+
return api._getCid();
110110
});
111111
},
112112

packages/analytics/lib/web/api.js

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -171,24 +171,22 @@ class AnalyticsApi {
171171
await setItem('analytics:cid', this.cid);
172172
if (isMemoryStorage()) {
173173
console.warn(
174-
```
175-
Firebase Analytics is using in memory persistence. This means that the analytics
176-
client ID is reset every time your app is restarted which may result in
177-
inaccurate data being shown on the Firebase Analytics dashboard.
178-
179-
To enable persistence, provide an Async Storage implementation.
180-
181-
For example, to use React Native Async Storage:
182-
183-
import AsyncStorage from '@react-native-async-storage/async-storage';
184-
185-
// Before initializing Firebase set the Async Storage implementation
186-
// that will be used to persist user sessions.
187-
firebase.setReactNativeAsyncStorage(AsyncStorage);
188-
189-
// Then initialize Firebase as normal.
190-
await firebase.initializeApp({ ... });
191-
```,
174+
'Firebase Analytics is using in memory persistence. This means that the analytics\n' +
175+
'client ID is reset every time your app is restarted which may result in\n' +
176+
'inaccurate data being shown on the Firebase Analytics dashboard.\n' +
177+
'\n' +
178+
'To enable persistence, provide an Async Storage implementation.\n' +
179+
'\n' +
180+
'For example, to use React Native Async Storage:\n' +
181+
'\n' +
182+
" import AsyncStorage from '@react-native-async-storage/async-storage';\n" +
183+
'\n' +
184+
' // Before initializing Firebase set the Async Storage implementation\n' +
185+
' // that will be used to persist user sessions.\n' +
186+
' firebase.setReactNativeAsyncStorage(AsyncStorage);\n' +
187+
'\n' +
188+
' // Then initialize Firebase as normal.\n' +
189+
' await firebase.initializeApp({ ... });\n',
192190
);
193191
}
194192
return this.cid;

packages/app/lib/internal/registry/app.js

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -218,26 +218,22 @@ export function setLogLevel(logLevel) {
218218
}
219219

220220
export function setReactNativeAsyncStorage(asyncStorage) {
221+
warnIfNotModularCall(arguments, 'setReactNativeAsyncStorage()');
222+
221223
if (!isObject(asyncStorage)) {
222-
throw new Error("firebase.setReactNativeAsyncStorage(*) 'asyncStorage' must be an object.");
224+
throw new Error("setReactNativeAsyncStorage(*) 'asyncStorage' must be an object.");
223225
}
224226

225227
if (!isFunction(asyncStorage.setItem)) {
226-
throw new Error(
227-
"firebase.setReactNativeAsyncStorage(*) 'asyncStorage.setItem' must be a function.",
228-
);
228+
throw new Error("setReactNativeAsyncStorage(*) 'asyncStorage.setItem' must be a function.");
229229
}
230230

231231
if (!isFunction(asyncStorage.getItem)) {
232-
throw new Error(
233-
"firebase.setReactNativeAsyncStorage(*) 'asyncStorage.getItem' must be a function.",
234-
);
232+
throw new Error("setReactNativeAsyncStorage(*) 'asyncStorage.getItem' must be a function.");
235233
}
236234

237235
if (!isFunction(asyncStorage.removeItem)) {
238-
throw new Error(
239-
"firebase.setReactNativeAsyncStorage(*) 'asyncStorage.removeItem' must be a function.",
240-
);
236+
throw new Error("setReactNativeAsyncStorage(*) 'asyncStorage.removeItem' must be a function.");
241237
}
242238

243239
setReactNativeAsyncStorageInternal(asyncStorage);

packages/app/lib/modular/index.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,11 @@ export function getApp(name?: string): FirebaseApp;
7070
* @returns void
7171
*/
7272
export function setLogLevel(logLevel: LogLevelString): void;
73+
74+
/**
75+
* The `AsyncStorage` implementation to use for persisting data on 'Other' platforms.
76+
* If not specified, in memory persistence is used.
77+
*
78+
* This is required if you want to persist things like Auth sessions, Analytics device IDs, etc.
79+
*/
80+
export function setReactNativeAsyncStorage(asyncStorage: ReactNativeAsyncStorage): void;

packages/app/lib/modular/index.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
getApps as getAppsCompat,
77
initializeApp as initializeAppCompat,
88
setLogLevel as setLogLevelCompat,
9+
setReactNativeAsyncStorage as setReactNativeAsyncStorageCompat,
910
} from '../internal';
1011
import { setUserLogHandler } from '../internal/logger';
1112
import sdkVersion from '../version';
@@ -84,4 +85,14 @@ export function setLogLevel(logLevel) {
8485
return setLogLevelCompat.call(null, logLevel, MODULAR_DEPRECATION_ARG);
8586
}
8687

88+
/**
89+
* The `AsyncStorage` implementation to use for persisting data on 'Other' platforms.
90+
* If not specified, in memory persistence is used.
91+
*
92+
* This is required if you want to persist things like Auth sessions, Analytics device IDs, etc.
93+
*/
94+
export function setReactNativeAsyncStorage(asyncStorage) {
95+
return setReactNativeAsyncStorageCompat.call(null, asyncStorage, MODULAR_DEPRECATION_ARG);
96+
}
97+
8798
export const SDK_VERSION = sdkVersion;

packages/auth/lib/web/RNFBAuthModule.js

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -230,20 +230,18 @@ function getCachedAuthInstance(appName) {
230230
// Warn auth persistence is is disabled unless Async Storage implementation is provided.
231231
// eslint-disable-next-line no-console
232232
console.warn(
233-
```
234-
Firebase Auth persistence is disabled. To enable persistence, provide an Async Storage implementation.
235-
236-
For example, to use React Native Async Storage:
237-
238-
import AsyncStorage from '@react-native-async-storage/async-storage';
239-
240-
// Before initializing Firebase set the Async Storage implementation
241-
// that will be used to persist user sessions.
242-
firebase.setReactNativeAsyncStorage(AsyncStorage);
243-
244-
// Then initialize Firebase as normal.
245-
await firebase.initializeApp({ ... });
246-
```,
233+
'Firebase Auth persistence is disabled. To enable persistence, provide an Async Storage implementation.\n' +
234+
'\n' +
235+
'For example, to use React Native Async Storage:\n' +
236+
'\n' +
237+
" import AsyncStorage from '@react-native-async-storage/async-storage';\n" +
238+
'\n' +
239+
' // Before initializing Firebase set the Async Storage implementation\n' +
240+
' // that will be used to persist user sessions.\n' +
241+
' firebase.setReactNativeAsyncStorage(AsyncStorage);\n' +
242+
'\n' +
243+
' // Then initialize Firebase as normal.\n' +
244+
' await firebase.initializeApp({ ... });\n',
247245
);
248246
}
249247
instances[appName] = initializeAuth(getApp(appName), {

0 commit comments

Comments
 (0)