Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(analytics): add 'logScreenView' API and deprecate setCurrentScreen API. #4145

Merged
merged 5 commits into from
Aug 28, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions docs/analytics/screen-tracking.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ therefore there is no "one fits all" solution to screen tracking.

The [React Navigation](https://reactnavigation.org/) library allows for various navigation techniques such as
Stack, Tab, Native or even custom navigation. The `NavigationController` component which the library exposes provides
access to the current navigation state when a screen changes, allowing you to use the [`setCurrentScreen`](/reference/analytics#setCurrentScreen)
access to the current navigation state when a screen changes, allowing you to use the [`logScreenView`](/reference/analytics#logScreenView)
method the Analytics library provides:

```jsx
Expand All @@ -22,12 +22,14 @@ import { NavigationContainer } from '@react-navigation/native';

<NavigationContainer
ref={navigationRef}
onStateChange={state => {
onStateChange={async (state) => {
const previousRouteName = routeNameRef.current;
const currentRouteName = getActiveRouteName(state);

if (previousRouteName !== currentRouteName) {
analytics().setCurrentScreen(currentRouteName, currentRouteName);
await analytics().logScreenView({
screen_name: currentRouteName,
});
}
```

Expand All @@ -38,15 +40,18 @@ documentation on the React Navigation website.

The [`wix/react-native-navigation`](https://github.com/wix/react-native-navigation) provides 100% native platform navigation
for React Native apps. To manually track screens, you need to setup a `componentDidAppear` event listener and manually call the
[`setCurrentScreen`](/reference/analytics#setCurrentScreen) method the Analytics library provides:
[`logScreenView`](/reference/analytics#logScreenView) method the Analytics library provides:

```js
import analytics from '@react-native-firebase/analytics';
import { Navigation } from 'react-native-navigation';

Navigation.events().registerComponentDidAppearListener(({ componentName, componentType }) => {
Navigation.events().registerComponentDidAppearListener(async ({ componentName, componentType }) => {
if (componentType === 'Component') {
analytics().setCurrentScreen(componentName, componentName);
await analytics().logScreenView({
screen_name: componentName,
screen_class: componentName,
});
russellwheatley marked this conversation as resolved.
Show resolved Hide resolved
}
});
```
Expand Down
23 changes: 9 additions & 14 deletions packages/analytics/__tests__/analytics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,6 @@ describe('Analytics', () => {
});
});

it('errors if screenName not a string', () => {
// @ts-ignore test
expect(() => firebase.analytics().setCurrentScreen(666.1337)).toThrowError(
"'screenName' expected a string value",
);
});

it('errors if screenClassOverride not a string', () => {
// @ts-ignore test
expect(() => firebase.analytics().setCurrentScreen('invertase screen', 666.1337)).toThrowError(
"'screenClassOverride' expected a string value",
);
});

it('errors if milliseconds not a number', () => {
// @ts-ignore test
expect(() => firebase.analytics().setMinimumSessionDuration('123')).toThrowError(
Expand Down Expand Up @@ -186,6 +172,15 @@ describe('Analytics', () => {
);
});

describe('logScreenView()', () => {
it('errors if param is not an object', () => {
// @ts-ignore test
expect(() => firebase.analytics().logScreenView(123)).toThrowError(
'firebase.analytics().logScreenView(*):',
);
});
});

describe('logAddPaymentInfo()', () => {
it('errors if param is not an object', () => {
// @ts-ignore test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,20 +52,6 @@ Task<Void> setAnalyticsCollectionEnabled(Boolean enabled) {
});
}

Task<Void> setAnalyticsCollectionEnabled(
Activity currentActivity,
String screenName,
@Nullable String screenClassOverride
) {
return Tasks.call(() -> {
if (currentActivity == null) return null;
FirebaseAnalytics
.getInstance(getContext())
.setCurrentScreen(currentActivity, screenName, screenClassOverride);
return null;
});
}

Task<Void> setMinimumSessionDuration(long milliseconds) {
return Tasks.call(() -> {
FirebaseAnalytics.getInstance(getContext()).setMinimumSessionDuration(milliseconds);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,23 +59,6 @@ public void setAnalyticsCollectionEnabled(Boolean enabled, Promise promise) {
});
}

@ReactMethod
public void setCurrentScreen(
String screenName,
@Nullable String screenClassOverride,
Promise promise
) {
module
.setAnalyticsCollectionEnabled(getCurrentActivity(), screenName, screenClassOverride)
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
promise.resolve(task.getResult());
} else {
rejectPromiseWithExceptionMap(promise, task.getException());
}
});
}

@ReactMethod
public void setMinimumSessionDuration(double milliseconds, Promise promise) {
module.setMinimumSessionDuration((long) milliseconds).addOnCompleteListener(task -> {
Expand Down
18 changes: 8 additions & 10 deletions packages/analytics/e2e/analytics.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,6 @@ describe('analytics()', () => {
});
});

describe('setCurrentScreen()', () => {
russellwheatley marked this conversation as resolved.
Show resolved Hide resolved
it('screenName only', async () => {
await firebase.analytics().setCurrentScreen('invertase screen');
});

it('screenName with screenClassOverride', async () => {
await firebase.analytics().setCurrentScreen('invertase screen', 'invertase class override');
});
});

describe('setMinimumSessionDuration()', () => {
it('default duration', async () => {
await firebase.analytics().setMinimumSessionDuration();
Expand Down Expand Up @@ -116,6 +106,14 @@ describe('analytics()', () => {
});
});

describe('logScreenView()', () => {
it('calls logScreenView', async () => {
await firebase
.analytics()
.logScreenView({ screen_name: 'invertase screen', screen_class: 'invertase class' });
});
});

describe('logAddPaymentInfo()', () => {
it('calls logAddPaymentInfo', async () => {
await firebase.analytics().logAddPaymentInfo({
Expand Down
18 changes: 0 additions & 18 deletions packages/analytics/ios/RNFBAnalytics/RNFBAnalyticsModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -67,24 +67,6 @@ - (dispatch_queue_t)methodQueue {
return resolve([NSNull null]);
}

RCT_EXPORT_METHOD(setCurrentScreen:
(NSString *) screenName
screenClass:
(NSString *) screenClassOverview
resolver:
(RCTPromiseResolveBlock) resolve
rejecter:
(RCTPromiseRejectBlock) reject) {
RCTUnsafeExecuteOnMainQueueSync(^{
@try {
[FIRAnalytics setScreenName:screenName screenClass:screenClassOverview];
} @catch (NSException *exception) {
return [RNFBSharedUtils rejectPromiseWithExceptionDict:reject exception:exception];
}
return resolve([NSNull null]);
});
}

RCT_EXPORT_METHOD(setUserId:
(NSString *) id
resolver:
Expand Down
27 changes: 26 additions & 1 deletion packages/analytics/lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,17 @@ export namespace FirebaseAnalyticsTypes {
transaction_id?: string;
}

export interface ScreenViewParameters {
/**
* Screen name the user is currently viewing.
mikehardy marked this conversation as resolved.
Show resolved Hide resolved
*/
screen_name?: string;
/**
* Current class associated with the view the user is currently viewing.
mikehardy marked this conversation as resolved.
Show resolved Hide resolved
*/
screen_class?: string;
}

export interface RefundEventParameters {
/**
* A product affiliation to designate a supplying company or brick and mortar store location
Expand Down Expand Up @@ -667,10 +678,10 @@ export namespace FirebaseAnalyticsTypes {
*
* @param screenName A screen name, e.g. Product.
* @param screenClassOverride On Android, React Native runs in a single activity called
* @deprecated
* 'MainActivity'. Setting this parameter overrides the default name shown on logs.
russellwheatley marked this conversation as resolved.
Show resolved Hide resolved
*/
setCurrentScreen(screenName: string, screenClassOverride?: string): Promise<void>;
russellwheatley marked this conversation as resolved.
Show resolved Hide resolved

/**
* Sets the minimum engagement time required before starting a session.
*
Expand Down Expand Up @@ -783,6 +794,20 @@ export namespace FirebaseAnalyticsTypes {
* ```
*/
logPurchase(params: PurchaseEventParameters): Promise<void>;
/**
* Sets or clears the screen name and class the user is currently viewing
*
* #### Example
*
* ```js
* await firebase.analytics().logScreenView({
* screen_class: 'ProductScreen',
* screen_name: 'ProductScreen',
* });
* ```
*
*/
logScreenView(params: ScreenViewParameters): Promise<void>;
/**
* Add Payment Info event. This event signifies that a user has submitted their payment information to your app.
*
Expand Down
33 changes: 20 additions & 13 deletions packages/analytics/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,19 +103,13 @@ class FirebaseAnalyticsModule extends FirebaseModule {
}

setCurrentScreen(screenName, screenClassOverride) {
if (!isString(screenName)) {
throw new Error(
"firebase.analytics().setCurrentScreen(*) 'screenName' expected a string value.",
);
}

if (!isUndefined(screenClassOverride) && !isString(screenClassOverride)) {
throw new Error(
"firebase.analytics().setCurrentScreen(_, *) 'screenClassOverride' expected a string value.",
);
}

return this.native.setCurrentScreen(screenName, screenClassOverride);
console.warn(
russellwheatley marked this conversation as resolved.
Show resolved Hide resolved
'firebase.analytics().setCurrentScreen(), is now deprecated. Please use firebase.analytics().logScreenView() instead',
);
return this.logScreenView({
screen_name: screenName,
screen_class: screenClassOverride,
});
}

setMinimumSessionDuration(milliseconds = 10000) {
Expand Down Expand Up @@ -214,6 +208,19 @@ class FirebaseAnalyticsModule extends FirebaseModule {
);
}

logScreenView(object) {
if (!isObject(object)) {
throw new Error(
'firebase.analytics().logScreenView(*): The supplied arg must be an object of key/values.',
);
}

return this.logEvent(
'screen_view',
validateStruct(object, structs.ScreenView, 'firebase.analytics().logScreenView(*):'),
);
}

logAddShippingInfo(object = {}) {
if (!isObject(object)) {
throw new Error(
Expand Down
5 changes: 5 additions & 0 deletions packages/analytics/lib/structs.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ const Item = struct({
item_variant: 'string?',
});

export const ScreenView = struct({
screen_class: 'string?',
screen_name: 'string?',
});

export const AddPaymentInfo = struct({
items: struct.optional([Item]),
value: 'number?',
Expand Down
4 changes: 2 additions & 2 deletions packages/analytics/type-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ console.log(firebase.analytics().resetAnalyticsData);
console.log(firebase.analytics().logViewCart);
console.log(firebase.analytics().setAnalyticsCollectionEnabled);
console.log(firebase.analytics().logSelectPromotion);
console.log(firebase.analytics().setCurrentScreen);
console.log(firebase.analytics().logScreenView);
console.log(firebase.analytics().logViewPromotion);
console.log(firebase.analytics().setMinimumSessionDuration);
console.log(firebase.analytics().setSessionTimeoutDuration);
Expand Down Expand Up @@ -108,7 +108,7 @@ console.log(analytics().resetAnalyticsData);
console.log(analytics().logViewCart);
console.log(analytics().setAnalyticsCollectionEnabled);
console.log(analytics().logSelectPromotion);
console.log(analytics().setCurrentScreen);
console.log(analytics().logScreenView);
console.log(analytics().logViewPromotion);
console.log(analytics().setMinimumSessionDuration);
console.log(analytics().setSessionTimeoutDuration);
Expand Down