Skip to content

Commit

Permalink
feat(analytics): implement getSessionId
Browse files Browse the repository at this point in the history
  • Loading branch information
dlackty authored and mikehardy committed Jul 13, 2023
1 parent b3ce13f commit 566470c
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ Task<String> getAppInstanceId() {
return FirebaseAnalytics.getInstance(getContext()).getAppInstanceId();
}

Task<Long> getSessionId() {
return FirebaseAnalytics.getInstance(getContext()).getSessionId();
}

Task<Void> setUserId(String id) {
return Tasks.call(
() -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,21 @@ public void getAppInstanceId(Promise promise) {
});
}

@ReactMethod
public void getSessionId(Promise promise) {
module
.getSessionId()
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
Long result = task.getResult();
promise.resolve(result != null ? result.doubleValue() : null);
} else {
rejectPromiseWithExceptionMap(promise, task.getException());
}
});
}

@ReactMethod
public void setUserId(String id, Promise promise) {
module
Expand Down
34 changes: 34 additions & 0 deletions packages/analytics/e2e/analytics.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,40 @@ describe('analytics()', function () {
});
});

describe('getSessionId()', function () {
it('calls native fn without error', async function () {
await firebase.analytics().getSessionId();
});

it('returns a non empty session ID', async function () {
let sessionId = await firebase.analytics().getSessionId();
// On iOS it can take ~ 3 minutes for the session ID to be generated
// Otherwise, `Analytics uninitialized` error will be thrown
const retries = 240;
while (!sessionId && retries > 0) {
await Utils.sleep(1000);
sessionId = await firebase.analytics().getSessionId();
}

if (!sessionId) {
return Promise.reject(
new Error('Firebase SDK did not return a session ID after 4 minutes'),
);
}

sessionId.should.not.equal(0);
});

it('returns a null value if session expires', async function () {
// Set session duration to 1 millisecond
firebase.analytics().setSessionTimeoutDuration(1);
// Wait 100 millisecond to ensure session expires
await Utils.sleep(100);
const sessionId = await firebase.analytics().getSessionId();
should.equal(sessionId, null);
});
});

