diff --git a/packages/plugins/plugin-appsflyer/README.md b/packages/plugins/plugin-appsflyer/README.md index 5d8237b47..5cb13ca0b 100644 --- a/packages/plugins/plugin-appsflyer/README.md +++ b/packages/plugins/plugin-appsflyer/README.md @@ -22,6 +22,8 @@ Run `pod install` after the installation to autolink the AppsFlyer SDK. See [AppsFlyer React Native Plugin](https://github.com/AppsFlyerSDK/appsflyer-react-native-plugin) for more details of this dependency. +This plugin requires `react-native-appsflyer` 7.x, which requires React Native 0.76 or later with the New Architecture enabled. For `react-native-appsflyer` 6.x, use an earlier release of this plugin. + ## Usage Follow the [instructions for adding plugins](https://github.com/segmentio/analytics-react-native#adding-plugins) on the main Analytics client: @@ -44,6 +46,12 @@ const plugin = new AppsflyerPlugin(); segmentClient.add({ plugin }); ``` +The plugin registers the AppsFlyer conversion and deep link listeners. `react-native-appsflyer` keeps one callback per listener, so do not register your own. Pass `onInstallConversionData` and `onDeepLink` to the plugin instead. + +### App Tracking Transparency on iOS + +The plugin does not wait for ATT authorization, because `react-native-appsflyer` 7.x removed `timeToWaitForATTUserAuthorization`. Request ATT authorization before you add the plugin. + ### Tracking Deep Links on iOS The Analytics React Native SDK [requires additonal setup](https://github.com/segmentio/analytics-react-native#ios-deep-link-tracking-setup) to automatically track deep links. If you are also tracking [Universal Links](https://dev.appsflyer.com/hc/docs/ios-sdk-reference-appsflyerlib#continue), add the following to your `AppDelegate.m` : diff --git a/packages/plugins/plugin-appsflyer/package.json b/packages/plugins/plugin-appsflyer/package.json index f8e330d22..53b485b54 100644 --- a/packages/plugins/plugin-appsflyer/package.json +++ b/packages/plugins/plugin-appsflyer/package.json @@ -46,14 +46,14 @@ "homepage": "https://github.com/segmentio/analytics-react-native/tree/master/packages/plugins/plugin-appsflyer#readme", "peerDependencies": { "@segment/analytics-react-native": "^2.18.0", - "react-native-appsflyer": "^6.9.4" + "react-native-appsflyer": "^7.0.2-0" }, "devDependencies": { "@segment/analytics-react-native": "^2.18.0", "@segment/analytics-rn-shared": "workspace:^", "@segment/sovran-react-native": "^1.1.0", "jest": "^29.7.0", - "react-native-appsflyer": "^6.9.4", + "react-native-appsflyer": "^7.0.2-0", "react-native-builder-bob": "^0.23.1", "rimraf": "^5.0.5", "semantic-release": "^22.0.8", diff --git a/packages/plugins/plugin-appsflyer/src/AppsflyerPlugin.tsx b/packages/plugins/plugin-appsflyer/src/AppsflyerPlugin.tsx index 360c725a3..7f62d2e70 100644 --- a/packages/plugins/plugin-appsflyer/src/AppsflyerPlugin.tsx +++ b/packages/plugins/plugin-appsflyer/src/AppsflyerPlugin.tsx @@ -1,6 +1,7 @@ import { DestinationPlugin, IdentifyEventType, + JsonMap, PluginType, TrackEventType, UpdateType, @@ -11,33 +12,27 @@ import { import type { SegmentAppsflyerSettings } from './types'; import appsFlyer, { ConversionData, - OnAppOpenAttributionData, - UnifiedDeepLinkData, + DeepLinkData, } from 'react-native-appsflyer'; import identify from './methods/identify'; import track from './methods/track'; export class AppsflyerPlugin extends DestinationPlugin { constructor(props?: { - timeToWaitForATTUserAuthorization: number; is_adset: boolean; is_adset_id: boolean; is_ad_id: boolean; - onDeepLink?: (data: UnifiedDeepLinkData) => void; + onDeepLink?: (data: DeepLinkData) => void; onInstallConversionData?: (data: ConversionData) => void; - onAppOpenAttribution?: (data: OnAppOpenAttributionData) => void; }) { super(); if (props != null) { - this.timeToWaitForATTUserAuthorization = - props.timeToWaitForATTUserAuthorization; this.is_adset = props.is_adset === undefined ? false : props.is_adset; this.is_ad_id = props.is_ad_id === undefined ? false : props.is_ad_id; this.is_adset_id = props.is_adset_id === undefined ? false : props.is_adset_id; this.onDeepLink = props.onDeepLink; this.onInstallConversionData = props.onInstallConversionData; - this.onAppOpenAttribution = props.onAppOpenAttribution; } } type = PluginType.destination; @@ -45,22 +40,14 @@ export class AppsflyerPlugin extends DestinationPlugin { is_adset = false; is_adset_id = false; is_ad_id = false; - onDeepLink?: (data: UnifiedDeepLinkData) => void; + onDeepLink?: (data: DeepLinkData) => void; onInstallConversionData?: (data: ConversionData) => void; - onAppOpenAttribution?: (data: OnAppOpenAttributionData) => void; private settings: SegmentAppsflyerSettings | null = null; private hasRegisteredInstallCallback = false; private hasRegisteredDeepLinkCallback = false; private hasInitialized = false; - timeToWaitForATTUserAuthorization = 60; - async update(settings: SegmentAPISettings, _: UpdateType): Promise { - const defaultOpts = { - isDebug: false, - timeToWaitForATTUserAuthorization: this.timeToWaitForATTUserAuthorization, - onInstallConversionDataListener: true, - }; const appsflyerSettings = settings.integrations[ this.key ] as SegmentAppsflyerSettings; @@ -72,39 +59,40 @@ export class AppsflyerPlugin extends DestinationPlugin { this.settings = appsflyerSettings; - if ( - this.settings.trackAttributionData && - !this.hasRegisteredInstallCallback - ) { - this.registerConversionCallback(); - this.hasRegisteredInstallCallback = true; - } - + // Must reach native before init(): Android permanently drops a deep link that resolves with no listener attached. if ( clientConfig?.trackDeepLinks === true && !this.hasRegisteredDeepLinkCallback ) { this.registerDeepLinkCallback(); - this.registerUnifiedDeepLinkCallback(); - this.hasRegisteredDeepLinkCallback = true; } - if (!this.hasInitialized) { - try { - await appsFlyer.initSdk({ + + const initialization = this.hasInitialized + ? undefined + : appsFlyer.init({ devKey: this.settings.appsFlyerDevKey, appId: this.settings.appleAppID, - onDeepLinkListener: clientConfig?.trackDeepLinks === true, - ...defaultOpts, }); - this.hasInitialized = true; - } catch (error) { - const message = 'AppsFlyer failed to initialize'; - this.analytics?.reportInternalError( - new SegmentError(ErrorType.PluginError, message, error) - ); - this.analytics?.logger.warn(`${message}: ${JSON.stringify(error)}`); - } + this.hasInitialized = true; + + if ( + this.settings.trackAttributionData && + !this.hasRegisteredInstallCallback + ) { + this.registerConversionCallback(); + this.hasRegisteredInstallCallback = true; + } + + if (initialization === undefined) { + return; + } + this.registerSessionReadyCallback(); + try { + await initialization; + } catch (error) { + this.hasInitialized = false; + this.reportError('AppsFlyer failed to initialize', error); } } @@ -118,101 +106,122 @@ export class AppsflyerPlugin extends DestinationPlugin { return event; } + registerSessionReadyCallback = () => { + appsFlyer + .registerSessionReadyListener(() => { + appsFlyer + .start() + .catch((error) => + this.reportError('AppsFlyer failed to start', error) + ); + }) + .catch((error) => + this.reportError( + 'AppsFlyer failed to register the session ready listener', + error + ) + ); + }; + registerConversionCallback = () => { - appsFlyer.onInstallConversionData((res) => { - const { - af_status, - media_source, - campaign, - is_first_launch, - adset_id, - ad_id, - adset, - } = res?.data; - const properties = { - provider: this.key, - campaign: { - source: media_source, - name: campaign, + appsFlyer + .registerConversionListener({ + onConversionDataSuccess: (data) => { + const { + af_status, + media_source, + campaign, + is_first_launch, + adset_id, + ad_id, + adset, + } = data as JsonMap; + const properties = { + provider: this.key, + campaign: { + source: media_source, + name: campaign, + }, + }; + if (this.is_adset_id) { + Object.assign(properties, { adset_id: adset_id }); + } + if (this.is_ad_id) { + Object.assign(properties, { ad_id: ad_id }); + } + if (this.is_adset) { + Object.assign(properties, { adset: adset }); + } + if (is_first_launch === true || is_first_launch === 'true') { + if (af_status === 'Non-organic') { + this.analytics + ?.track('Install Attributed', properties) + .then(() => + this.analytics?.logger.info( + 'Sent Install Attributed event to Segment' + ) + ); + } else { + this.analytics + ?.track('Organic Install', { + provider: 'AppsFlyer', + }) + .then(() => + this.analytics?.logger.info( + 'Sent Organic Install event to Segment' + ) + ); + } + } + this.onInstallConversionData?.(data); }, - }; - if (this.is_adset_id) { - Object.assign(properties, { adset_id: adset_id }); - } - if (this.is_ad_id) { - Object.assign(properties, { ad_id: ad_id }); - } - if (this.is_adset) { - Object.assign(properties, { adset: adset }); - } - if (Boolean(is_first_launch) && JSON.parse(is_first_launch) === true) { - if (af_status === 'Non-organic') { - this.analytics - ?.track('Install Attributed', properties) - .then(() => - this.analytics?.logger.info( - 'Sent Install Attributed event to Segment' - ) - ); - } else { - this.analytics - ?.track('Organic Install', { - provider: 'AppsFlyer', - }) - .then(() => - this.analytics?.logger.info( - 'Sent Organic Install event to Segment' - ) - ); - } - } - this.onInstallConversionData?.(res); - }); + }) + .catch((error) => + this.reportError( + 'AppsFlyer failed to register the conversion listener', + error + ) + ); }; registerDeepLinkCallback = () => { - appsFlyer.onAppOpenAttribution((res) => { - if (res?.status === 'success') { - const { campaign, media_source } = res.data; - const properties = { - provider: this.key, - campaign: { - name: campaign, - source: media_source, - }, - }; - this.analytics - ?.track('Deep Link Opened', properties) - .then(() => - this.analytics?.logger.info( - 'Sent Deep Link Opened event to Segment' - ) - ); - } - this.onAppOpenAttribution?.(res); - }); + appsFlyer + .registerDeepLinkListener({ + onDeepLinking: (data) => { + if (data.status === 'FOUND' && data.deepLink !== undefined) { + const { deep_link_value, media_source, campaign } = + data.deepLink as JsonMap; + const properties = { + provider: this.key, + deepLink: deep_link_value, + campaign: { + name: campaign, + source: media_source, + }, + }; + this.analytics + ?.track('Deep Link Opened', properties) + .then(() => + this.analytics?.logger.info( + 'Sent Deep Link Opened event to Segment' + ) + ); + } + this.onDeepLink?.(data); + }, + }) + .catch((error) => + this.reportError( + 'AppsFlyer failed to register the deep link listener', + error + ) + ); }; - registerUnifiedDeepLinkCallback = () => { - appsFlyer.onDeepLink((res) => { - if (res.deepLinkStatus !== 'NOT_FOUND') { - const { DLValue, media_source, campaign } = res.data; - const properties = { - deepLink: DLValue as string, - campaign: { - name: campaign, - source: media_source, - }, - }; - this.analytics - ?.track('Deep Link Opened', properties) - .then(() => - this.analytics?.logger.info( - 'Sent Deep Link Opened event to Segment' - ) - ); - } - this.onDeepLink?.(res); - }); - }; + private reportError(message: string, error: unknown) { + this.analytics?.reportInternalError( + new SegmentError(ErrorType.PluginError, message, error) + ); + this.analytics?.logger.warn(`${message}: ${JSON.stringify(error)}`); + } } diff --git a/packages/plugins/plugin-appsflyer/src/__tests__/AppsflyerPlugin.test.ts b/packages/plugins/plugin-appsflyer/src/__tests__/AppsflyerPlugin.test.ts index 145c45996..77bbf2828 100644 --- a/packages/plugins/plugin-appsflyer/src/__tests__/AppsflyerPlugin.test.ts +++ b/packages/plugins/plugin-appsflyer/src/__tests__/AppsflyerPlugin.test.ts @@ -1,20 +1,172 @@ +import { + SegmentAPISettings, + SegmentClient, + UpdateType, +} from '@segment/analytics-react-native'; +import type { + ConversionCallbacks, + DeepLinkCallbacks, + DeepLinkData, +} from 'react-native-appsflyer'; import { AppsflyerPlugin } from '../AppsflyerPlugin'; +import { + init, + registerConversionListener, + registerDeepLinkListener, + registerSessionReadyListener, + start, +} from '../methods/__mocks__/react-native-appsflyer'; + +const settings = { + integrations: { + AppsFlyer: { + appsFlyerDevKey: 'devKey', + appleAppID: 'appId', + trackAttributionData: true, + }, + }, +} as unknown as SegmentAPISettings; + +const createClient = () => + ({ + getConfig: () => ({ trackDeepLinks: true }), + track: jest.fn(() => Promise.resolve()), + reportInternalError: jest.fn(), + logger: { info: jest.fn(), warn: jest.fn() }, + } as unknown as SegmentClient); + +const setup = async () => { + const client = createClient(); + const plugin = new AppsflyerPlugin(); + plugin.configure(client); + await plugin.update(settings, UpdateType.initial); + return { client, plugin }; +}; + +const lastCallArg = (mock: jest.Mock) => { + const calls = mock.mock.calls as T[][]; + return calls[calls.length - 1][0]; +}; describe('#appsflyerPlugin', () => { beforeEach(() => { jest.clearAllMocks(); }); - it('Appsflyer plugin without timeToWait', () => { - const plugin = new AppsflyerPlugin(); - expect(plugin.timeToWaitForATTUserAuthorization).toEqual(60); + + it('registers the deep link listener before init and the rest after', async () => { + await setup(); + + expect(init).toHaveBeenCalledWith({ devKey: 'devKey', appId: 'appId' }); + const order = (mock: jest.Mock) => mock.mock.invocationCallOrder[0]; + expect(order(registerDeepLinkListener)).toBeLessThan(order(init)); + expect(order(init)).toBeLessThan(order(registerConversionListener)); + expect(order(init)).toBeLessThan(order(registerSessionReadyListener)); + expect(start).not.toHaveBeenCalled(); + }); + + it('starts the SDK when the session is ready', async () => { + await setup(); + + lastCallArg<() => void>(registerSessionReadyListener)(); + + expect(start).toHaveBeenCalledTimes(1); + }); + + it('initializes only once', async () => { + const { plugin } = await setup(); + await plugin.update(settings, UpdateType.refresh); + + expect(init).toHaveBeenCalledTimes(1); + expect(registerDeepLinkListener).toHaveBeenCalledTimes(1); + expect(registerConversionListener).toHaveBeenCalledTimes(1); }); - it('Appsflyer plugin with timeToWait', () => { + + it('retries init after a failure', async () => { + init.mockImplementationOnce(() => Promise.reject(new Error('boom'))); + const { client, plugin } = await setup(); + expect(client.reportInternalError).toHaveBeenCalledTimes(1); + + await plugin.update(settings, UpdateType.refresh); + + expect(init).toHaveBeenCalledTimes(2); + }); + + it('tracks Deep Link Opened once for a found deep link', async () => { + const onDeepLink = jest.fn(); + const client = createClient(); const plugin = new AppsflyerPlugin({ - timeToWaitForATTUserAuthorization: 90, - is_ad_id: true, - is_adset: true, - is_adset_id: true, + is_adset: false, + is_adset_id: false, + is_ad_id: false, + onDeepLink, + }); + plugin.configure(client); + await plugin.update(settings, UpdateType.initial); + + const data: DeepLinkData = { + status: 'FOUND', + deepLink: { + deep_link_value: 'promo', + media_source: 'source', + campaign: 'campaign', + }, + }; + lastCallArg(registerDeepLinkListener).onDeepLinking?.( + data + ); + + expect(client.track).toHaveBeenCalledTimes(1); + expect(client.track).toHaveBeenCalledWith('Deep Link Opened', { + provider: 'AppsFlyer', + deepLink: 'promo', + campaign: { name: 'campaign', source: 'source' }, + }); + expect(onDeepLink).toHaveBeenCalledWith(data); + }); + + it('does not track a deep link that was not found', async () => { + const { client } = await setup(); + + lastCallArg(registerDeepLinkListener).onDeepLinking?.({ + status: 'NOT_FOUND', + }); + + expect(client.track).not.toHaveBeenCalled(); + }); + + it.each([true, 'true'])( + 'tracks Install Attributed on a first launch of %p', + async (isFirstLaunch) => { + const { client } = await setup(); + + lastCallArg( + registerConversionListener + ).onConversionDataSuccess?.({ + af_status: 'Non-organic', + is_first_launch: isFirstLaunch, + media_source: 'source', + campaign: 'campaign', + }); + + expect(client.track).toHaveBeenCalledWith('Install Attributed', { + provider: 'AppsFlyer', + campaign: { source: 'source', name: 'campaign' }, + }); + } + ); + + it('tracks Organic Install on an organic first launch', async () => { + const { client } = await setup(); + + lastCallArg( + registerConversionListener + ).onConversionDataSuccess?.({ + af_status: 'Organic', + is_first_launch: true, + }); + + expect(client.track).toHaveBeenCalledWith('Organic Install', { + provider: 'AppsFlyer', }); - expect(plugin.timeToWaitForATTUserAuthorization).toEqual(90); }); }); diff --git a/packages/plugins/plugin-appsflyer/src/methods/__mocks__/react-native-appsflyer.ts b/packages/plugins/plugin-appsflyer/src/methods/__mocks__/react-native-appsflyer.ts index d204f0420..6106f83f6 100644 --- a/packages/plugins/plugin-appsflyer/src/methods/__mocks__/react-native-appsflyer.ts +++ b/packages/plugins/plugin-appsflyer/src/methods/__mocks__/react-native-appsflyer.ts @@ -1,9 +1,19 @@ -export const logEvent = jest.fn(); -export const setCurrencyCode = jest.fn(); -export const setCustomerUserId = jest.fn(); -export const setAdditionalData = jest.fn(); +export const init = jest.fn(() => Promise.resolve()); +export const start = jest.fn(() => Promise.resolve()); +export const registerSessionReadyListener = jest.fn(() => Promise.resolve()); +export const registerConversionListener = jest.fn(() => Promise.resolve()); +export const registerDeepLinkListener = jest.fn(() => Promise.resolve()); +export const logEvent = jest.fn(() => Promise.resolve()); +export const setCurrencyCode = jest.fn(() => Promise.resolve()); +export const setCustomerUserId = jest.fn(() => Promise.resolve()); +export const setAdditionalData = jest.fn(() => Promise.resolve()); export default { + init, + start, + registerSessionReadyListener, + registerConversionListener, + registerDeepLinkListener, logEvent, setCurrencyCode, setCustomerUserId, diff --git a/packages/plugins/plugin-appsflyer/src/methods/__tests__/identify.test.ts b/packages/plugins/plugin-appsflyer/src/methods/__tests__/identify.test.ts index cbc89a085..273a3958a 100644 --- a/packages/plugins/plugin-appsflyer/src/methods/__tests__/identify.test.ts +++ b/packages/plugins/plugin-appsflyer/src/methods/__tests__/identify.test.ts @@ -19,7 +19,7 @@ describe('#identify', () => { identify(payload as IdentifyEventType); - expect(setCustomerUserId).toHaveBeenCalledWith('user'); + expect(setCustomerUserId).toHaveBeenCalledWith({ customerId: 'user' }); }); it('sets custom data', () => { @@ -36,9 +36,11 @@ describe('#identify', () => { identify(payload as IdentifyEventType); expect(setAdditionalData).toHaveBeenCalledWith({ - email: 'john.smith@email.com', - firstName: 'John', - lastName: 'Smith', + customData: { + email: 'john.smith@email.com', + firstName: 'John', + lastName: 'Smith', + }, }); }); @@ -52,6 +54,6 @@ describe('#identify', () => { identify(payload as IdentifyEventType); - expect(setCurrencyCode).toHaveBeenCalledWith('JPY'); + expect(setCurrencyCode).toHaveBeenCalledWith({ currencyCode: 'JPY' }); }); }); diff --git a/packages/plugins/plugin-appsflyer/src/methods/__tests__/track.test.ts b/packages/plugins/plugin-appsflyer/src/methods/__tests__/track.test.ts index 5a2724768..25e97236f 100644 --- a/packages/plugins/plugin-appsflyer/src/methods/__tests__/track.test.ts +++ b/packages/plugins/plugin-appsflyer/src/methods/__tests__/track.test.ts @@ -15,7 +15,10 @@ describe('#identify', () => { await track(payload as TrackEventType); - expect(logEvent).toHaveBeenCalledWith('Some Event', {}); + expect(logEvent).toHaveBeenCalledWith({ + eventName: 'Some Event', + eventValues: {}, + }); }); it('logs an event with revenue as string and currency', async () => { @@ -31,10 +34,13 @@ describe('#identify', () => { await track(payload as TrackEventType); - expect(logEvent).toHaveBeenCalledWith('Some Event', { - foo: 'bar', - af_revenue: 1, - af_currency: 'JPY', + expect(logEvent).toHaveBeenCalledWith({ + eventName: 'Some Event', + eventValues: { + foo: 'bar', + af_revenue: 1, + af_currency: 'JPY', + }, }); }); @@ -51,10 +57,13 @@ describe('#identify', () => { await track(payload as TrackEventType); - expect(logEvent).toHaveBeenCalledWith('Some Event', { - foo: 'bar', - af_revenue: 1, - af_currency: 'JPY', + expect(logEvent).toHaveBeenCalledWith({ + eventName: 'Some Event', + eventValues: { + foo: 'bar', + af_revenue: 1, + af_currency: 'JPY', + }, }); }); @@ -71,10 +80,13 @@ describe('#identify', () => { await track(payload as TrackEventType); - expect(logEvent).toHaveBeenCalledWith('Some Event', { - currency: 'JPY', - revenue: true, - foo: 'bar', + expect(logEvent).toHaveBeenCalledWith({ + eventName: 'Some Event', + eventValues: { + currency: 'JPY', + revenue: true, + foo: 'bar', + }, }); }); @@ -90,10 +102,13 @@ describe('#identify', () => { await track(payload as TrackEventType); - expect(logEvent).toHaveBeenCalledWith('Some Event', { - foo: 'bar', - af_revenue: 1, - af_currency: 'USD', + expect(logEvent).toHaveBeenCalledWith({ + eventName: 'Some Event', + eventValues: { + foo: 'bar', + af_revenue: 1, + af_currency: 'USD', + }, }); }); }); diff --git a/packages/plugins/plugin-appsflyer/src/methods/identify.ts b/packages/plugins/plugin-appsflyer/src/methods/identify.ts index 188a92090..529a788fd 100644 --- a/packages/plugins/plugin-appsflyer/src/methods/identify.ts +++ b/packages/plugins/plugin-appsflyer/src/methods/identify.ts @@ -7,7 +7,7 @@ import { export default (event: IdentifyEventType) => { const userId = event.userId; if (userId !== undefined && userId !== null && userId.length > 0) { - appsFlyer.setCustomerUserId(userId); + void appsFlyer.setCustomerUserId({ customerId: userId }); } const traits = event.traits; @@ -33,10 +33,10 @@ export default (event: IdentifyEventType) => { if (traits.currencyCode !== undefined && traits.currencyCode !== null) { const codeString = unknownToString(traits.currencyCode); if (codeString !== undefined) { - appsFlyer.setCurrencyCode(codeString); + void appsFlyer.setCurrencyCode({ currencyCode: codeString }); } } - appsFlyer.setAdditionalData(aFTraits); + void appsFlyer.setAdditionalData({ customData: aFTraits }); } }; diff --git a/packages/plugins/plugin-appsflyer/src/methods/track.ts b/packages/plugins/plugin-appsflyer/src/methods/track.ts index 2dcb88d63..c84b2dde3 100644 --- a/packages/plugins/plugin-appsflyer/src/methods/track.ts +++ b/packages/plugins/plugin-appsflyer/src/methods/track.ts @@ -22,13 +22,19 @@ export default async (event: TrackEventType) => { return acc; }, {}); - await appsFlyer.logEvent(event.event, { - ...otherProperties, - af_revenue: revenue, - af_currency: currency, + await appsFlyer.logEvent({ + eventName: event.event, + eventValues: { + ...otherProperties, + af_revenue: revenue, + af_currency: currency, + }, }); } else { - await appsFlyer.logEvent(event.event, properties); + await appsFlyer.logEvent({ + eventName: event.event, + eventValues: properties, + }); } }; diff --git a/yarn.lock b/yarn.lock index 4f746e32b..828aecda0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -84,6 +84,13 @@ __metadata: languageName: node linkType: hard +"@appsflyer-sdk/js-core-plugin@npm:7.0.15": + version: 7.0.15 + resolution: "@appsflyer-sdk/js-core-plugin@npm:7.0.15" + checksum: 10c0/e4288ad809e1f18e00e91e2ba0365d90bf0f62bc1ba48fe665ca2e4b759342462f767ceab9defebf29d917b3d3822340aa30b82b8c86a81b2fe3b8de1c11415c + languageName: node + linkType: hard + "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.21.4, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.23.5": version: 7.23.5 resolution: "@babel/code-frame@npm:7.23.5" @@ -4322,14 +4329,14 @@ __metadata: "@segment/analytics-rn-shared": "workspace:^" "@segment/sovran-react-native": "npm:^1.1.0" jest: "npm:^29.7.0" - react-native-appsflyer: "npm:^6.9.4" + react-native-appsflyer: "npm:^7.0.2-0" react-native-builder-bob: "npm:^0.23.1" rimraf: "npm:^5.0.5" semantic-release: "npm:^22.0.8" typescript: "npm:^5.2.2" peerDependencies: "@segment/analytics-react-native": ^2.18.0 - react-native-appsflyer: ^6.9.4 + react-native-appsflyer: ^7.0.2-0 languageName: unknown linkType: soft @@ -15275,10 +15282,14 @@ __metadata: languageName: node linkType: hard -"react-native-appsflyer@npm:^6.9.4": - version: 6.12.2 - resolution: "react-native-appsflyer@npm:6.12.2" - checksum: 10c0/e8487481c00bbacefcb516fd17c5133b25382bdcdffd82b0b09a5765d67b1704e7604d8a9f95cc454c709b121bc167ae224bb93bce962b7bd0970f29f72b468e +"react-native-appsflyer@npm:^7.0.2-0": + version: 7.0.2 + resolution: "react-native-appsflyer@npm:7.0.2" + dependencies: + "@appsflyer-sdk/js-core-plugin": "npm:7.0.15" + peerDependencies: + react-native: ">=0.76.0" + checksum: 10c0/9ae15a7d17d3b18a313069090fa76791731fbcaa9870178861ba515ef6a8c713c9977f93ec17fbbe49eb670c75b1e2b08d329e6acf8d28dc715979175be8802c languageName: node linkType: hard