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,81 @@
1
+ import { ConfigPlugin, withEntitlementsPlist } from "@expo/config-plugins";
2
+ import { MoEngagePluginProps } from "../types";
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+
6
+ const plist = require('plist');
7
+
8
+ /**
9
+ * MoEngage Expo plugin for iOS - Entitlements modifications
10
+ *
11
+ * This plugin configures the app's entitlements file to enable MoEngage features by:
12
+ * 1. Reading the AppGroupName from the MoEngage configuration file
13
+ * 2. Adding app groups to entitlements for push notifications and extensions
14
+ * 3. Setting up keychain sharing if configured
15
+ * 4. Adding any other required entitlements for MoEngage features
16
+ *
17
+ * @param config - The Expo config object
18
+ * @param props - The MoEngage plugin properties
19
+ * @returns The updated config with modified entitlements
20
+ */
21
+ export const withMoEngageEntitlements: ConfigPlugin<MoEngagePluginProps> = (config, props) => {
22
+ return withEntitlementsPlist(config, (config) => {
23
+ // Import configuration from plist file if specified
24
+ try {
25
+ const configFilePath = path.join(config.modRequest.projectRoot, props.apple.configFilePath);
26
+ if (fs.existsSync(configFilePath)) {
27
+ const configPlist = plist.parse(fs.readFileSync(configFilePath, 'utf8')) as { [key: string]: any };
28
+
29
+ // Add the app group to the main application target's entitlements if rich push or push templates are enabled
30
+ const appGroupsKey = 'com.apple.security.application-groups';
31
+ const appGroupValue = configPlist['AppGroupName'] as string;
32
+ if (props.apple.pushTemplatesEnabled || props.apple.richPushNotificationEnabled || props.apple.pushNotificationImpressionTrackingEnabled) {
33
+ if (appGroupValue && appGroupValue.length > 0) {
34
+ const existingAppGroups = config.modResults[appGroupsKey];
35
+ if (Array.isArray(existingAppGroups)) {
36
+ if (!existingAppGroups.includes(appGroupValue)) {
37
+ config.modResults[appGroupsKey] = existingAppGroups.concat([appGroupValue]);
38
+ }
39
+ } else {
40
+ config.modResults[appGroupsKey] = [appGroupValue];
41
+ }
42
+ } else {
43
+ const message = `Missing AppGroupName key in MoEngage configuration`;
44
+ console.error(message);
45
+ throw new Error(message);
46
+ }
47
+ }
48
+
49
+ // Add the keychain access groups to the main application target's entitlements if specified
50
+ const keychainGroupsKey = 'keychain-access-groups';
51
+ const keychainGroupValue = configPlist['KeychainGroupName'] as string;
52
+ const isStorageEncryptionEnabled = configPlist['IsStorageEncryptionEnabled'] as boolean;
53
+ if (isStorageEncryptionEnabled && (!keychainGroupValue || keychainGroupValue.length == 0)) {
54
+ const message = `KeychainGroupName in "${configFilePath}" is required when IsStorageEncryptionEnabled is true`;
55
+ console.error(message);
56
+ throw new Error(message);
57
+ }
58
+
59
+ if (keychainGroupValue && keychainGroupValue.length > 0) {
60
+ const existingKeychainGroups = config.modResults[keychainGroupsKey];
61
+ if (Array.isArray(existingKeychainGroups)) {
62
+ if (!existingKeychainGroups.includes(keychainGroupValue)) {
63
+ config.modResults[keychainGroupsKey] = existingKeychainGroups.concat([keychainGroupValue]);
64
+ }
65
+ } else {
66
+ config.modResults[keychainGroupsKey] = [keychainGroupValue];
67
+ }
68
+ }
69
+ } else {
70
+ const message = `MoEngage configuration does not exist`;
71
+ console.error(message);
72
+ throw new Error(message);
73
+ }
74
+ } catch (e) {
75
+ const message = `Could not import MoEngage configuration: ${e}`;
76
+ console.error(message);
77
+ throw new Error(message);
78
+ }
79
+ return config;
80
+ });
81
+ };
@@ -0,0 +1,63 @@
1
+ import { ConfigPlugin, withInfoPlist } from "@expo/config-plugins";
2
+ import { MoEngagePluginProps } from "../types";
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+
6
+ const plist = require('plist');
7
+
8
+ /**
9
+ * MoEngage Expo plugin for iOS - Info.plist modifications
10
+ *
11
+ * This plugin configures the Info.plist file with MoEngage settings, including:
12
+ * 1. Importing configuration from the MoEngage plist file
13
+ * 2. Setting up notification service extensions
14
+ * 3. Configuring required app settings for MoEngage SDK
15
+ *
16
+ * @param config - The Expo config object
17
+ * @param props - The MoEngage plugin properties
18
+ * @returns The updated config with Info.plist modifications
19
+ */
20
+ export const withMoEngageInfoPlist: ConfigPlugin<MoEngagePluginProps> = (config, props) => {
21
+ return withInfoPlist(config, (config) => {
22
+ const { apple } = props;
23
+
24
+ // Initialize MoEngage configuration in Info.plist
25
+ config.modResults['MoEngage'] = config.modResults['MoEngage'] || {};
26
+
27
+ // Import configuration from plist file if specified
28
+ try {
29
+ const configFilePath = path.join(config.modRequest.projectRoot, apple.configFilePath);
30
+ if (fs.existsSync(configFilePath)) {
31
+ const configPlist = plist.parse(fs.readFileSync(configFilePath, 'utf8'));
32
+
33
+ // Merge the configuration from the plist file with existing MoEngage settings
34
+ config.modResults['MoEngage'] = {
35
+ ...config.modResults['MoEngage'] as { [key: string]: any },
36
+ ...configPlist
37
+ };
38
+ } else {
39
+ const message = `MoEngage configuration does not exist`;
40
+ console.error(message);
41
+ throw new Error(message);
42
+ }
43
+ } catch (e) {
44
+ const message = `Could not import MoEngage configuration: ${e}`;
45
+ console.error(message);
46
+ throw new Error(message);
47
+ }
48
+
49
+ /**
50
+ * Set up Live Activities support in the Info.plist if enabled
51
+ *
52
+ * This adds the NSSupportsLiveActivities key to Info.plist, which is required
53
+ * for the app to support Live Activities on iOS. We only enable this if:
54
+ * 1. The app is not a tvOS app (Live Activities aren't supported on tvOS)
55
+ * 2. A Live Activity target path has been specified in the plugin configuration
56
+ */
57
+ if (!process.env['EXPO_TV'] && apple.liveActivityTargetPath && apple.liveActivityTargetPath.length) {
58
+ config.modResults['NSSupportsLiveActivities'] = true;
59
+ }
60
+
61
+ return config;
62
+ });
63
+ };
@@ -0,0 +1,418 @@
1
+ import { ConfigPlugin, ExportedConfigWithProps, XcodeProject, withXcodeProject } from "@expo/config-plugins";
2
+ import { MoEngagePluginProps } from "../types";
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+ import {
6
+ MOENGAGE_IOS_RICH_PUSH_TARGET,
7
+ MOENGAGE_IOS_PUSH_TEMPLATE_TARGET,
8
+ MOENGAGE_IOS_LIVE_ACTIVITY_TARGET,
9
+ MOENGAGE_IOS_RICH_PUSH_FILES,
10
+ MOENGAGE_IOS_PUSH_TEMPLATE_FILES
11
+ } from './constants';
12
+
13
+ const plist = require('plist');
14
+
15
+ /**
16
+ * MoEngage Expo plugin for iOS - Xcode project modifications
17
+ *
18
+ * This plugin configures the Xcode project to include MoEngage extensions for rich notifications,
19
+ * push templates, and LiveActivity. It reads configuration from the MoEngage plist file and sets up
20
+ * the necessary targets, PBX groups, and build phases.
21
+ *
22
+ * @param config - The Expo config object
23
+ * @param props - The MoEngage plugin properties
24
+ * @returns The updated config object with Xcode project modifications
25
+ */
26
+ export const withMoEngageXcodeProject: ConfigPlugin<MoEngagePluginProps> = (config, props) => {
27
+ return withXcodeProject(config, (config) => {
28
+ if (process.env['EXPO_TV']) {
29
+ // Skip modifications for tvOS
30
+ console.log(`Skipping extension targets setup for tvOS`);
31
+ return config;
32
+ }
33
+
34
+ const { apple } = props;
35
+ const shouldAddRichPushExtension = apple.richPushNotificationEnabled || apple.pushNotificationImpressionTrackingEnabled || apple.pushTemplatesEnabled;
36
+
37
+ // Get app group from plist file if specified
38
+ let appGroupValue = ''
39
+ try {
40
+ const configFilePath = path.join(config.modRequest.projectRoot, props.apple.configFilePath);
41
+ if (fs.existsSync(configFilePath)) {
42
+ const configPlist = plist.parse(fs.readFileSync(configFilePath, 'utf8')) as { [key: string]: any };
43
+ appGroupValue = configPlist['AppGroupName'] as string;
44
+
45
+ if (!appGroupValue) {
46
+ const message = `Missing AppGroupName key in MoEngage configuration`;
47
+ console.error(message);
48
+ throw new Error(message);
49
+ }
50
+ } else {
51
+ const message = `MoEngage configuration does not exist`;
52
+ console.error(message);
53
+ throw new Error(message);
54
+ }
55
+ } catch (e) {
56
+ const message = `Could not import MoEngage configuration: ${e}`;
57
+ console.error(message);
58
+ throw new Error(message);
59
+ }
60
+
61
+ // Initialize with an empty object if these top-level objects are non-existent.
62
+ // This guarantees that the extension targets will have a destination.
63
+ const objects = config.modResults.hash.project.objects;
64
+ objects['PBXTargetDependency'] = objects['PBXTargetDependency'] || {};
65
+ objects['PBXContainerItemProxy'] = objects['PBXContainerItemProxy'] || {};
66
+
67
+ const groups = objects['PBXGroup'];
68
+ const xcconfigs = objects['XCBuildConfiguration'];
69
+
70
+ // Retrieve Swift version and code signing settings from main target to apply to dependency targets.
71
+ let swiftVersion;
72
+ let codeSignStyle;
73
+ let codeSignIdentity;
74
+ let otherCodeSigningFlags;
75
+ let developmentTeam;
76
+ let provisioningProfile;
77
+ for (const configUUID of Object.keys(xcconfigs)) {
78
+ const buildSettings = xcconfigs[configUUID].buildSettings;
79
+ if (!swiftVersion && buildSettings && buildSettings.SWIFT_VERSION) {
80
+ swiftVersion = buildSettings.SWIFT_VERSION;
81
+ codeSignStyle = buildSettings.CODE_SIGN_STYLE;
82
+ codeSignIdentity = buildSettings.CODE_SIGN_IDENTITY;
83
+ otherCodeSigningFlags = buildSettings.OTHER_CODE_SIGN_FLAGS;
84
+ developmentTeam = buildSettings.DEVELOPMENT_TEAM;
85
+ provisioningProfile = buildSettings.PROVISIONING_PROFILE_SPECIFIER;
86
+ break;
87
+ }
88
+ }
89
+
90
+ // Rich Push Notification Service Extension
91
+ if (shouldAddRichPushExtension && !config.modResults.pbxGroupByName(MOENGAGE_IOS_RICH_PUSH_TARGET)) {
92
+ // Add the Notification Service Extension target.
93
+ const richPushTarget = config.modResults.addTarget(
94
+ MOENGAGE_IOS_RICH_PUSH_TARGET,
95
+ 'app_extension',
96
+ MOENGAGE_IOS_RICH_PUSH_TARGET,
97
+ `${config.ios?.bundleIdentifier}.${MOENGAGE_IOS_RICH_PUSH_TARGET}`,
98
+ );
99
+
100
+ // Add the relevant files to the PBX group.
101
+ const moengageNotificationServiceGroup = config.modResults.addPbxGroup(
102
+ MOENGAGE_IOS_RICH_PUSH_FILES,
103
+ MOENGAGE_IOS_RICH_PUSH_TARGET,
104
+ MOENGAGE_IOS_RICH_PUSH_TARGET,
105
+ );
106
+
107
+ for (const groupUUID of Object.keys(groups)) {
108
+ if (typeof groups[groupUUID] === 'object'
109
+ && groups[groupUUID].name === undefined
110
+ && groups[groupUUID].path === undefined) {
111
+ config.modResults.addToPbxGroup(moengageNotificationServiceGroup.uuid, groupUUID);
112
+ }
113
+ };
114
+
115
+ for (const configUUID of Object.keys(xcconfigs)) {
116
+ const buildSettings = xcconfigs[configUUID].buildSettings;
117
+ if (buildSettings && buildSettings.PRODUCT_NAME === `"${MOENGAGE_IOS_RICH_PUSH_TARGET}"`) {
118
+ buildSettings.MOENGAGE_APP_GROUP = appGroupValue;
119
+ buildSettings.SWIFT_VERSION = swiftVersion;
120
+ buildSettings.CODE_SIGN_ENTITLEMENTS = `${MOENGAGE_IOS_RICH_PUSH_TARGET}/${MOENGAGE_IOS_RICH_PUSH_TARGET}.entitlements`;
121
+ if (codeSignStyle) { buildSettings.CODE_SIGN_STYLE = codeSignStyle; }
122
+ if (codeSignIdentity) { buildSettings.CODE_SIGN_IDENTITY = codeSignIdentity; }
123
+ if (otherCodeSigningFlags) { buildSettings.OTHER_CODE_SIGN_FLAGS = otherCodeSigningFlags; }
124
+ if (developmentTeam) { buildSettings.DEVELOPMENT_TEAM = developmentTeam; }
125
+ if (provisioningProfile) { buildSettings.PROVISIONING_PROFILE_SPECIFIER = provisioningProfile; }
126
+ }
127
+ }
128
+
129
+ // Set up target build phase scripts.
130
+ config.modResults.addBuildPhase(
131
+ [
132
+ 'NotificationService.swift',
133
+ ],
134
+ 'PBXSourcesBuildPhase',
135
+ 'Sources',
136
+ richPushTarget.uuid
137
+ );
138
+
139
+ config.modResults.addBuildPhase(
140
+ ['UserNotifications.framework'],
141
+ 'PBXFrameworksBuildPhase',
142
+ 'Frameworks',
143
+ richPushTarget.uuid
144
+ );
145
+ }
146
+
147
+ // Push Templates Notification Content Extension
148
+ if (apple.pushTemplatesEnabled && !config.modResults.pbxGroupByName(MOENGAGE_IOS_PUSH_TEMPLATE_TARGET)) {
149
+ // Add the Notification Content Extension target.
150
+ const pushTemplateTarget = config.modResults.addTarget(
151
+ MOENGAGE_IOS_PUSH_TEMPLATE_TARGET,
152
+ 'app_extension',
153
+ MOENGAGE_IOS_PUSH_TEMPLATE_TARGET,
154
+ `${config.ios?.bundleIdentifier}.${MOENGAGE_IOS_PUSH_TEMPLATE_TARGET}`,
155
+ );
156
+
157
+ // Add the relevant files to the PBX group.
158
+ const moengageNotificationContentGroup = config.modResults.addPbxGroup(
159
+ MOENGAGE_IOS_PUSH_TEMPLATE_FILES,
160
+ MOENGAGE_IOS_PUSH_TEMPLATE_TARGET,
161
+ MOENGAGE_IOS_PUSH_TEMPLATE_TARGET,
162
+ );
163
+
164
+ for (const groupUUID of Object.keys(groups)) {
165
+ if (typeof groups[groupUUID] === 'object'
166
+ && groups[groupUUID].name === undefined
167
+ && groups[groupUUID].path === undefined) {
168
+ config.modResults.addToPbxGroup(moengageNotificationContentGroup.uuid, groupUUID);
169
+ }
170
+ };
171
+
172
+ for (const configUUID of Object.keys(xcconfigs)) {
173
+ const buildSettings = xcconfigs[configUUID].buildSettings;
174
+ if (buildSettings && buildSettings.PRODUCT_NAME === `"${MOENGAGE_IOS_PUSH_TEMPLATE_TARGET}"`) {
175
+ buildSettings.MOENGAGE_APP_GROUP = appGroupValue;
176
+ buildSettings.SWIFT_VERSION = swiftVersion;
177
+ buildSettings.CODE_SIGN_ENTITLEMENTS = `${MOENGAGE_IOS_PUSH_TEMPLATE_TARGET}/${MOENGAGE_IOS_PUSH_TEMPLATE_TARGET}.entitlements`;
178
+ if (codeSignStyle) { buildSettings.CODE_SIGN_STYLE = codeSignStyle; }
179
+ if (codeSignIdentity) { buildSettings.CODE_SIGN_IDENTITY = codeSignIdentity; }
180
+ if (otherCodeSigningFlags) { buildSettings.OTHER_CODE_SIGN_FLAGS = otherCodeSigningFlags; }
181
+ if (developmentTeam) { buildSettings.DEVELOPMENT_TEAM = developmentTeam; }
182
+ if (provisioningProfile) { buildSettings.PROVISIONING_PROFILE_SPECIFIER = provisioningProfile; }
183
+ }
184
+ }
185
+
186
+ // Set up target build phase scripts.
187
+ config.modResults.addBuildPhase(
188
+ [
189
+ 'NotificationViewController.swift',
190
+ ],
191
+ 'PBXSourcesBuildPhase',
192
+ 'Sources',
193
+ pushTemplateTarget.uuid
194
+ );
195
+
196
+ config.modResults.addBuildPhase(
197
+ [
198
+ 'MainInterface.storyboard',
199
+ ],
200
+ 'PBXResourcesBuildPhase',
201
+ 'Resources',
202
+ pushTemplateTarget.uuid
203
+ );
204
+
205
+ config.modResults.addBuildPhase(
206
+ [
207
+ 'UserNotifications.framework',
208
+ 'UserNotificationsUI.framework'
209
+ ],
210
+ 'PBXFrameworksBuildPhase',
211
+ 'Frameworks',
212
+ pushTemplateTarget.uuid
213
+ );
214
+ }
215
+
216
+ // Handle Live Activity configuration if targetPath is provided
217
+ if (apple.liveActivityTargetPath && apple.liveActivityTargetPath.length && !config.modResults.pbxGroupByName(MOENGAGE_IOS_LIVE_ACTIVITY_TARGET)) {
218
+ config = withLiveActivity(config, apple.liveActivityTargetPath, {
219
+ swiftVersion,
220
+ codeSignStyle,
221
+ codeSignIdentity,
222
+ otherCodeSigningFlags,
223
+ developmentTeam,
224
+ provisioningProfile
225
+ });
226
+ }
227
+
228
+ return config;
229
+ });
230
+ };
231
+
232
+ /**
233
+ * Interface for code signing settings
234
+ * These settings are extracted from the main target and applied to extension targets
235
+ * to ensure consistent code signing across all targets in the project
236
+ */
237
+ interface CodeSignSettings {
238
+ /** Swift version used in the project (e.g. '5.0') */
239
+ swiftVersion?: string;
240
+ /** Code signing style ('Automatic' or 'Manual') */
241
+ codeSignStyle?: string;
242
+ /** Code signing identity (e.g. 'Apple Developer') */
243
+ codeSignIdentity?: string;
244
+ /** Additional code signing flags */
245
+ otherCodeSigningFlags?: string;
246
+ /** Development team identifier */
247
+ developmentTeam?: string;
248
+ /** Provisioning profile specifier */
249
+ provisioningProfile?: string;
250
+ }
251
+
252
+ /**
253
+ * Adds Live Activity extension target to the Xcode project
254
+ *
255
+ * This function configures a LiveActivity extension by:
256
+ * 1. Creating the target and PBX groups
257
+ * 2. Scanning the provided directory for source files, resources, and configuration files
258
+ * 3. Adding all files to appropriate build phases
259
+ * 4. Setting up build settings including code signing and entitlements
260
+ *
261
+ * @param config - Expo config with Xcode project
262
+ * @param liveActivityTargetPath - Path to the LiveActivity source files
263
+ * @param codeSignSettings - Code signing settings to apply to the target
264
+ * @returns The updated config object
265
+ */
266
+ export function withLiveActivity(config: ExportedConfigWithProps<XcodeProject>, liveActivityTargetPath: string, codeSignSettings: CodeSignSettings) {
267
+ const liveActivityPath = path.join(config.modRequest.projectRoot, liveActivityTargetPath);
268
+ const objects = config.modResults.hash.project.objects;
269
+ const xcconfigs = objects['XCBuildConfiguration'];
270
+ const groups = objects['PBXGroup'];
271
+
272
+ // Add the Live Activity target
273
+ const liveActivityTarget = config.modResults.addTarget(
274
+ MOENGAGE_IOS_LIVE_ACTIVITY_TARGET,
275
+ 'app_extension',
276
+ MOENGAGE_IOS_LIVE_ACTIVITY_TARGET,
277
+ `${config.ios?.bundleIdentifier}.${MOENGAGE_IOS_LIVE_ACTIVITY_TARGET}`,
278
+ );
279
+
280
+ // Add the relevant files to the PBX group.
281
+ const moengageLiveActivityPathContentGroup = config.modResults.addPbxGroup(
282
+ [], MOENGAGE_IOS_LIVE_ACTIVITY_TARGET, liveActivityPath,
283
+ );
284
+
285
+ for (const groupUUID of Object.keys(groups)) {
286
+ if (typeof groups[groupUUID] === 'object'
287
+ && groups[groupUUID].name === undefined
288
+ && groups[groupUUID].path === undefined) {
289
+ config.modResults.addToPbxGroup(moengageLiveActivityPathContentGroup.uuid, groupUUID);
290
+ }
291
+ };
292
+
293
+ // Find all .xcassets files, source files, header files,
294
+ // info plist file and entitlements file in liveActivityTargetPath
295
+ let entitlementsFile = '';
296
+ let infoPlistFile = '';
297
+ let resourcesFiles: string[] = [];
298
+ let sourceFiles: string[] = [];
299
+ let headerFiles: string[] = [];
300
+
301
+ try {
302
+ const findFilesRecursively = (directory: string, group: any) => {
303
+ let items = fs.readdirSync(directory, { withFileTypes: true });
304
+ for (const item of items) {
305
+ const itemPath = path.join(directory, item.name);
306
+ const ext = path.extname(item.name).toLowerCase();
307
+ if (item.isDirectory()) {
308
+ if (['.xcassets'].includes(ext)) {
309
+ resourcesFiles.push(itemPath);
310
+ console.log(`Found ${itemPath} as resource for LiveActivity`);
311
+ } else {
312
+ // Recursively read directories
313
+ const group = config.modResults.addPbxGroup([], item.name, itemPath);
314
+ config.modResults.addToPbxGroup(group.uuid, moengageLiveActivityPathContentGroup.uuid);
315
+ findFilesRecursively(itemPath, group);
316
+ continue;
317
+ }
318
+ } else if (['.swift', '.m', '.c', '.cpp'].includes(ext)) {
319
+ sourceFiles.push(itemPath);
320
+ console.log(`Found ${itemPath} as source file for LiveActivity`);
321
+ } else if (['.h'].includes(ext)) {
322
+ headerFiles.push(itemPath);
323
+ console.log(`Found ${itemPath} as header file for LiveActivity`);
324
+ } else if (['.entitlements'].includes(ext)) {
325
+ entitlementsFile = itemPath;
326
+ console.log(`Found ${itemPath} as entitlements file for LiveActivity`);
327
+ } else if (item.name === 'Info.plist' ||
328
+ item.name === `${MOENGAGE_IOS_LIVE_ACTIVITY_TARGET}-Info.plist` ||
329
+ item.name === `${path.basename(path.dirname(liveActivityTargetPath ?? ''))}-Info.plist`) {
330
+ infoPlistFile = itemPath;
331
+ console.log(`Found ${itemPath} as Info.plist file for LiveActivity`);
332
+ } else {
333
+ resourcesFiles.push(itemPath);
334
+ console.log(`Found ${itemPath} as resource for LiveActivity`);
335
+ }
336
+ // Add file to project
337
+ config.modResults.addFile(itemPath, group.uuid);
338
+ }
339
+ };
340
+
341
+ // Find all files
342
+ findFilesRecursively(liveActivityPath, moengageLiveActivityPathContentGroup);
343
+ } catch (e) {
344
+ const message = `Error finding files in Live Activity path: ${e}`;
345
+ console.error(message);
346
+ throw new Error(message);
347
+ }
348
+
349
+ // Set up build settings for the Live Activity target
350
+ for (const configUUID of Object.keys(xcconfigs)) {
351
+ const buildSettings = xcconfigs[configUUID].buildSettings;
352
+ if (buildSettings && buildSettings.PRODUCT_NAME === `"${MOENGAGE_IOS_LIVE_ACTIVITY_TARGET}"`) {
353
+ buildSettings.SWIFT_VERSION = codeSignSettings.swiftVersion;
354
+ buildSettings.IPHONEOS_DEPLOYMENT_TARGET = '18.0'; // Set minimum iOS version for Live Activity
355
+
356
+ // Add entitlements file if found
357
+ if (entitlementsFile && entitlementsFile.length) {
358
+ buildSettings.CODE_SIGN_ENTITLEMENTS = `${entitlementsFile}`;
359
+ }
360
+
361
+ // Add Info.plist file if found
362
+ if (infoPlistFile && infoPlistFile.length) {
363
+ buildSettings.INFOPLIST_FILE = `${infoPlistFile}`;
364
+ }
365
+
366
+ // Copy code signing settings from main target
367
+ if (codeSignSettings.codeSignStyle) { buildSettings.CODE_SIGN_STYLE = codeSignSettings.codeSignStyle; }
368
+ if (codeSignSettings.codeSignIdentity) { buildSettings.CODE_SIGN_IDENTITY = codeSignSettings.codeSignIdentity; }
369
+ if (codeSignSettings.otherCodeSigningFlags) { buildSettings.OTHER_CODE_SIGN_FLAGS = codeSignSettings.otherCodeSigningFlags; }
370
+ if (codeSignSettings.developmentTeam) { buildSettings.DEVELOPMENT_TEAM = codeSignSettings.developmentTeam; }
371
+ if (codeSignSettings.provisioningProfile) { buildSettings.PROVISIONING_PROFILE_SPECIFIER = codeSignSettings.provisioningProfile; }
372
+ }
373
+ }
374
+
375
+ // Add resources (xcassets) to the target
376
+ if (resourcesFiles.length) {
377
+ config.modResults.addBuildPhase(
378
+ resourcesFiles,
379
+ 'PBXResourcesBuildPhase',
380
+ 'Resources',
381
+ liveActivityTarget.uuid
382
+ );
383
+ }
384
+
385
+ // Add source files to the target
386
+ if (sourceFiles.length) {
387
+ config.modResults.addBuildPhase(
388
+ sourceFiles,
389
+ 'PBXSourcesBuildPhase',
390
+ 'Sources',
391
+ liveActivityTarget.uuid
392
+ );
393
+ }
394
+
395
+ // Add header files to the target
396
+ if (headerFiles.length) {
397
+ config.modResults.addBuildPhase(
398
+ headerFiles,
399
+ 'PBXHeadersBuildPhase',
400
+ 'Headers',
401
+ liveActivityTarget.uuid
402
+ );
403
+ }
404
+
405
+ // Add required frameworks for Live Activity
406
+ config.modResults.addBuildPhase(
407
+ [
408
+ 'SwiftUI.framework',
409
+ 'WidgetKit.framework',
410
+ 'ActivityKit.framework'
411
+ ],
412
+ 'PBXFrameworksBuildPhase',
413
+ 'Frameworks',
414
+ liveActivityTarget.uuid
415
+ );
416
+
417
+ return config;
418
+ }
package/src/index.ts ADDED
@@ -0,0 +1,52 @@
1
+ import { ConfigPlugin, createRunOncePlugin } from '@expo/config-plugins';
2
+ import withMoEngageAndroid from './android/withMoEngageAndroid';
3
+ import { withMoEngageIos } from './apple';
4
+ import { MoEngagePluginProps } from './types';
5
+
6
+ const defaultProps: MoEngagePluginProps = {
7
+ android: {
8
+ disableMoEngageDefaultBackupFile: false,
9
+ isExpoNotificationIntegration: false,
10
+ shouldIncludeMoEngageFirebaseMessagingService: false,
11
+ includeFirebaseMessagingDependencies: false,
12
+ configFilePath: 'assets/moengage/android_initilisation_config.xml',
13
+ },
14
+ apple: {
15
+ configFilePath: 'assets/moengage/MoEngage-Config.plist',
16
+ pushNotificationImpressionTrackingEnabled: true,
17
+ richPushNotificationEnabled: false,
18
+ pushTemplatesEnabled: false,
19
+ deviceTriggerEnabled: false,
20
+ liveActivityTargetPath: '',
21
+ },
22
+ };
23
+
24
+ /**
25
+ * Configure MoEngage SDK in your Expo app
26
+ */
27
+ const withMoEngage: ConfigPlugin<MoEngagePluginProps | undefined> = (config, props) => {
28
+ // Apply default values or handle undefined props
29
+ const pluginProps: MoEngagePluginProps = props ? {
30
+ ...defaultProps,
31
+ ...props,
32
+ android: {
33
+ ...defaultProps.android,
34
+ ...props.android,
35
+ },
36
+ apple: {
37
+ ...defaultProps.apple,
38
+ ...props.apple,
39
+ },
40
+ } : defaultProps
41
+ config = withMoEngageAndroid(config, pluginProps);
42
+ config = withMoEngageIos(config, pluginProps);
43
+ return config;
44
+ };
45
+
46
+ const pkg = require('../package.json');
47
+
48
+ export default createRunOncePlugin(
49
+ withMoEngage,
50
+ pkg.name,
51
+ pkg.version
52
+ );