react-native-mapp-plugin 2.0.0-beta.1 → 2.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 CHANGED
@@ -13,8 +13,11 @@
13
13
  - Android: Failed Firebase token registration now rejects with `FCM_REGISTRATION_FAILED` instead of crashing while reading a failed task result.
14
14
  - Android: All Mapp engage calls run on the main looper. Background Firebase callbacks wait for a bounded engage attempt and safely return failure after SDK errors, timeout, or interruption.
15
15
  - Android/Expo: Mapp and custom push ownership now remove the SDK v7 Firebase service and remain idempotent when prebuild runs repeatedly or changes mode.
16
+ - Android/Expo: The config plugin now writes required permissions, the Mapp messaging service, and the push receiver through `withAndroidManifest`; Firebase configuration remains customer-owned through `expo.android.googleServicesFile`.
16
17
  - Android: Exported Expo SDK 57 compatibility constraints stabilize WorkManager, Lifecycle, AndroidX Core, Play Services Location, and Kotlin stdlib for API 36/AGP 8.12/Kotlin 2.1.20 builds.
17
18
  - Android: Coroutines remain aligned at 1.11.0 to preserve the Mapp 7.1.2 native in-app dismissal ABI.
19
+ - iOS/Expo: The config plugin now creates and embeds a standalone Notification Service Extension for Mapp rich-push media from `ios_apx_media`, with EAS app-extension metadata and no App Group or extra Pod.
20
+ - iOS/Expo: Verified that Expo SDK 57 CocoaPods autolinking discovers `RNMappPlugin.podspec` and processes `RNMappPlugin` under the New Architecture.
18
21
 
19
22
  ***Compatibility***
20
23
 
