From 1a8f631315b0266059a0b68e3b2da2b464f82be2 Mon Sep 17 00:00:00 2001 From: Mahmoud Elmorabea Date: Mon, 10 Mar 2025 21:44:33 +0400 Subject: [PATCH 1/3] Prevent adding GoogleService-info.plist is not double copied --- .../ios/fcm/GoogleService-InfoCopied.test.js | 12 ++ plugin/src/ios/withGoogleServicesJsonFile.ts | 117 ++++++++++-------- 2 files changed, 79 insertions(+), 50 deletions(-) create mode 100644 __tests__/ios/fcm/GoogleService-InfoCopied.test.js diff --git a/__tests__/ios/fcm/GoogleService-InfoCopied.test.js b/__tests__/ios/fcm/GoogleService-InfoCopied.test.js new file mode 100644 index 00000000..82d21825 --- /dev/null +++ b/__tests__/ios/fcm/GoogleService-InfoCopied.test.js @@ -0,0 +1,12 @@ +const fs = require("fs-extra"); +const path = require("path"); + +const testProjectPath = path.join(__dirname, "../../../test-app"); +const iosPath = path.join(testProjectPath, "ios"); +const googleServicesFile = path.join(iosPath, "GoogleService-Info.plist"); + +test("Plugin injects expected customerio-reactnative/apn and customerio-reactnative-richpush/apn in Podfile", async () => { + const googleServicesFileExists = fs.existsSync(googleServicesFile); + + expect(googleServicesFileExists).toBe(true); +}); diff --git a/plugin/src/ios/withGoogleServicesJsonFile.ts b/plugin/src/ios/withGoogleServicesJsonFile.ts index 1576c358..0feb337b 100644 --- a/plugin/src/ios/withGoogleServicesJsonFile.ts +++ b/plugin/src/ios/withGoogleServicesJsonFile.ts @@ -1,68 +1,85 @@ -import { withXcodeProject, IOSConfig, ConfigPlugin } from '@expo/config-plugins'; +import { + withXcodeProject, + IOSConfig, + ConfigPlugin, +} from '@expo/config-plugins'; import { FileManagement } from './../helpers/utils/fileManagement'; import type { CustomerIOPluginOptionsIOS } from '../types/cio-types'; +import { isFcmPushProvider } from './utils'; -export const withGoogleServicesJsonFile: ConfigPlugin = ( - config, - cioProps -) => { +export const withGoogleServicesJsonFile: ConfigPlugin< + CustomerIOPluginOptionsIOS +> = (config, cioProps) => { return withXcodeProject(config, async (props) => { - - const pushProvider = cioProps.pushNotification?.provider ?? 'apn'; - const useFcm = pushProvider === 'fcm'; + const useFcm = isFcmPushProvider(cioProps); if (!useFcm) { - // Nothing to do, for providers other than FCM, the Google services JSON file isn't needed - return props; + // Nothing to do, for providers other than FCM, the Google services JSON file isn't needed + return props; } // googleServicesFile const iosPath = props.modRequest.platformProjectRoot; const googleServicesFile = cioProps.pushNotification?.googleServicesFile; - if (!FileManagement.exists(`${iosPath}/GoogleService-Info.plist`)) { - if (googleServicesFile && FileManagement.exists(googleServicesFile)) { - try { - FileManagement.copyFile( - googleServicesFile, - `${iosPath}/GoogleService-Info.plist` - ); + const appName = props.modRequest.projectName; - addFileToXcodeProject(props.modResults, "GoogleService-Info.plist"); - } catch (e) { - console.error( - `There was an error copying your GoogleService-Info.plist file. You can copy it manually into ${iosPath}/GoogleService-Info.plist` - ); - } - } else { - console.error( - `The Google Services file provided in ${googleServicesFile} doesn't seem to exist. You can copy it manually into ${iosPath}/GoogleService-Info.plist` - ); - } - } else { - console.log( - `File already exists: ${iosPath}/GoogleService-Info.plist. Skipping...` - ); - } - + if (FileManagement.exists(`${iosPath}/GoogleService-Info.plist`)) { + console.log( + `File already exists: ${iosPath}/GoogleService-Info.plist. Skipping...` + ); + return props; + } + + if ( + FileManagement.exists(`${iosPath}/${appName}/GoogleService-Info.plist`) + ) { + // This is where RN Firebase potentially copies GoogleService-Info.plist + // Do not copy if it's already done by Firebase to avoid conflict in Resources + console.log( + `File already exists: ${iosPath}/${appName}/GoogleService-Info.plist. Skipping...` + ); + return props; + } + + if (googleServicesFile && FileManagement.exists(googleServicesFile)) { + try { + FileManagement.copyFile( + googleServicesFile, + `${iosPath}/GoogleService-Info.plist` + ); + + addFileToXcodeProject(props.modResults, 'GoogleService-Info.plist'); + } catch (e) { + console.error( + `There was an error copying your GoogleService-Info.plist file. You can copy it manually into ${iosPath}/GoogleService-Info.plist` + ); + } + } else { + console.error( + `The Google Services file provided in ${googleServicesFile} doesn't seem to exist. You can copy it manually into ${iosPath}/GoogleService-Info.plist` + ); + } return props; }); }; function addFileToXcodeProject(project: any, fileName: string) { - const groupName = "Resources"; - const filepath = fileName; - - if (!IOSConfig.XcodeUtils.ensureGroupRecursively(project, groupName)) { - console.error(`Error copying GoogleService-Info.plist. Failed to find or create '${groupName}' group in Xcode.`); - return; - } - - // Add GoogleService-Info.plist to the Xcode project - IOSConfig.XcodeUtils.addResourceFileToGroup({ - project, - filepath, - groupName, - isBuildFile: true, - }); - } \ No newline at end of file + const groupName = 'Resources'; + const filepath = fileName; + + if (!IOSConfig.XcodeUtils.ensureGroupRecursively(project, groupName)) { + console.error( + `Error copying GoogleService-Info.plist. Failed to find or create '${groupName}' group in Xcode.` + ); + return; + } + + // Add GoogleService-Info.plist to the Xcode project + IOSConfig.XcodeUtils.addResourceFileToGroup({ + project, + filepath, + groupName, + isBuildFile: true, + }); +} From 74e492c5f29ca048122453f5c3f2b9e849bb4210 Mon Sep 17 00:00:00 2001 From: Mahmoud Elmorabea Date: Wed, 12 Mar 2025 18:20:08 +0400 Subject: [PATCH 2/3] Add info and warning messages to help customers detect Firebase conflict --- plugin/src/ios/withGoogleServicesJsonFile.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/plugin/src/ios/withGoogleServicesJsonFile.ts b/plugin/src/ios/withGoogleServicesJsonFile.ts index 0feb337b..3409e85e 100644 --- a/plugin/src/ios/withGoogleServicesJsonFile.ts +++ b/plugin/src/ios/withGoogleServicesJsonFile.ts @@ -18,6 +18,11 @@ export const withGoogleServicesJsonFile: ConfigPlugin< return props; } + console.log( + 'Only specify Customer IO ios.pushNotification.googleServicesFile config if you are not already including' + + ' GoogleService-Info.plist as part of Firebase integration' + ); + // googleServicesFile const iosPath = props.modRequest.platformProjectRoot; const googleServicesFile = cioProps.pushNotification?.googleServicesFile; @@ -42,6 +47,13 @@ export const withGoogleServicesJsonFile: ConfigPlugin< } if (googleServicesFile && FileManagement.exists(googleServicesFile)) { + if (config.ios?.googleServicesFile) { + console.warn( + 'Specifying both Expo ios.googleServicesFile and Customer IO ios.pushNotification.googleServicesFile can cause a conflict' + + ' duplicating GoogleService-Info.plist in the iOS project resources. Please remove Customer IO ios.pushNotification.googleServicesFile' + ); + } + try { FileManagement.copyFile( googleServicesFile, From 52bd88ca15e40da80adf3d0ff2bdb2baffd07eaa Mon Sep 17 00:00:00 2001 From: Mahmoud Elmorabea Date: Thu, 13 Mar 2025 12:57:11 +0400 Subject: [PATCH 3/3] Review comments --- __tests__/ios/fcm/GoogleService-InfoCopied.test.js | 2 +- plugin/src/ios/withGoogleServicesJsonFile.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/__tests__/ios/fcm/GoogleService-InfoCopied.test.js b/__tests__/ios/fcm/GoogleService-InfoCopied.test.js index 82d21825..748b5980 100644 --- a/__tests__/ios/fcm/GoogleService-InfoCopied.test.js +++ b/__tests__/ios/fcm/GoogleService-InfoCopied.test.js @@ -5,7 +5,7 @@ const testProjectPath = path.join(__dirname, "../../../test-app"); const iosPath = path.join(testProjectPath, "ios"); const googleServicesFile = path.join(iosPath, "GoogleService-Info.plist"); -test("Plugin injects expected customerio-reactnative/apn and customerio-reactnative-richpush/apn in Podfile", async () => { +test("GoogleService-Info.plist is copied at the expected location in the iOS project", async () => { const googleServicesFileExists = fs.existsSync(googleServicesFile); expect(googleServicesFileExists).toBe(true); diff --git a/plugin/src/ios/withGoogleServicesJsonFile.ts b/plugin/src/ios/withGoogleServicesJsonFile.ts index 3409e85e..92b3f493 100644 --- a/plugin/src/ios/withGoogleServicesJsonFile.ts +++ b/plugin/src/ios/withGoogleServicesJsonFile.ts @@ -19,7 +19,7 @@ export const withGoogleServicesJsonFile: ConfigPlugin< } console.log( - 'Only specify Customer IO ios.pushNotification.googleServicesFile config if you are not already including' + + 'Only specify Customer.io ios.pushNotification.googleServicesFile config if you are not already including' + ' GoogleService-Info.plist as part of Firebase integration' ); @@ -49,8 +49,8 @@ export const withGoogleServicesJsonFile: ConfigPlugin< if (googleServicesFile && FileManagement.exists(googleServicesFile)) { if (config.ios?.googleServicesFile) { console.warn( - 'Specifying both Expo ios.googleServicesFile and Customer IO ios.pushNotification.googleServicesFile can cause a conflict' + - ' duplicating GoogleService-Info.plist in the iOS project resources. Please remove Customer IO ios.pushNotification.googleServicesFile' + 'Specifying both Expo ios.googleServicesFile and Customer.io ios.pushNotification.googleServicesFile can cause a conflict' + + ' duplicating GoogleService-Info.plist in the iOS project resources. Please remove Customer.io ios.pushNotification.googleServicesFile' ); }