diff options
Diffstat (limited to 'src/lib/analytics/analytics.tsx')
-rw-r--r-- | src/lib/analytics/analytics.tsx | 85 |
1 files changed, 39 insertions, 46 deletions
diff --git a/src/lib/analytics/analytics.tsx b/src/lib/analytics/analytics.tsx index 1650dfd3f..64b66904b 100644 --- a/src/lib/analytics/analytics.tsx +++ b/src/lib/analytics/analytics.tsx @@ -1,15 +1,10 @@ import React from 'react' import {AppState, AppStateStatus} from 'react-native' import AsyncStorage from '@react-native-async-storage/async-storage' -import { - createClient, - AnalyticsProvider, - useAnalytics as useAnalyticsOrig, - ClientMethods, -} from '@segment/analytics-react-native' +import {createClient, SegmentClient} from '@segment/analytics-react-native' import {useSession, SessionAccount} from '#/state/session' import {sha256} from 'js-sha256' -import {ScreenEvent, TrackEvent} from './types' +import {TrackEvent, AnalyticsMethods} from './types' import {logger} from '#/logger' type AppInfo = { @@ -19,53 +14,56 @@ type AppInfo = { version?: string | undefined } -const segmentClient = createClient({ - writeKey: '8I6DsgfiSLuoONyaunGoiQM7A6y2ybdI', - trackAppLifecycleEvents: false, - proxy: 'https://api.events.bsky.app/v1', -}) +// Delay creating until first actual use. +let segmentClient: SegmentClient | null = null +function getClient(): SegmentClient { + if (!segmentClient) { + segmentClient = createClient({ + writeKey: '8I6DsgfiSLuoONyaunGoiQM7A6y2ybdI', + trackAppLifecycleEvents: false, + proxy: 'https://api.events.bsky.app/v1', + }) + } + return segmentClient +} -export const track = segmentClient?.track?.bind?.(segmentClient) as TrackEvent +export const track: TrackEvent = async (...args) => { + await getClient().track(...args) +} -export function useAnalytics() { +export function useAnalytics(): AnalyticsMethods { const {hasSession} = useSession() - const methods: ClientMethods = useAnalyticsOrig() return React.useMemo(() => { if (hasSession) { return { - screen: methods.screen as ScreenEvent, // ScreenEvents defines all the possible screen names - track: methods.track as TrackEvent, // TrackEvents defines all the possible track events and their properties - identify: methods.identify, - flush: methods.flush, - group: methods.group, - alias: methods.alias, - reset: methods.reset, + async screen(...args) { + await getClient().screen(...args) + }, + async track(...args) { + await getClient().track(...args) + }, } } // dont send analytics pings for anonymous users return { - screen: () => Promise<void>, - track: () => Promise<void>, - identify: () => Promise<void>, - flush: () => Promise<void>, - group: () => Promise<void>, - alias: () => Promise<void>, - reset: () => Promise<void>, + screen: async () => {}, + track: async () => {}, } - }, [hasSession, methods]) + }, [hasSession]) } export function init(account: SessionAccount | undefined) { setupListenersOnce() if (account) { + const client = getClient() if (account.did) { const did_hashed = sha256(account.did) - segmentClient.identify(did_hashed, {did_hashed}) + client.identify(did_hashed, {did_hashed}) logger.debug('Ping w/hash') } else { logger.debug('Ping w/o hash') - segmentClient.identify() + client.identify() } } } @@ -80,12 +78,13 @@ function setupListenersOnce() { // this is a copy of segment's own lifecycle event tracking // we handle it manually to ensure that it never fires while the app is backgrounded // -prf - segmentClient.isReady.onChange(async () => { + const client = getClient() + client.isReady.onChange(async () => { if (AppState.currentState !== 'active') { logger.debug('Prevented a metrics ping while the app was backgrounded') return } - const context = segmentClient.context.get() + const context = client.context.get() if (typeof context?.app === 'undefined') { logger.debug('Aborted metrics ping due to unavailable context') return @@ -97,19 +96,19 @@ function setupListenersOnce() { logger.debug('Recording app info', {new: newAppInfo, old: oldAppInfo}) if (typeof oldAppInfo === 'undefined') { - segmentClient.track('Application Installed', { + client.track('Application Installed', { version: newAppInfo.version, build: newAppInfo.build, }) } else if (newAppInfo.version !== oldAppInfo.version) { - segmentClient.track('Application Updated', { + client.track('Application Updated', { version: newAppInfo.version, build: newAppInfo.build, previous_version: oldAppInfo.version, previous_build: oldAppInfo.build, }) } - segmentClient.track('Application Opened', { + client.track('Application Opened', { from_background: false, version: newAppInfo.version, build: newAppInfo.build, @@ -119,25 +118,19 @@ function setupListenersOnce() { let lastState: AppStateStatus = AppState.currentState AppState.addEventListener('change', (state: AppStateStatus) => { if (state === 'active' && lastState !== 'active') { - const context = segmentClient.context.get() - segmentClient.track('Application Opened', { + const context = client.context.get() + client.track('Application Opened', { from_background: true, version: context?.app?.version, build: context?.app?.build, }) } else if (state !== 'active' && lastState === 'active') { - segmentClient.track('Application Backgrounded') + client.track('Application Backgrounded') } lastState = state }) } -export function Provider({children}: React.PropsWithChildren<{}>) { - return ( - <AnalyticsProvider client={segmentClient}>{children}</AnalyticsProvider> - ) -} - async function writeAppInfo(value: AppInfo) { await AsyncStorage.setItem('BSKY_APP_INFO', JSON.stringify(value)) } |