package/README.md CHANGED
@@ -59,6 +59,8 @@ Configure the installed package by name in `app.json` (values shown are examples
59
59
 
60
60
  The Android package must match the Firebase Android application in `google-services.json`. For iOS, configure an APNs-enabled App ID, matching bundle identifier, and Apple/EAS signing credentials. Values embedded in app config and native resources are public application configuration; do not put service-account keys or signing secrets there.
61
61
 
62
+ The Firebase file is customer-owned configuration. Point Expo's built-in `expo.android.googleServicesFile` field at it; this plugin does not copy, generate, or modify `google-services.json`.
63
+
62
64
  Generate and run development builds:
63
65
 
64
66
  ```bash
@@ -113,6 +115,12 @@ Use `pushHandling: "custom"` when another integration, such as a client-owned `F
113
115
 
114
116
  Set `enableGeofencing` on each platform that needs it. Android then adds fine/background location permissions and `Mapp.requestGeofenceLocationPermission()` requests foreground permission before background permission. On iOS, also supply non-empty `locationWhenInUsePermission` and `locationAlwaysPermission` messages. Only request location access when your user-facing feature and store policy justify it.
115
117
 
118
+ ### iOS rich push
119
+
120
+ The Expo config plugin creates a `MappNotificationService` Notification Service Extension with the bundle identifier `<expo.ios.bundleIdentifier>.mappnotificationservice`. The extension reads the public Mapp `ios_apx_media` payload key, downloads the media, and attaches it to the notification. It follows the app minimum deployment target and is set to iOS 15+, uses an App Group shared with the main app, and does not require an additional CocoaPod or React Native code.
121
+
122
+ The extension is also declared in Expo's experimental EAS app-extension metadata so EAS can prepare its signing credentials. Regenerate the iOS project after changing the application bundle identifier.
123
+
116
124
  ### Tested compatibility
117
125
 
118
126
  | Component | Tested baseline |
@@ -143,6 +151,8 @@ cd ios && pod install
143
151
 
144
152
  Modern React Native autolinking discovers the Android package and CocoaPod automatically. Do not run `react-native link`, edit `settings.gradle`, or add `compile project(...)`.
145
153
 
154
+ No `MainActivity` or `MainApplication` edit is required. The native module is registered by autolinking. In Expo projects, the config plugin applies Android permissions, the Mapp messaging service, and the push receiver during prebuild without modifying consumer Gradle files. React Native CLI projects receive the same declarations through the library manifest merge. On iOS, CocoaPods discovers `RNMappPlugin.podspec` automatically; do not add the pod manually.
155
+
146
156
  For a manually maintained iOS native project, add Push Notifications, Remote Notifications background mode, and (only if needed) Location Updates, then include an `AppoxeeConfig.plist` in the application target. Expo clients should use the config plugin above instead.
147
157
 
148
158
  Basic usage:
@@ -5,11 +5,23 @@
5
5
  #import "AppoxeeLocationManager.h"
6
6
  #import <UserNotifications/UNUserNotificationCenter.h>
7
7
  #if RCT_NEW_ARCH_ENABLED
8
+ #import <ReactCommon/RCTTurboModule.h>
9
+ #if __has_include(<RNMappPluginSpec/RNMappPluginSpec.h>)
10
+ #import <RNMappPluginSpec/RNMappPluginSpec.h>
11
+ #define RNMAPP_HAS_TURBO_MODULE_SPEC 1
12
+ #elif __has_include(<RNMappPlugin/RNMappPlugin.h>)
8
13
  #import <RNMappPlugin/RNMappPlugin.h>
14
+ #define RNMAPP_HAS_TURBO_MODULE_SPEC 1
15
+ #elif __has_include("RNMappPlugin.h")
16
+ #import "RNMappPlugin.h"
17
+ #define RNMAPP_HAS_TURBO_MODULE_SPEC 1
18
+ #else
19
+ #define RNMAPP_HAS_TURBO_MODULE_SPEC 0
20
+ #endif
9
21
  #endif
10
22
 
11
23
  @interface RNMappPluginModule : NSObject <RCTBridgeModule,AppoxeeInappDelegate, AppoxeeNotificationDelegate, AppoxeeLocationManagerDelegate
12
- #if RCT_NEW_ARCH_ENABLED
24
+ #if RCT_NEW_ARCH_ENABLED && RNMAPP_HAS_TURBO_MODULE_SPEC
13
25
  , NativeRNMappPluginModuleSpec
14
26
  #endif
15
27
  >
@@ -2,12 +2,24 @@
2
2
  #import "RNMappEventEmmiter.h"
3
3
  #if RCT_NEW_ARCH_ENABLED
4
4
  #import <ReactCommon/RCTTurboModule.h>
5
+ #if __has_include(<RNMappPluginSpec/RNMappPluginSpec.h>)
6
+ #import <RNMappPluginSpec/RNMappPluginSpec.h>
7
+ #define RNMAPP_HAS_TURBO_MODULE_SPEC 1
8
+ #elif __has_include(<RNMappPlugin/RNMappPlugin.h>)
9
+ #import <RNMappPlugin/RNMappPlugin.h>
10
+ #define RNMAPP_HAS_TURBO_MODULE_SPEC 1
11
+ #elif __has_include("RNMappPlugin.h")
12
+ #import "RNMappPlugin.h"
13
+ #define RNMAPP_HAS_TURBO_MODULE_SPEC 1
14
+ #else
15
+ #define RNMAPP_HAS_TURBO_MODULE_SPEC 0
16
+ #endif
5
17
  #endif
6
18
 
7
19
 
8
20
  @implementation RNMappPluginModule
9
21
 
10
- #if RCT_NEW_ARCH_ENABLED
22
+ #if RCT_NEW_ARCH_ENABLED && RNMAPP_HAS_TURBO_MODULE_SPEC
11
23
  - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
12
24
  (const facebook::react::ObjCTurboModule::InitParams &)params
13
25
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-mapp-plugin",
3
- "version": "2.0.0-beta.1",
3
+ "version": "2.0.0",
4
4
  "description": "Mapp SDK for React Native.",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -1,4 +1,4 @@
1
1
  import { ConfigPlugin } from '@expo/config-plugins';
2
2
  import type { NormalizedMappExpoPluginProps } from './types';
3
- export declare function updatePushHandling(androidManifest: any, pushHandling: NormalizedMappExpoPluginProps['android']['pushHandling']): any;
3
+ export declare function updateAndroidManifest(androidManifest: any, props: NormalizedMappExpoPluginProps['android']): any;
4
4
  export declare const withMappEngageAndroid: ConfigPlugin<NormalizedMappExpoPluginProps['android']>;
@@ -1,28 +1,68 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.withMappEngageAndroid = void 0;
4
- exports.updatePushHandling = updatePushHandling;
4
+ exports.updateAndroidManifest = updateAndroidManifest;
5
5
  const config_plugins_1 = require("@expo/config-plugins");
6
6
  const messageService = 'com.reactlibrary.MessageService';
7
+ const pushBroadcastReceiver = 'com.reactlibrary.MyPushBroadcastReceiver';
7
8
  const sdkMessagingServices = [
8
9
  'com.appoxee.shared.MappMessagingService',
9
10
  'com.appoxee.push.fcm.MappMessagingService',
10
11
  ];
11
12
  const managedMessagingServices = [messageService, ...sdkMessagingServices];
13
+ const receiveBootCompleted = 'android.permission.RECEIVE_BOOT_COMPLETED';
14
+ const internet = 'android.permission.INTERNET';
15
+ const postNotifications = 'android.permission.POST_NOTIFICATIONS';
12
16
  const fineLocation = 'android.permission.ACCESS_FINE_LOCATION';
13
17
  const backgroundLocation = 'android.permission.ACCESS_BACKGROUND_LOCATION';
18
+ const firebaseMessagingEvent = 'com.google.firebase.MESSAGING_EVENT';
14
19
  function removeAll(items, predicate) {
15
20
  return (items ?? []).filter(item => !predicate(item));
16
21
  }
17
- function updatePushHandling(androidManifest, pushHandling) {
22
+ function addPermission(androidManifest, permission) {
23
+ const permissions = androidManifest.manifest['uses-permission'] ?? [];
24
+ if (!permissions.some((item) => item.$?.['android:name'] === permission)) {
25
+ permissions.push({ $: { 'android:name': permission } });
26
+ }
27
+ androidManifest.manifest['uses-permission'] = permissions;
28
+ }
29
+ function updateAndroidManifest(androidManifest, props) {
18
30
  const manifest = androidManifest.manifest;
19
31
  const application = config_plugins_1.AndroidConfig.Manifest.getMainApplicationOrThrow(androidManifest);
20
32
  application.service = removeAll(application.service, service => {
21
- return managedMessagingServices.includes(service.$?.['android:name'])
22
- && service.$?.['tools:node'] === 'remove';
33
+ return managedMessagingServices.includes(service.$?.['android:name']);
23
34
  });
35
+ application.receiver = removeAll(application.receiver, receiver => (receiver.$?.['android:name'] === pushBroadcastReceiver));
24
36
  manifest.$ = manifest.$ ?? {};
25
37
  manifest.$['xmlns:tools'] = 'http://schemas.android.com/tools';
38
+ for (const permission of [receiveBootCompleted, internet, postNotifications]) {
39
+ addPermission(androidManifest, permission);
40
+ }
41
+ if (props.enableGeofencing) {
42
+ addPermission(androidManifest, fineLocation);
43
+ addPermission(androidManifest, backgroundLocation);
44
+ }
45
+ application.receiver.push({
46
+ $: {
47
+ 'android:name': pushBroadcastReceiver,
48
+ 'android:enabled': 'true',
49
+ 'android:exported': 'false',
50
+ },
51
+ 'intent-filter': [{
52
+ action: [
53
+ { $: { 'android:name': 'com.appoxee.PUSH_OPENED' } },
54
+ { $: { 'android:name': 'com.appoxee.PUSH_RECEIVED' } },
55
+ { $: { 'android:name': 'com.appoxee.PUSH_DISMISSED' } },
56
+ { $: { 'android:name': 'com.appoxee.BUTTON_CLICKED' } },
57
+ { $: { 'android:name': 'android.intent.action.VIEW' } },
58
+ ],
59
+ category: [
60
+ { $: { 'android:name': '${applicationId}' } },
61
+ { $: { 'android:name': 'android.intent.category.DEFAULT' } },
62
+ { $: { 'android:name': 'android.intent.category.BROWSABLE' } },
63
+ ],
64
+ }],
65
+ });
26
66
  for (const serviceName of sdkMessagingServices) {
27
67
  application.service.push({
28
68
  $: {
@@ -31,7 +71,18 @@ function updatePushHandling(androidManifest, pushHandling) {
31
71
  },
32
72
  });
33
73
  }
34
- if (pushHandling === 'custom') {
74
+ if (props.pushHandling === 'mapp') {
75
+ application.service.push({
76
+ $: {
77
+ 'android:name': messageService,
78
+ 'android:exported': 'false',
79
+ },
80
+ 'intent-filter': [{
81
+ action: [{ $: { 'android:name': firebaseMessagingEvent } }],
82
+ }],
83
+ });
84
+ }
85
+ else {
35
86
  application.service.push({
36
87
  $: {
37
88
  'android:name': messageService,
@@ -42,11 +93,8 @@ function updatePushHandling(androidManifest, pushHandling) {
42
93
  return androidManifest;
43
94
  }
44
95
  const withMappEngageAndroid = (config, props) => {
45
- if (props.enableGeofencing) {
46
- config = config_plugins_1.AndroidConfig.Permissions.withPermissions(config, [fineLocation, backgroundLocation]);
47
- }
48
96
  return (0, config_plugins_1.withAndroidManifest)(config, configWithManifest => {
49
- configWithManifest.modResults = updatePushHandling(configWithManifest.modResults, props.pushHandling);
97
+ configWithManifest.modResults = updateAndroidManifest(configWithManifest.modResults, props);
50
98
  return configWithManifest;
51
99
  });
52
100
  };
@@ -3,6 +3,6 @@ import type { MappExpoPluginProps } from './types';
3
3
  export declare const withMappEngage: ConfigPlugin<MappExpoPluginProps>;
4
4
  export type { MappExpoPluginProps } from './types';
5
5
  export { withMappEngageAndroid } from './android';
6
- export { withMappEngageIos, buildAppoxeeConfig, writeAppoxeeConfig } from './ios';
6
+ export { withMappEngageIos, buildAppoxeeConfig, writeAppoxeeConfig, buildNotificationServiceInfoPlist, writeNotificationServiceFiles, } from './ios';
7
7
  export { validateAndNormalizeProps } from './validation';
8
8
  export default withMappEngage;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateAndNormalizeProps = exports.writeAppoxeeConfig = exports.buildAppoxeeConfig = exports.withMappEngageIos = exports.withMappEngageAndroid = exports.withMappEngage = void 0;
3
+ exports.validateAndNormalizeProps = exports.writeNotificationServiceFiles = exports.buildNotificationServiceInfoPlist = exports.writeAppoxeeConfig = exports.buildAppoxeeConfig = exports.withMappEngageIos = exports.withMappEngageAndroid = exports.withMappEngage = void 0;
4
4
  const config_plugins_1 = require("@expo/config-plugins");
5
5
  const android_1 = require("./android");
6
6
  const ios_1 = require("./ios");
@@ -19,6 +19,8 @@ var ios_2 = require("./ios");
19
19
  Object.defineProperty(exports, "withMappEngageIos", { enumerable: true, get: function () { return ios_2.withMappEngageIos; } });
20
20
  Object.defineProperty(exports, "buildAppoxeeConfig", { enumerable: true, get: function () { return ios_2.buildAppoxeeConfig; } });
21
21
  Object.defineProperty(exports, "writeAppoxeeConfig", { enumerable: true, get: function () { return ios_2.writeAppoxeeConfig; } });
22
+ Object.defineProperty(exports, "buildNotificationServiceInfoPlist", { enumerable: true, get: function () { return ios_2.buildNotificationServiceInfoPlist; } });
23
+ Object.defineProperty(exports, "writeNotificationServiceFiles", { enumerable: true, get: function () { return ios_2.writeNotificationServiceFiles; } });
22
24
  var validation_2 = require("./validation");
23
25
  Object.defineProperty(exports, "validateAndNormalizeProps", { enumerable: true, get: function () { return validation_2.validateAndNormalizeProps; } });
24
26
  exports.default = exports.withMappEngage;
@@ -2,4 +2,6 @@ import { ConfigPlugin } from '@expo/config-plugins';
2
2
  import type { NormalizedMappExpoPluginProps } from './types';
3
3
  export declare function buildAppoxeeConfig(props: NormalizedMappExpoPluginProps['ios']): Record<string, unknown>;
4
4
  export declare function writeAppoxeeConfig(platformProjectRoot: string, props: NormalizedMappExpoPluginProps['ios']): Promise<string>;
5
+ export declare function buildNotificationServiceInfoPlist(): Record<string, unknown>;
6
+ export declare function writeNotificationServiceFiles(platformProjectRoot: string, bundleIdentifier: string): Promise<string[]>;
5
7
  export declare const withMappEngageIos: ConfigPlugin<NormalizedMappExpoPluginProps['ios']>;
@@ -6,11 +6,84 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.withMappEngageIos = void 0;
7
7
  exports.buildAppoxeeConfig = buildAppoxeeConfig;
8
8
  exports.writeAppoxeeConfig = writeAppoxeeConfig;
9
+ exports.buildNotificationServiceInfoPlist = buildNotificationServiceInfoPlist;
10
+ exports.writeNotificationServiceFiles = writeNotificationServiceFiles;
9
11
  const fs_1 = __importDefault(require("fs"));
10
12
  const path_1 = __importDefault(require("path"));
11
13
  const config_plugins_1 = require("@expo/config-plugins");
12
14
  const plist_1 = __importDefault(require("@expo/plist"));
13
15
  const plistName = 'AppoxeeConfig.plist';
16
+ const notificationServiceTargetName = 'MappNotificationService';
17
+ const notificationServiceInfoPlistName = 'Info.plist';
18
+ const notificationServiceEntitlementsName = 'MappNotificationService.entitlements';
19
+ const notificationServiceSourceName = 'NotificationService.swift';
20
+ const notificationServiceDeploymentTarget = '15.0';
21
+ const notificationServiceSource = `import UserNotifications
22
+
23
+ class NotificationService: UNNotificationServiceExtension {
24
+
25
+ var contentHandler: ((UNNotificationContent) -> Void)?
26
+
27
+ var bestAttemptContent: UNMutableNotificationContent?
28
+
29
+ override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
30
+
31
+ self.contentHandler = contentHandler
32
+
33
+ bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
34
+
35
+ print("categori identifier: ", request.content)
36
+
37
+ UNUserNotificationCenter.current().getNotificationCategories { (categories) in
38
+
39
+ if let categoryIdentifier = self.bestAttemptContent?.categoryIdentifier, let lc = request.content.userInfo["aps"] {
40
+
41
+ self.bestAttemptContent?.categoryIdentifier = categoryIdentifier + "_" + ((lc as! NSDictionary)["lc"] as! String)
42
+
43
+ let categoryExistArray = categories.filter { (category) -> Bool in
44
+ category.identifier == self.bestAttemptContent?.categoryIdentifier
45
+ }
46
+
47
+ if categoryExistArray.isEmpty {
48
+ self.bestAttemptContent?.categoryIdentifier = categoryIdentifier + "_en"
49
+ }
50
+ }
51
+
52
+ if let urlString = request.content.userInfo["ios_apx_media"], let fileUrl = URL(string: urlString as? String ?? "") {
53
+
54
+ URLSession.shared.downloadTask(with: fileUrl ) { (location, response, error) in
55
+
56
+ if let location = location {
57
+ let tmpDirectory = NSTemporaryDirectory()
58
+ let tmpFile = "file://".appending(tmpDirectory).appending(fileUrl.lastPathComponent)
59
+ let tmpUrl = URL(string: tmpFile)!
60
+
61
+ try! FileManager.default.moveItem(at: location, to: tmpUrl)
62
+
63
+ if let attachment = try? UNNotificationAttachment(identifier: "", url: tmpUrl) {
64
+ self.bestAttemptContent?.attachments = [attachment]
65
+ }
66
+ }
67
+
68
+ print("categori identifier: ", self.bestAttemptContent?.categoryIdentifier ?? "no category identifier")
69
+
70
+ self.contentHandler!(self.bestAttemptContent!)
71
+
72
+ }.resume()
73
+
74
+ } else {
75
+ self.contentHandler!(self.bestAttemptContent!)
76
+ }
77
+ }
78
+ }
79
+
80
+ override func serviceExtensionTimeWillExpire() {
81
+ if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
82
+ contentHandler(bestAttemptContent)
83
+ }
84
+ }
85
+ }
86
+ `;
14
87
  function buildAppoxeeConfig(props) {
15
88
  return {
16
89
  inapp: {
@@ -33,11 +106,96 @@ async function writeAppoxeeConfig(platformProjectRoot, props) {
33
106
  await fs_1.default.promises.writeFile(outputPath, plist_1.default.build(buildAppoxeeConfig(props)));
34
107
  return outputPath;
35
108
  }
109
+ function buildNotificationServiceInfoPlist() {
110
+ return {
111
+ NSExtension: {
112
+ NSExtensionPointIdentifier: 'com.apple.usernotifications.service',
113
+ NSExtensionPrincipalClass: '$(PRODUCT_MODULE_NAME).NotificationService',
114
+ },
115
+ };
116
+ }
117
+ async function writeFileIfChanged(filePath, contents) {
118
+ const current = await fs_1.default.promises.readFile(filePath, 'utf8').catch(() => undefined);
119
+ if (current !== contents) {
120
+ await fs_1.default.promises.writeFile(filePath, contents);
121
+ }
122
+ }
123
+ async function writeNotificationServiceFiles(platformProjectRoot, bundleIdentifier) {
124
+ const extensionRoot = path_1.default.join(platformProjectRoot, notificationServiceTargetName);
125
+ const infoPlistPath = path_1.default.join(extensionRoot, notificationServiceInfoPlistName);
126
+ const entitlementsPath = path_1.default.join(extensionRoot, notificationServiceEntitlementsName);
127
+ const sourcePath = path_1.default.join(extensionRoot, notificationServiceSourceName);
128
+ await fs_1.default.promises.mkdir(extensionRoot, { recursive: true });
129
+ await writeFileIfChanged(infoPlistPath, plist_1.default.build(buildNotificationServiceInfoPlist()));
130
+ await writeFileIfChanged(entitlementsPath, plist_1.default.build(buildNotificationServiceEntitlements(bundleIdentifier)));
131
+ await writeFileIfChanged(sourcePath, notificationServiceSource);
132
+ return [infoPlistPath, entitlementsPath, sourcePath];
133
+ }
134
+ function getNotificationServiceBundleIdentifier(config) {
135
+ return `${config.ios.bundleIdentifier}.mappnotificationservice`;
136
+ }
137
+ function getAppGroupIdentifier(bundleIdentifier) {
138
+ return `group.${bundleIdentifier}`;
139
+ }
140
+ function buildNotificationServiceEntitlements(bundleIdentifier) {
141
+ return {
142
+ 'com.apple.security.application-groups': [getAppGroupIdentifier(bundleIdentifier)],
143
+ };
144
+ }
145
+ function addNotificationServiceToEasConfig(config, bundleIdentifier) {
146
+ config.extra = config.extra ?? {};
147
+ config.extra.eas = config.extra.eas ?? {};
148
+ config.extra.eas.build = config.extra.eas.build ?? {};
149
+ config.extra.eas.build.experimental = config.extra.eas.build.experimental ?? {};
150
+ config.extra.eas.build.experimental.ios = config.extra.eas.build.experimental.ios ?? {};
151
+ const ios = config.extra.eas.build.experimental.ios;
152
+ const appExtensions = Array.isArray(ios.appExtensions) ? ios.appExtensions : [];
153
+ ios.appExtensions = [
154
+ ...appExtensions.filter((extension) => extension?.targetName !== notificationServiceTargetName),
155
+ { targetName: notificationServiceTargetName, bundleIdentifier },
156
+ ];
157
+ }
158
+ function addNotificationServiceTarget(project, bundleIdentifier) {
159
+ const existingTarget = config_plugins_1.IOSConfig.Target.getNativeTargets(project).find(([, target]) => (config_plugins_1.IOSConfig.XcodeUtils.unquote(target.name) === notificationServiceTargetName));
160
+ if (existingTarget) {
161
+ return;
162
+ }
163
+ project.hash.project.objects.PBXContainerItemProxy =
164
+ project.hash.project.objects.PBXContainerItemProxy ?? {};
165
+ project.hash.project.objects.PBXTargetDependency =
166
+ project.hash.project.objects.PBXTargetDependency ?? {};
167
+ const target = project.addTarget(notificationServiceTargetName, 'app_extension', notificationServiceTargetName, bundleIdentifier);
168
+ project.addBuildPhase([], 'PBXSourcesBuildPhase', 'Sources', target.uuid);
169
+ project.addBuildPhase([], 'PBXFrameworksBuildPhase', 'Frameworks', target.uuid);
170
+ const groupKey = project.pbxCreateGroup(notificationServiceTargetName, notificationServiceTargetName);
171
+ const { firstProject } = project.getFirstProject();
172
+ project.getPBXGroupByKey(firstProject.mainGroup).children.push({
173
+ value: groupKey,
174
+ comment: notificationServiceTargetName,
175
+ });
176
+ project.addFile(notificationServiceInfoPlistName, groupKey);
177
+ project.addFile(notificationServiceEntitlementsName, groupKey);
178
+ project.addSourceFile(notificationServiceSourceName, { target: target.uuid }, groupKey);
179
+ project.addFramework('UserNotifications.framework', { target: target.uuid });
180
+ for (const [, buildConfiguration] of config_plugins_1.IOSConfig.XcodeUtils.getBuildConfigurationsForListId(project, target.pbxNativeTarget.buildConfigurationList)) {
181
+ const settings = buildConfiguration.buildSettings;
182
+ settings.CODE_SIGN_STYLE = 'Automatic';
183
+ settings.CODE_SIGN_ENTITLEMENTS = `"${notificationServiceTargetName}/${notificationServiceEntitlementsName}"`;
184
+ settings.GENERATE_INFOPLIST_FILE = 'NO';
185
+ settings.INFOPLIST_FILE = `"${notificationServiceTargetName}/${notificationServiceInfoPlistName}"`;
186
+ settings.IPHONEOS_DEPLOYMENT_TARGET = notificationServiceDeploymentTarget;
187
+ settings.PRODUCT_BUNDLE_IDENTIFIER = `"${bundleIdentifier}"`;
188
+ settings.SWIFT_VERSION = '5.0';
189
+ settings.TARGETED_DEVICE_FAMILY = '"1,2"';
190
+ }
191
+ }
36
192
  function appendUnique(values, value) {
37
193
  const result = Array.isArray(values) ? values.filter(item => typeof item === 'string') : [];
38
194
  return result.includes(value) ? result : [...result, value];
39
195
  }
40
196
  const withMappEngageIos = (config, props) => {
197
+ const notificationServiceBundleIdentifier = getNotificationServiceBundleIdentifier(config);
198
+ addNotificationServiceToEasConfig(config, notificationServiceBundleIdentifier);
41
199
  config = (0, config_plugins_1.withInfoPlist)(config, configWithPlist => {
42
200
  configWithPlist.modResults.UIBackgroundModes = appendUnique(configWithPlist.modResults.UIBackgroundModes, 'remote-notification');
43
201
  if (props.enableGeofencing) {
@@ -50,10 +208,12 @@ const withMappEngageIos = (config, props) => {
50
208
  config = (0, config_plugins_1.withEntitlementsPlist)(config, configWithEntitlements => {
51
209
  configWithEntitlements.modResults['aps-environment'] =
52
210
  configWithEntitlements.modResults['aps-environment'] ?? 'development';
211
+ configWithEntitlements.modResults['com.apple.security.application-groups'] = appendUnique(configWithEntitlements.modResults['com.apple.security.application-groups'], getAppGroupIdentifier(config.ios.bundleIdentifier));
53
212
  return configWithEntitlements;
54
213
  });
55
214
  config = (0, config_plugins_1.withDangerousMod)(config, ['ios', async (configWithFiles) => {
56
215
  await writeAppoxeeConfig(configWithFiles.modRequest.platformProjectRoot, props);
216
+ await writeNotificationServiceFiles(configWithFiles.modRequest.platformProjectRoot, config.ios.bundleIdentifier);
57
217
  return configWithFiles;
58
218
  }]);
59
219
  return (0, config_plugins_1.withXcodeProject)(config, configWithProject => {
@@ -71,6 +231,7 @@ const withMappEngageIos = (config, props) => {
71
231
  targetUuid: target.uuid,
72
232
  });
73
233
  }
234
+ addNotificationServiceTarget(project, notificationServiceBundleIdentifier);
74
235
  return configWithProject;
75
236
  });
76
237
  };