UNPKG

react-native-expo-moengage

Version:

MoEngage Expo plugin for integrating MoEngage React-Native SDK

365 lines (364 loc) 19.4 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.withMoEngageXcodeProject = void 0; exports.withLiveActivity = withLiveActivity; const config_plugins_1 = require("@expo/config-plugins"); const fs = __importStar(require("fs")); const path = __importStar(require("path")); const constants_1 = require("./constants"); const plist = require('plist'); /** * MoEngage Expo plugin for iOS - Xcode project modifications * * This plugin configures the Xcode project to include MoEngage extensions for rich notifications, * push templates, and LiveActivity. It reads configuration from the MoEngage plist file and sets up * the necessary targets, PBX groups, and build phases. * * @param config - The Expo config object * @param props - The MoEngage plugin properties * @returns The updated config object with Xcode project modifications */ const withMoEngageXcodeProject = (config, props) => { return (0, config_plugins_1.withXcodeProject)(config, (config) => { var _a, _b; if (process.env['EXPO_TV']) { // Skip modifications for tvOS console.log(`Skipping extension targets setup for tvOS`); return config; } const { apple } = props; const shouldAddRichPushExtension = apple.richPushNotificationEnabled || apple.pushNotificationImpressionTrackingEnabled || apple.pushTemplatesEnabled; // Get app group from plist file if specified let appGroupValue = ''; try { const configFilePath = path.join(config.modRequest.projectRoot, props.apple.configFilePath); if (fs.existsSync(configFilePath)) { const configPlist = plist.parse(fs.readFileSync(configFilePath, 'utf8')); appGroupValue = configPlist['AppGroupName']; if (!appGroupValue) { const message = `Missing AppGroupName key in MoEngage configuration`; console.error(message); throw new Error(message); } } else { const message = `MoEngage configuration does not exist`; console.error(message); throw new Error(message); } } catch (e) { const message = `Could not import MoEngage configuration: ${e}`; console.error(message); throw new Error(message); } // Initialize with an empty object if these top-level objects are non-existent. // This guarantees that the extension targets will have a destination. const objects = config.modResults.hash.project.objects; objects['PBXTargetDependency'] = objects['PBXTargetDependency'] || {}; objects['PBXContainerItemProxy'] = objects['PBXContainerItemProxy'] || {}; const groups = objects['PBXGroup']; const xcconfigs = objects['XCBuildConfiguration']; // Retrieve Swift version and code signing settings from main target to apply to dependency targets. let swiftVersion; let codeSignStyle; let codeSignIdentity; let otherCodeSigningFlags; let developmentTeam; let provisioningProfile; for (const configUUID of Object.keys(xcconfigs)) { const buildSettings = xcconfigs[configUUID].buildSettings; if (!swiftVersion && buildSettings && buildSettings.SWIFT_VERSION) { swiftVersion = buildSettings.SWIFT_VERSION; codeSignStyle = buildSettings.CODE_SIGN_STYLE; codeSignIdentity = buildSettings.CODE_SIGN_IDENTITY; otherCodeSigningFlags = buildSettings.OTHER_CODE_SIGN_FLAGS; developmentTeam = buildSettings.DEVELOPMENT_TEAM; provisioningProfile = buildSettings.PROVISIONING_PROFILE_SPECIFIER; break; } } // Rich Push Notification Service Extension if (shouldAddRichPushExtension && !config.modResults.pbxGroupByName(constants_1.MOENGAGE_IOS_RICH_PUSH_TARGET)) { // Add the Notification Service Extension target. const richPushTarget = config.modResults.addTarget(constants_1.MOENGAGE_IOS_RICH_PUSH_TARGET, 'app_extension', constants_1.MOENGAGE_IOS_RICH_PUSH_TARGET, `${(_a = config.ios) === null || _a === void 0 ? void 0 : _a.bundleIdentifier}.${constants_1.MOENGAGE_IOS_RICH_PUSH_TARGET}`); // Add the relevant files to the PBX group. const moengageNotificationServiceGroup = config.modResults.addPbxGroup(constants_1.MOENGAGE_IOS_RICH_PUSH_FILES, constants_1.MOENGAGE_IOS_RICH_PUSH_TARGET, constants_1.MOENGAGE_IOS_RICH_PUSH_TARGET); for (const groupUUID of Object.keys(groups)) { if (typeof groups[groupUUID] === 'object' && groups[groupUUID].name === undefined && groups[groupUUID].path === undefined) { config.modResults.addToPbxGroup(moengageNotificationServiceGroup.uuid, groupUUID); } } ; for (const configUUID of Object.keys(xcconfigs)) { const buildSettings = xcconfigs[configUUID].buildSettings; if (buildSettings && buildSettings.PRODUCT_NAME === `"${constants_1.MOENGAGE_IOS_RICH_PUSH_TARGET}"`) { buildSettings.MOENGAGE_APP_GROUP = appGroupValue; buildSettings.SWIFT_VERSION = swiftVersion; buildSettings.CODE_SIGN_ENTITLEMENTS = `${constants_1.MOENGAGE_IOS_RICH_PUSH_TARGET}/${constants_1.MOENGAGE_IOS_RICH_PUSH_TARGET}.entitlements`; if (codeSignStyle) { buildSettings.CODE_SIGN_STYLE = codeSignStyle; } if (codeSignIdentity) { buildSettings.CODE_SIGN_IDENTITY = codeSignIdentity; } if (otherCodeSigningFlags) { buildSettings.OTHER_CODE_SIGN_FLAGS = otherCodeSigningFlags; } if (developmentTeam) { buildSettings.DEVELOPMENT_TEAM = developmentTeam; } if (provisioningProfile) { buildSettings.PROVISIONING_PROFILE_SPECIFIER = provisioningProfile; } } } // Set up target build phase scripts. config.modResults.addBuildPhase([ 'NotificationService.swift', ], 'PBXSourcesBuildPhase', 'Sources', richPushTarget.uuid); config.modResults.addBuildPhase(['UserNotifications.framework'], 'PBXFrameworksBuildPhase', 'Frameworks', richPushTarget.uuid); } // Push Templates Notification Content Extension if (apple.pushTemplatesEnabled && !config.modResults.pbxGroupByName(constants_1.MOENGAGE_IOS_PUSH_TEMPLATE_TARGET)) { // Add the Notification Content Extension target. const pushTemplateTarget = config.modResults.addTarget(constants_1.MOENGAGE_IOS_PUSH_TEMPLATE_TARGET, 'app_extension', constants_1.MOENGAGE_IOS_PUSH_TEMPLATE_TARGET, `${(_b = config.ios) === null || _b === void 0 ? void 0 : _b.bundleIdentifier}.${constants_1.MOENGAGE_IOS_PUSH_TEMPLATE_TARGET}`); // Add the relevant files to the PBX group. const moengageNotificationContentGroup = config.modResults.addPbxGroup(constants_1.MOENGAGE_IOS_PUSH_TEMPLATE_FILES, constants_1.MOENGAGE_IOS_PUSH_TEMPLATE_TARGET, constants_1.MOENGAGE_IOS_PUSH_TEMPLATE_TARGET); for (const groupUUID of Object.keys(groups)) { if (typeof groups[groupUUID] === 'object' && groups[groupUUID].name === undefined && groups[groupUUID].path === undefined) { config.modResults.addToPbxGroup(moengageNotificationContentGroup.uuid, groupUUID); } } ; for (const configUUID of Object.keys(xcconfigs)) { const buildSettings = xcconfigs[configUUID].buildSettings; if (buildSettings && buildSettings.PRODUCT_NAME === `"${constants_1.MOENGAGE_IOS_PUSH_TEMPLATE_TARGET}"`) { buildSettings.MOENGAGE_APP_GROUP = appGroupValue; buildSettings.SWIFT_VERSION = swiftVersion; buildSettings.CODE_SIGN_ENTITLEMENTS = `${constants_1.MOENGAGE_IOS_PUSH_TEMPLATE_TARGET}/${constants_1.MOENGAGE_IOS_PUSH_TEMPLATE_TARGET}.entitlements`; if (codeSignStyle) { buildSettings.CODE_SIGN_STYLE = codeSignStyle; } if (codeSignIdentity) { buildSettings.CODE_SIGN_IDENTITY = codeSignIdentity; } if (otherCodeSigningFlags) { buildSettings.OTHER_CODE_SIGN_FLAGS = otherCodeSigningFlags; } if (developmentTeam) { buildSettings.DEVELOPMENT_TEAM = developmentTeam; } if (provisioningProfile) { buildSettings.PROVISIONING_PROFILE_SPECIFIER = provisioningProfile; } } } // Set up target build phase scripts. config.modResults.addBuildPhase([ 'NotificationViewController.swift', ], 'PBXSourcesBuildPhase', 'Sources', pushTemplateTarget.uuid); config.modResults.addBuildPhase([ 'MainInterface.storyboard', ], 'PBXResourcesBuildPhase', 'Resources', pushTemplateTarget.uuid); config.modResults.addBuildPhase([ 'UserNotifications.framework', 'UserNotificationsUI.framework' ], 'PBXFrameworksBuildPhase', 'Frameworks', pushTemplateTarget.uuid); } // Handle Live Activity configuration if targetPath is provided if (apple.liveActivityTargetPath && apple.liveActivityTargetPath.length && !config.modResults.pbxGroupByName(constants_1.MOENGAGE_IOS_LIVE_ACTIVITY_TARGET)) { config = withLiveActivity(config, apple.liveActivityTargetPath, { swiftVersion, codeSignStyle, codeSignIdentity, otherCodeSigningFlags, developmentTeam, provisioningProfile }); } return config; }); }; exports.withMoEngageXcodeProject = withMoEngageXcodeProject; /** * Adds Live Activity extension target to the Xcode project * * This function configures a LiveActivity extension by: * 1. Creating the target and PBX groups * 2. Scanning the provided directory for source files, resources, and configuration files * 3. Adding all files to appropriate build phases * 4. Setting up build settings including code signing and entitlements * * @param config - Expo config with Xcode project * @param liveActivityTargetPath - Path to the LiveActivity source files * @param codeSignSettings - Code signing settings to apply to the target * @returns The updated config object */ function withLiveActivity(config, liveActivityTargetPath, codeSignSettings) { var _a; const liveActivityPath = path.join(config.modRequest.projectRoot, liveActivityTargetPath); const objects = config.modResults.hash.project.objects; const xcconfigs = objects['XCBuildConfiguration']; const groups = objects['PBXGroup']; // Add the Live Activity target const liveActivityTarget = config.modResults.addTarget(constants_1.MOENGAGE_IOS_LIVE_ACTIVITY_TARGET, 'app_extension', constants_1.MOENGAGE_IOS_LIVE_ACTIVITY_TARGET, `${(_a = config.ios) === null || _a === void 0 ? void 0 : _a.bundleIdentifier}.${constants_1.MOENGAGE_IOS_LIVE_ACTIVITY_TARGET}`); // Add the relevant files to the PBX group. const moengageLiveActivityPathContentGroup = config.modResults.addPbxGroup([], constants_1.MOENGAGE_IOS_LIVE_ACTIVITY_TARGET, liveActivityPath); for (const groupUUID of Object.keys(groups)) { if (typeof groups[groupUUID] === 'object' && groups[groupUUID].name === undefined && groups[groupUUID].path === undefined) { config.modResults.addToPbxGroup(moengageLiveActivityPathContentGroup.uuid, groupUUID); } } ; // Find all .xcassets files, source files, header files, // info plist file and entitlements file in liveActivityTargetPath let entitlementsFile = ''; let infoPlistFile = ''; let resourcesFiles = []; let sourceFiles = []; let headerFiles = []; try { const findFilesRecursively = (directory, group) => { let items = fs.readdirSync(directory, { withFileTypes: true }); for (const item of items) { const itemPath = path.join(directory, item.name); const ext = path.extname(item.name).toLowerCase(); if (item.isDirectory()) { if (['.xcassets'].includes(ext)) { resourcesFiles.push(itemPath); console.log(`Found ${itemPath} as resource for LiveActivity`); } else { // Recursively read directories const group = config.modResults.addPbxGroup([], item.name, itemPath); config.modResults.addToPbxGroup(group.uuid, moengageLiveActivityPathContentGroup.uuid); findFilesRecursively(itemPath, group); continue; } } else if (['.swift', '.m', '.c', '.cpp'].includes(ext)) { sourceFiles.push(itemPath); console.log(`Found ${itemPath} as source file for LiveActivity`); } else if (['.h'].includes(ext)) { headerFiles.push(itemPath); console.log(`Found ${itemPath} as header file for LiveActivity`); } else if (['.entitlements'].includes(ext)) { entitlementsFile = itemPath; console.log(`Found ${itemPath} as entitlements file for LiveActivity`); } else if (item.name === 'Info.plist' || item.name === `${constants_1.MOENGAGE_IOS_LIVE_ACTIVITY_TARGET}-Info.plist` || item.name === `${path.basename(path.dirname(liveActivityTargetPath !== null && liveActivityTargetPath !== void 0 ? liveActivityTargetPath : ''))}-Info.plist`) { infoPlistFile = itemPath; console.log(`Found ${itemPath} as Info.plist file for LiveActivity`); } else { resourcesFiles.push(itemPath); console.log(`Found ${itemPath} as resource for LiveActivity`); } // Add file to project config.modResults.addFile(itemPath, group.uuid); } }; // Find all files findFilesRecursively(liveActivityPath, moengageLiveActivityPathContentGroup); } catch (e) { const message = `Error finding files in Live Activity path: ${e}`; console.error(message); throw new Error(message); } // Set up build settings for the Live Activity target for (const configUUID of Object.keys(xcconfigs)) { const buildSettings = xcconfigs[configUUID].buildSettings; if (buildSettings && buildSettings.PRODUCT_NAME === `"${constants_1.MOENGAGE_IOS_LIVE_ACTIVITY_TARGET}"`) { buildSettings.SWIFT_VERSION = codeSignSettings.swiftVersion; buildSettings.IPHONEOS_DEPLOYMENT_TARGET = '18.0'; // Set minimum iOS version for Live Activity // Add entitlements file if found if (entitlementsFile && entitlementsFile.length) { buildSettings.CODE_SIGN_ENTITLEMENTS = `${entitlementsFile}`; } // Add Info.plist file if found if (infoPlistFile && infoPlistFile.length) { buildSettings.INFOPLIST_FILE = `${infoPlistFile}`; } // Copy code signing settings from main target if (codeSignSettings.codeSignStyle) { buildSettings.CODE_SIGN_STYLE = codeSignSettings.codeSignStyle; } if (codeSignSettings.codeSignIdentity) { buildSettings.CODE_SIGN_IDENTITY = codeSignSettings.codeSignIdentity; } if (codeSignSettings.otherCodeSigningFlags) { buildSettings.OTHER_CODE_SIGN_FLAGS = codeSignSettings.otherCodeSigningFlags; } if (codeSignSettings.developmentTeam) { buildSettings.DEVELOPMENT_TEAM = codeSignSettings.developmentTeam; } if (codeSignSettings.provisioningProfile) { buildSettings.PROVISIONING_PROFILE_SPECIFIER = codeSignSettings.provisioningProfile; } } } // Add resources (xcassets) to the target if (resourcesFiles.length) { config.modResults.addBuildPhase(resourcesFiles, 'PBXResourcesBuildPhase', 'Resources', liveActivityTarget.uuid); } // Add source files to the target if (sourceFiles.length) { config.modResults.addBuildPhase(sourceFiles, 'PBXSourcesBuildPhase', 'Sources', liveActivityTarget.uuid); } // Add header files to the target if (headerFiles.length) { config.modResults.addBuildPhase(headerFiles, 'PBXHeadersBuildPhase', 'Headers', liveActivityTarget.uuid); } // Add required frameworks for Live Activity config.modResults.addBuildPhase([ 'SwiftUI.framework', 'WidgetKit.framework', 'ActivityKit.framework' ], 'PBXFrameworksBuildPhase', 'Frameworks', liveActivityTarget.uuid); return config; }