diff --git a/docs/analytics/usage/index.mdx b/docs/analytics/usage/index.mdx index 157ee8e199..14fd76f11e 100644 --- a/docs/analytics/usage/index.mdx +++ b/docs/analytics/usage/index.mdx @@ -171,6 +171,31 @@ of your app handle data in a way that requires ATT) Note that for obvious reasons, configuring Firebase Analytics for use without IDFA is incompatible with AdMob +# Google Analytics on-device conversion measurement + +If you would like to enable Google Analytics on-device conversion measurement APIs on iOS, define the following variable in your Podfile: + +```ruby +$RNFirebaseAnalyticsGoogleAppMeasurementOnDeviceConversion = true +``` + +During `pod install`, using that variable adds the `GoogleAdsOnDeviceConversion` Pod. + +If you use Expo, including EAS Build, add the Analytics config plugin to your `app.json` / `app.config.js` instead of editing the generated Podfile manually: + +```json +[ + "@react-native-firebase/analytics", + { + "ios": { + "googleAppMeasurementOnDeviceConversion": true + } + } +] +``` + +This adds `$RNFirebaseAnalyticsGoogleAppMeasurementOnDeviceConversion = true` to the generated iOS `Podfile` during prebuild. + # Device Identification If you would like to enable Firebase Analytics to generate automatic audience metrics for iOS (as it does by default in Android), you must link additional iOS libraries, [as documented by the Google Firebase team](https://support.google.com/firebase/answer/6318039). Specifically you need to link in `AdSupport.framework`. diff --git a/docs/index.mdx b/docs/index.mdx index 55f47aa079..2b791c1715 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -78,20 +78,21 @@ The following is an example `app.json` to enable the React Native Firebase modul > Listing a module in the Config Plugins (the `"plugins"` array in the JSON above) is only required for React Native Firebase modules that involve _native installation steps_ - e.g. modifying the Xcode project, `Podfile`, `build.gradle`, `AndroidManifest.xml` etc. React Native Firebase modules without native steps will work out of the box; no `"plugins"` entry is required. Not all modules have Expo Config Plugins provided yet. A React Native Firebase module has Config Plugin support if it contains an `app.plugin.js` file in its package directory (e.g.`node_modules/@react-native-firebase/app/app.plugin.js`). -If you use `@react-native-firebase/analytics` with Expo, including EAS Build, and want to opt out of iOS Ad ID support, add the Analytics config plugin with the `withoutAdIdSupport` iOS option: +If you use `@react-native-firebase/analytics` with Expo, including EAS Build, and want to configure iOS Analytics Podfile flags, add the Analytics config plugin with the relevant iOS options: ```json [ "@react-native-firebase/analytics", { "ios": { - "withoutAdIdSupport": true + "withoutAdIdSupport": true, + "googleAppMeasurementOnDeviceConversion": true } } ] ``` -This adds `$RNFirebaseAnalyticsWithoutAdIdSupport = true` to the generated iOS `Podfile` during prebuild. +The `withoutAdIdSupport` option adds `$RNFirebaseAnalyticsWithoutAdIdSupport = true` to opt out of iOS Ad ID support. The `googleAppMeasurementOnDeviceConversion` option adds `$RNFirebaseAnalyticsGoogleAppMeasurementOnDeviceConversion = true` to include Google Analytics on-device conversion measurement support. You may omit either option if it is not needed. ### Local app compilation diff --git a/packages/analytics/README.md b/packages/analytics/README.md index d9db2dd6e9..ee9e49cab8 100644 --- a/packages/analytics/README.md +++ b/packages/analytics/README.md @@ -40,7 +40,7 @@ yarn add @react-native-firebase/analytics ### Expo -If you use Expo, including EAS Build, and want to build iOS Analytics without Ad ID support, add the Analytics config plugin to your `app.json` / `app.config.js`: +If you use Expo, including EAS Build, and want to configure iOS Analytics Podfile flags, add the Analytics config plugin to your `app.json` / `app.config.js`: ```json { @@ -50,7 +50,8 @@ If you use Expo, including EAS Build, and want to build iOS Analytics without Ad "@react-native-firebase/analytics", { "ios": { - "withoutAdIdSupport": true + "withoutAdIdSupport": true, + "googleAppMeasurementOnDeviceConversion": true } } ] @@ -59,7 +60,7 @@ If you use Expo, including EAS Build, and want to build iOS Analytics without Ad } ``` -This adds `$RNFirebaseAnalyticsWithoutAdIdSupport = true` to the generated iOS `Podfile` during prebuild, which excludes `FirebaseAnalytics/IdentitySupport`. +The `withoutAdIdSupport` option adds `$RNFirebaseAnalyticsWithoutAdIdSupport = true` during prebuild, which excludes `FirebaseAnalytics/IdentitySupport`. The `googleAppMeasurementOnDeviceConversion` option adds `$RNFirebaseAnalyticsGoogleAppMeasurementOnDeviceConversion = true`, which includes Google Analytics on-device conversion measurement support. You may omit either option if it is not needed. ## Documentation diff --git a/packages/analytics/plugin/__tests__/__snapshots__/iosPlugin.test.ts.snap b/packages/analytics/plugin/__tests__/__snapshots__/iosPlugin.test.ts.snap index 8e0ea488f8..2affb5c3d2 100644 --- a/packages/analytics/plugin/__tests__/__snapshots__/iosPlugin.test.ts.snap +++ b/packages/analytics/plugin/__tests__/__snapshots__/iosPlugin.test.ts.snap @@ -1,5 +1,34 @@ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing +exports[`Analytics Config Plugin iOS Tests adds both iOS Podfile flags when both analytics options are enabled 1`] = ` +"platform :ios, '15.0' + +prepare_react_native_project! +# @generated begin @react-native-firebase/analytics-googleAppMeasurementOnDeviceConversion - expo prebuild (DO NOT MODIFY) sync-6d1952a1f7b9ccb2d313cbd66659db4cdeae591f +$RNFirebaseAnalyticsGoogleAppMeasurementOnDeviceConversion = true +# @generated end @react-native-firebase/analytics-googleAppMeasurementOnDeviceConversion +# @generated begin @react-native-firebase/analytics-withoutAdIdSupport - expo prebuild (DO NOT MODIFY) sync-06c0e725ab83bc834a9294f76fea47cf14bb6ac3 +$RNFirebaseAnalyticsWithoutAdIdSupport = true +# @generated end @react-native-firebase/analytics-withoutAdIdSupport + +target 'ReactNativeFirebaseDemo' do +end +" +`; + +exports[`Analytics Config Plugin iOS Tests adds the Podfile flag when googleAppMeasurementOnDeviceConversion is enabled 1`] = ` +"platform :ios, '15.0' + +prepare_react_native_project! +# @generated begin @react-native-firebase/analytics-googleAppMeasurementOnDeviceConversion - expo prebuild (DO NOT MODIFY) sync-6d1952a1f7b9ccb2d313cbd66659db4cdeae591f +$RNFirebaseAnalyticsGoogleAppMeasurementOnDeviceConversion = true +# @generated end @react-native-firebase/analytics-googleAppMeasurementOnDeviceConversion + +target 'ReactNativeFirebaseDemo' do +end +" +`; + exports[`Analytics Config Plugin iOS Tests adds the Podfile flag when withoutAdIdSupport is enabled 1`] = ` "platform :ios, '15.0' diff --git a/packages/analytics/plugin/__tests__/iosPlugin.test.ts b/packages/analytics/plugin/__tests__/iosPlugin.test.ts index a2014345dc..71c89c32ac 100644 --- a/packages/analytics/plugin/__tests__/iosPlugin.test.ts +++ b/packages/analytics/plugin/__tests__/iosPlugin.test.ts @@ -1,6 +1,9 @@ import { describe, expect, it } from '@jest/globals'; -import { setAnalyticsPodfileWithoutAdIdSupport } from '../src/ios/podfile'; +import { + setAnalyticsPodfileGoogleAppMeasurementOnDeviceConversion, + setAnalyticsPodfileWithoutAdIdSupport, +} from '../src/ios/podfile'; const podfileFixture = `platform :ios, '15.0' @@ -29,4 +32,42 @@ describe('Analytics Config Plugin iOS Tests', function () { expect(restored).toEqual(podfileFixture); }); + + it('adds the Podfile flag when googleAppMeasurementOnDeviceConversion is enabled', function () { + const result = setAnalyticsPodfileGoogleAppMeasurementOnDeviceConversion(podfileFixture, true); + expect(result).toMatchSnapshot(); + }); + + it('is idempotent when the ODM Podfile flag is already present', function () { + const onceModified = setAnalyticsPodfileGoogleAppMeasurementOnDeviceConversion( + podfileFixture, + true, + ); + const twiceModified = setAnalyticsPodfileGoogleAppMeasurementOnDeviceConversion( + onceModified, + true, + ); + + expect(twiceModified).toEqual(onceModified); + }); + + it('removes the generated Podfile flag when googleAppMeasurementOnDeviceConversion is disabled', function () { + const onceModified = setAnalyticsPodfileGoogleAppMeasurementOnDeviceConversion( + podfileFixture, + true, + ); + const restored = setAnalyticsPodfileGoogleAppMeasurementOnDeviceConversion(onceModified, false); + + expect(restored).toEqual(podfileFixture); + }); + + it('adds both iOS Podfile flags when both analytics options are enabled', function () { + const withWithoutAdIdSupport = setAnalyticsPodfileWithoutAdIdSupport(podfileFixture, true); + const result = setAnalyticsPodfileGoogleAppMeasurementOnDeviceConversion( + withWithoutAdIdSupport, + true, + ); + + expect(result).toMatchSnapshot(); + }); }); diff --git a/packages/analytics/plugin/src/index.ts b/packages/analytics/plugin/src/index.ts index fb2cd5e10a..66ae941ee4 100644 --- a/packages/analytics/plugin/src/index.ts +++ b/packages/analytics/plugin/src/index.ts @@ -1,6 +1,6 @@ import { ConfigPlugin, withPlugins, createRunOncePlugin } from '@expo/config-plugins'; -import { withIosWithoutAdIdSupport } from './ios'; +import { withIosWithoutAdIdSupport, withIosGoogleAppMeasurementOnDeviceConversion } from './ios'; import { PluginConfigType } from './pluginConfig'; /** @@ -10,6 +10,7 @@ const withRnFirebaseAnalytics: ConfigPlugin = (config, props) return withPlugins(config, [ // iOS [withIosWithoutAdIdSupport, props], + [withIosGoogleAppMeasurementOnDeviceConversion, props], ]); }; diff --git a/packages/analytics/plugin/src/ios/index.ts b/packages/analytics/plugin/src/ios/index.ts index b63d644c3b..e642d277ac 100644 --- a/packages/analytics/plugin/src/ios/index.ts +++ b/packages/analytics/plugin/src/ios/index.ts @@ -1,3 +1,3 @@ -import { withIosWithoutAdIdSupport } from './podfile'; +import { withIosWithoutAdIdSupport, withIosGoogleAppMeasurementOnDeviceConversion } from './podfile'; -export { withIosWithoutAdIdSupport }; +export { withIosWithoutAdIdSupport, withIosGoogleAppMeasurementOnDeviceConversion }; diff --git a/packages/analytics/plugin/src/ios/podfile.ts b/packages/analytics/plugin/src/ios/podfile.ts index 0d3e2f4cbf..23c30196e4 100644 --- a/packages/analytics/plugin/src/ios/podfile.ts +++ b/packages/analytics/plugin/src/ios/podfile.ts @@ -9,25 +9,57 @@ import { PluginConfigType } from '../pluginConfig'; const TAG = '@react-native-firebase/analytics-withoutAdIdSupport'; const ANCHOR = /prepare_react_native_project!/; const FLAG = '$RNFirebaseAnalyticsWithoutAdIdSupport = true'; +const TAG_ODM = '@react-native-firebase/analytics-googleAppMeasurementOnDeviceConversion'; +const FLAG_ODM = '$RNFirebaseAnalyticsGoogleAppMeasurementOnDeviceConversion = true'; -export function setAnalyticsPodfileWithoutAdIdSupport( +function setAnalyticsPodfileFlag( src: string, + tag: string, + flag: string, enabled: boolean = false, ): string { if (!enabled) { - return removeGeneratedContents(src, TAG) ?? src; + return removeGeneratedContents(src, tag) ?? src; } return mergeContents({ src, - newSrc: FLAG, - tag: TAG, + newSrc: flag, + tag, anchor: ANCHOR, offset: 1, comment: '#', }).contents; } +export function setAnalyticsPodfileWithoutAdIdSupport( + src: string, + enabled: boolean = false, +): string { + return setAnalyticsPodfileFlag(src, TAG, FLAG, enabled); +} + +export function setAnalyticsPodfileGoogleAppMeasurementOnDeviceConversion( + src: string, + enabled: boolean = false, +): string { + return setAnalyticsPodfileFlag(src, TAG_ODM, FLAG_ODM, enabled); +} + +export const withIosGoogleAppMeasurementOnDeviceConversion: ConfigPlugin = ( + config, + props, +) => { + return withPodfile(config, config => { + config.modResults.contents = setAnalyticsPodfileGoogleAppMeasurementOnDeviceConversion( + config.modResults.contents, + props?.ios?.googleAppMeasurementOnDeviceConversion === true, + ); + + return config; + }); +}; + export const withIosWithoutAdIdSupport: ConfigPlugin = (config, props) => { return withPodfile(config, config => { config.modResults.contents = setAnalyticsPodfileWithoutAdIdSupport( diff --git a/packages/analytics/plugin/src/pluginConfig.ts b/packages/analytics/plugin/src/pluginConfig.ts index 29aa84c79a..b8856086f3 100644 --- a/packages/analytics/plugin/src/pluginConfig.ts +++ b/packages/analytics/plugin/src/pluginConfig.ts @@ -4,4 +4,8 @@ export interface PluginConfigType { export interface PluginConfigTypeIos { withoutAdIdSupport?: boolean; + /** + * @platform ios iOS + */ + googleAppMeasurementOnDeviceConversion?: boolean; }