react-native-expo-moengage
Version:
MoEngage Expo plugin for integrating MoEngage React-Native SDK
365 lines (364 loc) • 19.4 kB
JavaScript
;
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;
}