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.
- package/CHANGELOG.md +5 -0
- package/LICENSE.txt +8 -0
- package/README.md +38 -0
- package/android/build.gradle +53 -0
- package/android/src/main/AndroidManifest.xml +6 -0
- package/android/src/main/java/expo/modules/moengage/MoEExpoFireBaseMessagingService.kt +56 -0
- package/android/src/main/java/expo/modules/moengage/MoEngageApplicationLifecycleListener.kt +31 -0
- package/android/src/main/java/expo/modules/moengage/MoEngagePackage.kt +12 -0
- package/android/src/main/java/expo/modules/moengage/internal/Constants.kt +4 -0
- package/android/user-agent.gradle +15 -0
- package/app.plugin.js +1 -0
- package/apple/ExpoAdapterMoEngage/MoEngageAppDelegate.swift +76 -0
- package/apple/ExpoAdapterMoEngage/MoEngageExpoPluginInfo.swift +5 -0
- package/apple/ExpoAdapterMoEngage.podspec +40 -0
- package/apple/PushTemplates/MainInterface.storyboard +29 -0
- package/apple/PushTemplates/MoEngageExpoPushTemplates-Info.plist +45 -0
- package/apple/PushTemplates/MoEngageExpoPushTemplates.entitlements +14 -0
- package/apple/PushTemplates/NotificationViewController.swift +14 -0
- package/apple/RichPush/MoEngageExpoRichPush-Info.plist +31 -0
- package/apple/RichPush/MoEngageExpoRichPush.entitlements +14 -0
- package/apple/RichPush/NotificationService.swift +20 -0
- package/build/android/constants.js +47 -0
- package/build/android/types.js +2 -0
- package/build/android/utils.js +80 -0
- package/build/android/withMoEngageAndroid.js +100 -0
- package/build/apple/constants.js +47 -0
- package/build/apple/index.js +72 -0
- package/build/apple/withDangerousMod.js +275 -0
- package/build/apple/withEntitlements.js +117 -0
- package/build/apple/withInfoPlist.js +91 -0
- package/build/apple/withXcodeProject.js +364 -0
- package/build/index.js +37 -0
- package/build/types.js +2 -0
- package/expo-module.config.json +18 -0
- package/package.json +69 -0
- package/src/android/constants.ts +52 -0
- package/src/android/types.ts +1 -0
- package/src/android/utils.ts +74 -0
- package/src/android/withMoEngageAndroid.ts +127 -0
- package/src/apple/constants.ts +48 -0
- package/src/apple/index.ts +38 -0
- package/src/apple/withDangerousMod.ts +265 -0
- package/src/apple/withEntitlements.ts +81 -0
- package/src/apple/withInfoPlist.ts +63 -0
- package/src/apple/withXcodeProject.ts +418 -0
- package/src/index.ts +52 -0
- 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;
|