react-native-expo-moengage 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/LICENSE.txt +8 -0
  3. package/README.md +38 -0
  4. package/android/build.gradle +53 -0
  5. package/android/src/main/AndroidManifest.xml +6 -0
  6. package/android/src/main/java/expo/modules/moengage/MoEExpoFireBaseMessagingService.kt +56 -0
  7. package/android/src/main/java/expo/modules/moengage/MoEngageApplicationLifecycleListener.kt +31 -0
  8. package/android/src/main/java/expo/modules/moengage/MoEngagePackage.kt +12 -0
  9. package/android/src/main/java/expo/modules/moengage/internal/Constants.kt +4 -0
  10. package/android/user-agent.gradle +15 -0
  11. package/app.plugin.js +1 -0
  12. package/apple/ExpoAdapterMoEngage/MoEngageAppDelegate.swift +76 -0
  13. package/apple/ExpoAdapterMoEngage/MoEngageExpoPluginInfo.swift +5 -0
  14. package/apple/ExpoAdapterMoEngage.podspec +40 -0
  15. package/apple/PushTemplates/MainInterface.storyboard +29 -0
  16. package/apple/PushTemplates/MoEngageExpoPushTemplates-Info.plist +45 -0
  17. package/apple/PushTemplates/MoEngageExpoPushTemplates.entitlements +14 -0
  18. package/apple/PushTemplates/NotificationViewController.swift +14 -0
  19. package/apple/RichPush/MoEngageExpoRichPush-Info.plist +31 -0
  20. package/apple/RichPush/MoEngageExpoRichPush.entitlements +14 -0
  21. package/apple/RichPush/NotificationService.swift +20 -0
  22. package/build/android/constants.js +47 -0
  23. package/build/android/types.js +2 -0
  24. package/build/android/utils.js +80 -0
  25. package/build/android/withMoEngageAndroid.js +100 -0
  26. package/build/apple/constants.js +47 -0
  27. package/build/apple/index.js +72 -0
  28. package/build/apple/withDangerousMod.js +275 -0
  29. package/build/apple/withEntitlements.js +117 -0
  30. package/build/apple/withInfoPlist.js +91 -0
  31. package/build/apple/withXcodeProject.js +364 -0
  32. package/build/index.js +37 -0
  33. package/build/types.js +2 -0
  34. package/expo-module.config.json +18 -0
  35. package/package.json +69 -0
  36. package/src/android/constants.ts +52 -0
  37. package/src/android/types.ts +1 -0
  38. package/src/android/utils.ts +74 -0
  39. package/src/android/withMoEngageAndroid.ts +127 -0
  40. package/src/apple/constants.ts +48 -0
  41. package/src/apple/index.ts +38 -0
  42. package/src/apple/withDangerousMod.ts +265 -0
  43. package/src/apple/withEntitlements.ts +81 -0
  44. package/src/apple/withInfoPlist.ts +63 -0
  45. package/src/apple/withXcodeProject.ts +418 -0
  46. package/src/index.ts +52 -0
  47. package/src/types.ts +100 -0
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.addServiceToManifestIfNotExist = addServiceToManifestIfNotExist;
16
+ exports.isServiceExistInManifest = isServiceExistInManifest;
17
+ exports.addServiceToManifest = addServiceToManifest;
18
+ exports.copyFile = copyFile;
19
+ exports.addDependencyToGradle = addDependencyToGradle;
20
+ const node_fs_1 = __importDefault(require("node:fs"));
21
+ const node_path_1 = __importDefault(require("node:path"));
22
+ /**
23
+ * Add serviceEntry to the main application manifest if does not already exist.
24
+ */
25
+ function addServiceToManifestIfNotExist(mainApplication, serviceEntry, serviceName) {
26
+ console.log('Checking if service exists:', serviceName);
27
+ if (!isServiceExistInManifest(mainApplication, serviceName)) {
28
+ console.log('Adding service to manifest:', serviceName);
29
+ addServiceToManifest(mainApplication, serviceEntry);
30
+ }
31
+ return mainApplication;
32
+ }
33
+ /**
34
+ * Return true if given serviceName already exists in the main application manifest, else false.
35
+ */
36
+ function isServiceExistInManifest(mainApplication, serviceName) {
37
+ const isServiceExist = (mainApplication.service || []).find((service) => service.$ && service.$['android:name'] === serviceName);
38
+ console.log('Service exists:', serviceName, isServiceExist !== undefined);
39
+ return isServiceExist !== undefined;
40
+ }
41
+ /**
42
+ * Add serviceEntry to the main application manifest.
43
+ */
44
+ function addServiceToManifest(mainApplication, serviceEntry) {
45
+ console.log('Adding service entry:', serviceEntry);
46
+ if (!mainApplication.service) {
47
+ mainApplication.service = [];
48
+ }
49
+ mainApplication.service.push(serviceEntry);
50
+ }
51
+ /**
52
+ * Copy file from src to dest after creating dest directory if not exist
53
+ */
54
+ function copyFile(src, dest) {
55
+ return __awaiter(this, void 0, void 0, function* () {
56
+ let destPath = dest;
57
+ if (node_fs_1.default.existsSync(dest) && node_fs_1.default.statSync(dest).isDirectory()) {
58
+ destPath = node_path_1.default.join(dest, node_path_1.default.basename(src));
59
+ }
60
+ const destDir = node_path_1.default.dirname(destPath);
61
+ if (!node_fs_1.default.existsSync(destDir)) {
62
+ node_fs_1.default.mkdirSync(destDir, { recursive: true });
63
+ }
64
+ console.log('Copying file from', src, 'to', destPath);
65
+ node_fs_1.default.copyFileSync(src, destPath);
66
+ });
67
+ }
68
+ /**
69
+ * Add a dependency to the dependencies block in app/build.gradle if not already present.
70
+ */
71
+ function addDependencyToGradle(contents, group, module, version) {
72
+ const dependency = `implementation("${group}:${module}:${version}")`;
73
+ console.log('Checking for dependency:', group, module, version);
74
+ if (!contents.includes(`${group}:${module}`)) {
75
+ console.log('Adding dependency:', dependency);
76
+ return contents.replace(/dependencies\s*\{/, match => `${match}\n ${dependency}`);
77
+ }
78
+ console.log('Dependency already present:', dependency);
79
+ return contents;
80
+ }
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const config_plugins_1 = require("@expo/config-plugins");
13
+ const constants_1 = require("./constants");
14
+ const utils_1 = require("./utils");
15
+ const packageJsonFile = require('../../package.json');
16
+ const withMoEngageAndroid = (config, props) => {
17
+ console.log('Running withMoEngageAndroid');
18
+ config = withMoEngageAndroidManifest(config, props);
19
+ config = withMoEngageInitialisationConfigResource(config, props);
20
+ config = withMoEngageDependencies(config, props);
21
+ return config;
22
+ };
23
+ /**
24
+ * Update the AndroidManifest.xml file with MoEngage specific configurations.
25
+ */
26
+ const withMoEngageAndroidManifest = (config, props) => {
27
+ console.log('Running withMoEngageAndroidManifest');
28
+ if (!props.android.disableMoEngageDefaultBackupFile) {
29
+ (0, config_plugins_1.withAndroidManifest)(config, config => {
30
+ const mainApplication = config_plugins_1.AndroidConfig.Manifest.getMainApplicationOrThrow(config.modResults);
31
+ console.log('Adding manifest application keys');
32
+ constants_1.manifestApplicationKeys.forEach(item => {
33
+ const key = Object.keys(item)[0];
34
+ if (key !== undefined) {
35
+ const value = item[key];
36
+ if (!mainApplication.$) {
37
+ const androidName = mainApplication["android:name"] || "";
38
+ mainApplication.$ = { "android:name": androidName };
39
+ }
40
+ if (!(key in mainApplication.$)) {
41
+ mainApplication.$[key] = value;
42
+ }
43
+ }
44
+ });
45
+ return config;
46
+ });
47
+ }
48
+ if (props.android.shouldIncludeMoEngageFirebaseMessagingService) {
49
+ (0, config_plugins_1.withAndroidManifest)(config, config => {
50
+ const mainApplication = config_plugins_1.AndroidConfig.Manifest.getMainApplicationOrThrow(config.modResults);
51
+ if (props.android.isExpoNotificationIntegration) {
52
+ console.log('Adding Expo Notification Service to manifest');
53
+ (0, utils_1.addServiceToManifestIfNotExist)(mainApplication, constants_1.moEngageExpoNotificationServiceEntry, constants_1.moEngageExpoNotificationServiceName);
54
+ }
55
+ else {
56
+ console.log('Adding MoEngage FCM Service to manifest');
57
+ (0, utils_1.addServiceToManifestIfNotExist)(mainApplication, constants_1.moEngageFCMServiceEntry, constants_1.moEngageFCMServiceName);
58
+ }
59
+ return config;
60
+ });
61
+ }
62
+ return config;
63
+ };
64
+ /**
65
+ * Copy all the required resources for MoEngage initialisation to native Android module.
66
+ */
67
+ const withMoEngageInitialisationConfigResource = (config, props) => {
68
+ console.log('Running withMoEngageInitialisationConfigResource');
69
+ return (0, config_plugins_1.withDangerousMod)(config, [
70
+ 'android',
71
+ (config) => __awaiter(void 0, void 0, void 0, function* () {
72
+ if (props.android.smallIconPath !== undefined) {
73
+ console.log('Copying small icon:', props.android.smallIconPath);
74
+ yield (0, utils_1.copyFile)(props.android.smallIconPath, constants_1.drawableResourcePath);
75
+ }
76
+ if (props.android.largeIconPath !== undefined) {
77
+ console.log('Copying large icon:', props.android.largeIconPath);
78
+ yield (0, utils_1.copyFile)(props.android.largeIconPath, constants_1.drawableResourcePath);
79
+ }
80
+ console.log('Copying config file:', props.android.configFilePath);
81
+ yield (0, utils_1.copyFile)(props.android.configFilePath, constants_1.xmlValuesResourcePath);
82
+ return config;
83
+ }),
84
+ ]);
85
+ };
86
+ /**
87
+ * Add required dependencies to app/build.gradle
88
+ */
89
+ const withMoEngageDependencies = (config, props) => {
90
+ if (props.android.includeFirebaseMessagingDependencies) {
91
+ const firebaseMessagingVersion = packageJsonFile.dependencyVersions.firebaseMessaging;
92
+ console.log('Adding Firebase Messaging dependency:', firebaseMessagingVersion);
93
+ return (0, config_plugins_1.withAppBuildGradle)(config, gradleConfig => {
94
+ gradleConfig.modResults.contents = (0, utils_1.addDependencyToGradle)(gradleConfig.modResults.contents, constants_1.googleFirebaseMessagingGroup, constants_1.googleFirebaseMessagingModule, firebaseMessagingVersion);
95
+ return gradleConfig;
96
+ });
97
+ }
98
+ return config;
99
+ };
100
+ exports.default = withMoEngageAndroid;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ /**
3
+ * Constants used in the MoEngage iOS implementation
4
+ *
5
+ * This file contains all the constants needed for configuring the MoEngage SDK for iOS,
6
+ * including target names, file lists, and pod dependencies.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.MOENGAGE_IOS_LIVE_ACTIVITY_POD = exports.MOENGAGE_IOS_DEVICE_TRIGGER_POD = exports.MOENGAGE_IOS_PUSH_TEMPLATE_POD = exports.MOENGAGE_IOS_NOTIFICATION_SERVICE_POD = exports.MOENGAGE_IOS_PUSH_TEMPLATE_FILES = exports.MOENGAGE_IOS_RICH_PUSH_FILES = exports.MOENGAGE_IOS_LIVE_ACTIVITY_TARGET = exports.MOENGAGE_IOS_PUSH_TEMPLATE_TARGET = exports.MOENGAGE_IOS_RICH_PUSH_TARGET = void 0;
10
+ /**
11
+ * Target names for the extension targets in Xcode
12
+ * These names are used when creating extension targets in the Xcode project
13
+ * and must match the names used in entitlements and Info.plist files
14
+ */
15
+ exports.MOENGAGE_IOS_RICH_PUSH_TARGET = 'MoEngageExpoRichPush';
16
+ exports.MOENGAGE_IOS_PUSH_TEMPLATE_TARGET = 'MoEngageExpoPushTemplates';
17
+ exports.MOENGAGE_IOS_LIVE_ACTIVITY_TARGET = 'MoEngageExpoLiveActivity';
18
+ /**
19
+ * Files required for the Rich Push Notification Service Extension
20
+ * These files are copied from the plugin's resources to the Xcode project
21
+ * and added to the Rich Push target
22
+ */
23
+ exports.MOENGAGE_IOS_RICH_PUSH_FILES = [
24
+ 'NotificationService.swift',
25
+ `${exports.MOENGAGE_IOS_RICH_PUSH_TARGET}-Info.plist`,
26
+ `${exports.MOENGAGE_IOS_RICH_PUSH_TARGET}.entitlements`
27
+ ];
28
+ /**
29
+ * Files required for the Push Templates Notification Content Extension
30
+ * These files are copied from the plugin's resources to the Xcode project
31
+ * and added to the Push Templates target
32
+ */
33
+ exports.MOENGAGE_IOS_PUSH_TEMPLATE_FILES = [
34
+ 'MainInterface.storyboard',
35
+ 'NotificationViewController.swift',
36
+ `${exports.MOENGAGE_IOS_PUSH_TEMPLATE_TARGET}-Info.plist`,
37
+ `${exports.MOENGAGE_IOS_PUSH_TEMPLATE_TARGET}.entitlements`
38
+ ];
39
+ /**
40
+ * CocoaPods dependencies for each feature
41
+ * These pod specifications are added to the Podfile for each target
42
+ * that requires the functionality
43
+ */
44
+ exports.MOENGAGE_IOS_NOTIFICATION_SERVICE_POD = 'MoEngage-iOS-SDK/RichNotification'; // For Rich Push Notification Service Extension
45
+ exports.MOENGAGE_IOS_PUSH_TEMPLATE_POD = 'MoEngage-iOS-SDK/RichNotification'; // For Push Templates Notification Content Extension
46
+ exports.MOENGAGE_IOS_DEVICE_TRIGGER_POD = 'MoEngage-iOS-SDK/RealTimeTrigger'; // For Device-based campaign triggers
47
+ exports.MOENGAGE_IOS_LIVE_ACTIVITY_POD = 'MoEngage-iOS-SDK/LiveActivity'; // For LiveActivity support
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.withMoEngageDangerousMod = exports.withMoEngageXcodeProject = exports.withMoEngageEntitlements = exports.withMoEngageInfoPlist = exports.constants = exports.withMoEngageIos = void 0;
37
+ const withInfoPlist_1 = require("./withInfoPlist");
38
+ Object.defineProperty(exports, "withMoEngageInfoPlist", { enumerable: true, get: function () { return withInfoPlist_1.withMoEngageInfoPlist; } });
39
+ const withEntitlements_1 = require("./withEntitlements");
40
+ Object.defineProperty(exports, "withMoEngageEntitlements", { enumerable: true, get: function () { return withEntitlements_1.withMoEngageEntitlements; } });
41
+ const withXcodeProject_1 = require("./withXcodeProject");
42
+ Object.defineProperty(exports, "withMoEngageXcodeProject", { enumerable: true, get: function () { return withXcodeProject_1.withMoEngageXcodeProject; } });
43
+ const withDangerousMod_1 = require("./withDangerousMod");
44
+ Object.defineProperty(exports, "withMoEngageDangerousMod", { enumerable: true, get: function () { return withDangerousMod_1.withMoEngageDangerousMod; } });
45
+ const constants = __importStar(require("./constants"));
46
+ exports.constants = constants;
47
+ /**
48
+ * The main iOS plugin that applies all modifiers to set up MoEngage iOS integration
49
+ *
50
+ * This is the primary entry point for the MoEngage Expo plugin for iOS.
51
+ * It orchestrates the entire configuration process by applying each of the
52
+ * specialized modifiers in the correct order:
53
+ *
54
+ * 1. withMoEngageInfoPlist - Updates Info.plist with MoEngage configuration
55
+ * 2. withMoEngageEntitlements - Sets up app groups and other entitlements
56
+ * 3. withMoEngageXcodeProject - Configures the Xcode project with extension targets
57
+ * 4. withMoEngageDangerousMod - Performs file operations and updates Podfile
58
+ *
59
+ * @param config - The Expo config object
60
+ * @param props - The MoEngage plugin properties
61
+ * @returns The fully configured Expo config
62
+ */
63
+ const withMoEngageIos = (config, props) => {
64
+ config = (0, withInfoPlist_1.withMoEngageInfoPlist)(config, props);
65
+ config = (0, withEntitlements_1.withMoEngageEntitlements)(config, props);
66
+ config = (0, withXcodeProject_1.withMoEngageXcodeProject)(config, props);
67
+ config = (0, withDangerousMod_1.withMoEngageDangerousMod)(config, props);
68
+ return config;
69
+ };
70
+ exports.withMoEngageIos = withMoEngageIos;
71
+ // Default export
72
+ exports.default = exports.withMoEngageIos;
@@ -0,0 +1,275 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.withMoEngageDangerousMod = void 0;
37
+ const config_plugins_1 = require("@expo/config-plugins");
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const constants_1 = require("./constants");
41
+ const plist = require('plist');
42
+ /**
43
+ * MoEngage Expo plugin for iOS - Dangerous modifications
44
+ *
45
+ * This plugin handles file operations that are not directly exposed by the Expo Config Plugin API,
46
+ * including copying Rich Push, Push Templates, and LiveActivity files, and updating the Podfile
47
+ * to include the necessary MoEngage pods for each target.
48
+ *
49
+ * @param config - The Expo config object
50
+ * @param props - The MoEngage plugin properties
51
+ * @returns The updated config object
52
+ */
53
+ const withMoEngageDangerousMod = (config, props) => {
54
+ return (0, config_plugins_1.withDangerousMod)(config, [
55
+ 'ios',
56
+ (config) => {
57
+ var _a, _b, _c, _d, _e, _f, _g;
58
+ if (process.env['EXPO_TV']) {
59
+ // Skip modifications for tvOS
60
+ console.log(`Skipping extension targets copy for tvOS`);
61
+ return config;
62
+ }
63
+ const applicationPods = [];
64
+ const projectRoot = config.modRequest.projectRoot;
65
+ const { apple } = props;
66
+ const shouldAddRichPushExtension = apple.richPushNotificationEnabled || apple.pushNotificationImpressionTrackingEnabled || apple.pushTemplatesEnabled;
67
+ /**
68
+ * Extract the KeychainGroupName from the MoEngage configuration file
69
+ *
70
+ * The keychain group is needed for secure data sharing between the main app
71
+ * and extension targets. If present, it's added to the entitlements files
72
+ * for the extension targets.
73
+ */
74
+ let keychainGroupValue = '';
75
+ try {
76
+ const configFilePath = path.join(config.modRequest.projectRoot, props.apple.configFilePath);
77
+ if (fs.existsSync(configFilePath)) {
78
+ const configPlist = plist.parse(fs.readFileSync(configFilePath, 'utf8'));
79
+ keychainGroupValue = configPlist['KeychainGroupName'];
80
+ }
81
+ else {
82
+ const message = `MoEngage configuration does not exist`;
83
+ console.error(message);
84
+ throw new Error(message);
85
+ }
86
+ }
87
+ catch (e) {
88
+ const message = `Could not import MoEngage configuration: ${e}`;
89
+ console.error(message);
90
+ throw new Error(message);
91
+ }
92
+ /**
93
+ * Set up the Rich Push Notification Service Extension
94
+ *
95
+ * This extension handles rich push notifications with media attachments and
96
+ * custom notification UI. We:
97
+ * 1. Create the extension directory if it doesn't exist
98
+ * 2. Copy template files from the plugin's resources
99
+ * 3. Update entitlements with keychain access if configured
100
+ * 4. Modify the Podfile to include the MoEngage rich notification dependency
101
+ */
102
+ if (shouldAddRichPushExtension) {
103
+ // Copy Rich Push files to project path.
104
+ const absoluteSource = require.resolve('react-native-expo-moengage/apple/RichPush/NotificationService.swift');
105
+ const sourcePath = path.dirname(absoluteSource);
106
+ const destinationPath = `${projectRoot}/ios/${constants_1.MOENGAGE_IOS_RICH_PUSH_TARGET}`;
107
+ if (!fs.existsSync(`${destinationPath}`)) {
108
+ fs.mkdirSync(`${destinationPath}`, { recursive: true });
109
+ }
110
+ for (const file of constants_1.MOENGAGE_IOS_RICH_PUSH_FILES) {
111
+ // Copy keychain group to extension entitlements
112
+ if (keychainGroupValue && keychainGroupValue.length > 0 && file.endsWith('.entitlements')) {
113
+ const entitlements = plist.parse(fs.readFileSync(`${sourcePath}/${file}`, 'utf8'));
114
+ entitlements['keychain-access-groups'] = [keychainGroupValue];
115
+ fs.writeFileSync(`${destinationPath}/${file}`, plist.build(entitlements));
116
+ continue;
117
+ }
118
+ fs.copyFileSync(`${sourcePath}/${file}`, `${destinationPath}/${file}`);
119
+ }
120
+ // Modify Podfile to include `MoEngageRichNotification`.
121
+ const podfilePath = `${projectRoot}/ios/Podfile`;
122
+ if (fs.existsSync(podfilePath)) {
123
+ const podfile = fs.readFileSync(podfilePath, 'utf8');
124
+ if (!podfile.includes(constants_1.MOENGAGE_IOS_RICH_PUSH_TARGET) || !podfile.includes(constants_1.MOENGAGE_IOS_NOTIFICATION_SERVICE_POD)) {
125
+ const notificationServiceTarget = [
126
+ ``,
127
+ `target '${constants_1.MOENGAGE_IOS_RICH_PUSH_TARGET}' do`,
128
+ ` use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']`,
129
+ ` use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS']`,
130
+ ` pod '${constants_1.MOENGAGE_IOS_NOTIFICATION_SERVICE_POD}'`,
131
+ `end`
132
+ ].join('\n');
133
+ fs.appendFileSync(podfilePath, notificationServiceTarget);
134
+ }
135
+ }
136
+ }
137
+ /**
138
+ * Set up the Push Templates Notification Content Extension
139
+ *
140
+ * This extension enables custom notification UI templates for push notifications.
141
+ * The setup process includes:
142
+ * 1. Creating the extension directory if it doesn't exist
143
+ * 2. Copying template files from the plugin's resources
144
+ * 3. Updating entitlements with keychain access if configured
145
+ * 4. Modifying the Podfile to include the MoEngage push template dependency
146
+ */
147
+ if (apple.pushTemplatesEnabled) {
148
+ // Copy Push Template files to project path.
149
+ const absoluteSource = require.resolve('react-native-expo-moengage/apple/PushTemplates/NotificationViewController.swift');
150
+ const sourcePath = path.dirname(absoluteSource);
151
+ const destinationPath = `${projectRoot}/ios/${constants_1.MOENGAGE_IOS_PUSH_TEMPLATE_TARGET}`;
152
+ if (!fs.existsSync(`${destinationPath}`)) {
153
+ fs.mkdirSync(`${destinationPath}`, { recursive: true });
154
+ }
155
+ for (const file of constants_1.MOENGAGE_IOS_PUSH_TEMPLATE_FILES) {
156
+ // Copy keychain group to extension entitlements
157
+ if (keychainGroupValue && keychainGroupValue.length > 0 && file.endsWith('.entitlements')) {
158
+ const entitlements = plist.parse(fs.readFileSync(`${sourcePath}/${file}`, 'utf8'));
159
+ entitlements['keychain-access-groups'] = [keychainGroupValue];
160
+ fs.writeFileSync(`${destinationPath}/${file}`, plist.build(entitlements));
161
+ continue;
162
+ }
163
+ fs.copyFileSync(`${sourcePath}/${file}`, `${destinationPath}/${file}`);
164
+ }
165
+ // Modify Podfile to include `MoEngageRichNotification`.
166
+ const podfilePath = `${projectRoot}/ios/Podfile`;
167
+ if (fs.existsSync(podfilePath)) {
168
+ const podfile = fs.readFileSync(podfilePath, 'utf8');
169
+ if (!podfile.includes(constants_1.MOENGAGE_IOS_PUSH_TEMPLATE_TARGET) || !podfile.includes(constants_1.MOENGAGE_IOS_PUSH_TEMPLATE_POD)) {
170
+ const pushTemplateTarget = [
171
+ ``,
172
+ `target '${constants_1.MOENGAGE_IOS_PUSH_TEMPLATE_TARGET}' do`,
173
+ ` use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']`,
174
+ ` use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS']`,
175
+ ` pod '${constants_1.MOENGAGE_IOS_PUSH_TEMPLATE_POD}'`,
176
+ `end`
177
+ ].join('\n');
178
+ fs.appendFileSync(podfilePath, pushTemplateTarget);
179
+ }
180
+ }
181
+ }
182
+ /**
183
+ * Set up Live Activity support
184
+ *
185
+ * Live Activities allow apps to display persistent, interactive notifications
186
+ * on the lock screen and in the Dynamic Island on supported devices.
187
+ *
188
+ * This section:
189
+ * 1. Adds the MoEngageLiveActivity pod to the main app target
190
+ * 2. Creates a LiveActivity extension target in the Podfile if needed
191
+ * 3. Configures the pod dependencies for the LiveActivity extension
192
+ */
193
+ if (apple.liveActivityTargetPath && apple.liveActivityTargetPath.length) {
194
+ // Add MoEngageLiveActivity pod to the Podfile
195
+ applicationPods.push(` pod '${constants_1.MOENGAGE_IOS_LIVE_ACTIVITY_POD}'`);
196
+ const podfilePath = path.join(projectRoot, 'ios', 'Podfile');
197
+ if (fs.existsSync(podfilePath)) {
198
+ const podfile = fs.readFileSync(podfilePath, 'utf8');
199
+ if (!podfile.includes(constants_1.MOENGAGE_IOS_LIVE_ACTIVITY_TARGET)) {
200
+ const liveActivityTarget = [
201
+ ``,
202
+ `target '${constants_1.MOENGAGE_IOS_LIVE_ACTIVITY_TARGET}' do`,
203
+ ` use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']`,
204
+ ` use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS']`,
205
+ ` pod '${constants_1.MOENGAGE_IOS_LIVE_ACTIVITY_POD}'`,
206
+ `end`
207
+ ].join('\n');
208
+ fs.appendFileSync(podfilePath, liveActivityTarget);
209
+ console.log(`Added MoEngageLiveActivity pod to Podfile for ${constants_1.MOENGAGE_IOS_LIVE_ACTIVITY_TARGET} target`);
210
+ }
211
+ }
212
+ }
213
+ /**
214
+ * Set up Device Trigger support
215
+ *
216
+ * Device Triggers allow campaigns to be triggered based on device events,
217
+ * without requiring server communication. This is useful for real-time
218
+ * engagement based on user actions within the app.
219
+ *
220
+ * If enabled, we add the MoEngage RealTimeTrigger pod to the main application.
221
+ */
222
+ if (apple.deviceTriggerEnabled) {
223
+ applicationPods.push(` pod '${constants_1.MOENGAGE_IOS_DEVICE_TRIGGER_POD}'`);
224
+ }
225
+ /**
226
+ * Update the main application's Podfile with MoEngage dependencies
227
+ *
228
+ * This section adds any accumulated MoEngage pods to the main application target
229
+ * in the Podfile. It:
230
+ * 1. Finds the main application target section in the Podfile
231
+ * 2. Locates a suitable insertion point before existing dependencies
232
+ * 3. Inserts the MoEngage pod declarations
233
+ */
234
+ if (applicationPods && applicationPods.length) {
235
+ const podfilePath = `${projectRoot}/ios/Podfile`;
236
+ if (fs.existsSync(podfilePath)) {
237
+ const podfile = fs.readFileSync(podfilePath, 'utf8');
238
+ if (!podfile.includes(constants_1.MOENGAGE_IOS_DEVICE_TRIGGER_POD)) {
239
+ // Find the main target and add the pod there
240
+ const lines = podfile.split('\n');
241
+ let mainTargetIndex = -1;
242
+ // Find the main application target
243
+ for (let i = 0; i < lines.length; i++) {
244
+ if (((_a = lines[i]) === null || _a === void 0 ? void 0 : _a.includes('target')) && ((_b = lines[i]) === null || _b === void 0 ? void 0 : _b.includes('do')) &&
245
+ !((_c = lines[i]) === null || _c === void 0 ? void 0 : _c.includes(constants_1.MOENGAGE_IOS_RICH_PUSH_TARGET)) &&
246
+ !((_d = lines[i]) === null || _d === void 0 ? void 0 : _d.includes(constants_1.MOENGAGE_IOS_PUSH_TEMPLATE_TARGET))) {
247
+ mainTargetIndex = i;
248
+ break;
249
+ }
250
+ }
251
+ if (mainTargetIndex !== -1) {
252
+ // Find the end of the dependency section
253
+ let dependenciesEndIndex = -1;
254
+ for (let i = mainTargetIndex; i < lines.length; i++) {
255
+ if (((_e = lines[i]) === null || _e === void 0 ? void 0 : _e.includes('use_native_modules')) ||
256
+ ((_f = lines[i]) === null || _f === void 0 ? void 0 : _f.includes('use_react_native')) ||
257
+ ((_g = lines[i]) === null || _g === void 0 ? void 0 : _g.includes('post_install'))) {
258
+ dependenciesEndIndex = i;
259
+ break;
260
+ }
261
+ }
262
+ if (dependenciesEndIndex !== -1) {
263
+ // Insert the application pods before the end of the target
264
+ lines.splice(dependenciesEndIndex, 0, ...applicationPods);
265
+ fs.writeFileSync(podfilePath, lines.join('\n'));
266
+ }
267
+ }
268
+ }
269
+ }
270
+ }
271
+ return config;
272
+ },
273
+ ]);
274
+ };
275
+ exports.withMoEngageDangerousMod = withMoEngageDangerousMod;