describe('setUserId()', function () {
it('allows a null values to be set', async function () {
await firebase.analytics().setUserId(null);
Expand Down
71 changes: 71 additions & 0 deletions packages/analytics/e2e/analytics.modular.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,40 @@ describe('analytics() modular', function () {
});
});

describe('getSessionId()', function () {
it('calls native fn without error', async function () {
await firebase.analytics().getSessionId();
});

it('returns a non empty session ID', async function () {
let sessionId = await firebase.analytics().getSessionId();
// On iOS it can take ~ 3 minutes for the session ID to be generated
// Otherwise, `Analytics uninitialized` error will be thrown
const retries = 240;
while (!sessionId && retries > 0) {
await Utils.sleep(1000);
sessionId = await firebase.analytics().getSessionId();
}

if (!sessionId) {
return Promise.reject(
new Error('Firebase SDK did not return a session ID after 4 minutes'),
);
}

sessionId.should.not.equal(0);
});

it('returns a null value if session expires', async function () {
// Set session duration to 1 millisecond
firebase.analytics().setSessionTimeoutDuration(1);
// Wait 100 millisecond to ensure session expires
await Utils.sleep(100);
const sessionId = await firebase.analytics().getSessionId();
should.equal(sessionId, null);
});
});

describe('setUserId()', function () {
it('allows a null values to be set', async function () {
await firebase.analytics().setUserId(null);
Expand Down Expand Up @@ -503,6 +537,43 @@ describe('analytics() modular', function () {
});
});

describe('getSessionId()', function () {
it('calls native fn without error', async function () {
const { getAnalytics, getSessionId } = analyticsModular;
await getSessionId(getAnalytics());
});

it('returns a non empty session ID', async function () {
const { getAnalytics, getSessionId } = analyticsModular;
let sessionId = await getSessionId(getAnalytics());
// On iOS it can take ~ 3 minutes for the session ID to be generated
// Otherwise, `Analytics uninitialized` error will be thrown
const retries = 240;
while (!sessionId && retries > 0) {
await Utils.sleep(1000);
sessionId = await getSessionId(getAnalytics());
}

if (!sessionId) {
return Promise.reject(
new Error('Firebase SDK did not return a session ID after 4 minutes'),
);
}

sessionId.should.not.equal(0);
});

it('returns a null value if session expires', async function () {
const { getAnalytics, getSessionId, setSessionTimeoutDuration } = analyticsModular;
// Set session duration to 1 millisecond
setSessionTimeoutDuration(getAnalytics(), 1);
// Wait 100 millisecond to ensure session expires
await Utils.sleep(100);
const sessionId = await getSessionId(getAnalytics());
should.equal(sessionId, null);
});
});

describe('setUserId()', function () {
it('allows a null values to be set', async function () {
const { getAnalytics, setUserId } = analyticsModular;
Expand Down
13 changes: 13 additions & 0 deletions packages/analytics/ios/RNFBAnalytics/RNFBAnalyticsModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,19 @@ - (dispatch_queue_t)methodQueue {
return resolve([FIRAnalytics appInstanceID]);
}

RCT_EXPORT_METHOD(getSessionId
: (RCTPromiseResolveBlock)resolve rejecter
: (RCTPromiseRejectBlock)reject) {
[FIRAnalytics sessionIDWithCompletion:^(int64_t sessionID, NSError *_Nullable error) {
if (error) {
DLog(@"Error getting session ID: %@", error);
return resolve([NSNull null]);
} else {
return resolve([NSNumber numberWithLongLong:sessionID]);
}
}];
}

RCT_EXPORT_METHOD(setDefaultEventParameters
: (NSDictionary *)params resolver
: (RCTPromiseResolveBlock)resolve rejecter
Expand Down
14 changes: 14 additions & 0 deletions packages/analytics/lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -869,6 +869,20 @@ export namespace FirebaseAnalyticsTypes {
*/
getAppInstanceId(): Promise<string | null>;

/**
* Retrieves the session id from the client.
* On iOS, Firebase SDK may return an error that is handled internally and may take many minutes to return a valid value. Check native debug logs for more details.
*
* #### Example
*
* ```js
* const sessionId = await firebase.analytics().getSessionId();
* ```
*
* @returns Returns the session id or null if session is expired, null on android if FirebaseAnalytics.ConsentType.ANALYTICS_STORAGE has been set to FirebaseAnalytics.ConsentStatus.DENIED and null on iOS if ConsentType.analyticsStorage has been set to ConsentStatus.denied.
*/
getSessionId(): Promise<number | null>;

/**
* Gives a user a unique identification.
*
Expand Down
5 changes: 5 additions & 0 deletions packages/analytics/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export {
setAnalyticsCollectionEnabled,
setSessionTimeoutDuration,
getAppInstanceId,
getSessionId,
setUserId,
setUserProperty,
setUserProperties,
Expand Down Expand Up @@ -196,6 +197,10 @@ class FirebaseAnalyticsModule extends FirebaseModule {
return this.native.getAppInstanceId();
}

getSessionId() {
return this.native.getSessionId();
}

setUserId(id) {
if (!isNull(id) && !isString(id)) {
throw new Error("firebase.analytics().setUserId(*) 'id' expected a string value.");
Expand Down
10 changes: 10 additions & 0 deletions packages/analytics/modular/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ export function setSessionTimeoutDuration(analytics, milliseconds = 1800000) {
export function getAppInstanceId(analytics) {
return analytics.getAppInstanceId();
}
/**
* Retrieves the session id from the client.
* On iOS, Firebase SDK may return an error that is handled internally and may take many minutes to return a valid value. Check native debug logs for more details.
*
* @param analytics Analytics instance.
* @returns Returns the session id or null if session is expired, null on android if FirebaseAnalytics.ConsentType.ANALYTICS_STORAGE has been set to FirebaseAnalytics.ConsentStatus.DENIED and null on iOS if ConsentType.analyticsStorage has been set to ConsentStatus.denied.
*/
export function getSessionId(analytics) {
return analytics.getSessionId();
}
/**
* Gives a user a unique identification.
*
Expand Down

1 comment on commit 566470c

@vercel
Copy link

@vercel vercel bot commented on 566470c Jul 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.