react-native-mapp-plugin 1.4.2 → 2.0.0-beta.1

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.
@@ -11,8 +11,6 @@ import android.content.Intent;
11
11
  import android.content.pm.PackageManager;
12
12
  import android.net.Uri;
13
13
  import android.os.Build;
14
- import android.os.Handler;
15
- import android.os.Looper;
16
14
  import android.util.DisplayMetrics;
17
15
  import android.provider.Settings;
18
16
 
@@ -24,6 +22,7 @@ import androidx.core.content.ContextCompat;
24
22
  import com.appoxee.Appoxee;
25
23
  import com.appoxee.internal.model.response.DevicePayload;
26
24
  import com.appoxee.shared.InboxMessage;
25
+ import com.appoxee.shared.MessageStatus;
27
26
  import com.appoxee.sdk.BuildConfig;
28
27
  import com.appoxee.shared.AppoxeeObserver;
29
28
  import com.appoxee.shared.AppoxeeOptions;
@@ -80,12 +79,15 @@ public class RNMappPluginModule extends NativeRNMappPluginModuleSpec implements
80
79
 
81
80
  public static final String NAME = "RNMappPluginModule";
82
81
  private static final int POST_NOTIFICATION_PERMISSION_REQUEST_CODE = 1001;
82
+ private static final int GEOFENCE_PERMISSION_REQUEST_CODE = 2001;
83
83
  private final ReactApplicationContext reactContext;
84
84
  private Map<Callback, String> mFeedSubscriberMap = new ConcurrentHashMap<>();
85
85
  private Map<Callback, Boolean> mCallbackWasCalledMap = new ConcurrentHashMap<>();
86
86
  private final Map<Integer, Promise> notificationPermissionPromises = new ConcurrentHashMap<>();
87
+ private final Map<Integer, Promise> geofencePermissionPromises = new ConcurrentHashMap<>();
87
88
  private Application application = null;
88
89
  private int nextNotificationPermissionRequestCode = POST_NOTIFICATION_PERMISSION_REQUEST_CODE;
90
+ private int nextGeofencePermissionRequestCode = GEOFENCE_PERMISSION_REQUEST_CODE;
89
91
 
90
92
  public RNMappPluginModule(ReactApplicationContext reactContext) {
91
93
  super(reactContext);
@@ -128,10 +130,32 @@ public class RNMappPluginModule extends NativeRNMappPluginModuleSpec implements
128
130
  promise.resolve(true);
129
131
  return;
130
132
  }
131
- int fineLocation = ContextCompat.checkSelfPermission(reactContext, Manifest.permission.ACCESS_FINE_LOCATION);
132
- int backgroundLocation = ContextCompat.checkSelfPermission(reactContext, Manifest.permission.ACCESS_BACKGROUND_LOCATION);
133
- promise.resolve(fineLocation == PackageManager.PERMISSION_GRANTED
134
- && backgroundLocation == PackageManager.PERMISSION_GRANTED);
133
+ if (hasFineLocationPermission() && hasBackgroundLocationPermission()) {
134
+ promise.resolve(true);
135
+ return;
136
+ }
137
+ Activity activity = getCurrentActivity();
138
+ if (!(activity instanceof PermissionAwareActivity)) {
139
+ promise.resolve(false);
140
+ return;
141
+ }
142
+ int requestCode = nextGeofencePermissionRequestCode++;
143
+ geofencePermissionPromises.put(requestCode, promise);
144
+ String[] permissions = hasFineLocationPermission()
145
+ ? new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION}
146
+ : new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
147
+ ((PermissionAwareActivity) activity).requestPermissions(permissions, requestCode, this);
148
+ }
149
+
150
+ private boolean hasFineLocationPermission() {
151
+ return ContextCompat.checkSelfPermission(reactContext, Manifest.permission.ACCESS_FINE_LOCATION)
152
+ == PackageManager.PERMISSION_GRANTED;
153
+ }
154
+
155
+ private boolean hasBackgroundLocationPermission() {
156
+ return Build.VERSION.SDK_INT < Build.VERSION_CODES.Q
157
+ || ContextCompat.checkSelfPermission(reactContext, Manifest.permission.ACCESS_BACKGROUND_LOCATION)
158
+ == PackageManager.PERMISSION_GRANTED;
135
159
  }
136
160
 
137
161
  @ReactMethod
@@ -168,6 +192,31 @@ public class RNMappPluginModule extends NativeRNMappPluginModuleSpec implements
168
192
 
169
193
  @Override
170
194
  public boolean onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
195
+ Promise geofencePromise = geofencePermissionPromises.remove(requestCode);
196
+ if (geofencePromise != null) {
197
+ boolean granted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED;
198
+ if (!granted) {
199
+ geofencePromise.resolve(false);
200
+ return true;
201
+ }
202
+ if (!hasBackgroundLocationPermission()) {
203
+ Activity activity = getCurrentActivity();
204
+ if (!(activity instanceof PermissionAwareActivity)) {
205
+ geofencePromise.resolve(false);
206
+ return true;
207
+ }
208
+ int backgroundRequestCode = nextGeofencePermissionRequestCode++;
209
+ geofencePermissionPromises.put(backgroundRequestCode, geofencePromise);
210
+ ((PermissionAwareActivity) activity).requestPermissions(
211
+ new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION},
212
+ backgroundRequestCode,
213
+ this
214
+ );
215
+ return true;
216
+ }
217
+ geofencePromise.resolve(hasFineLocationPermission());
218
+ return true;
219
+ }
171
220
  Promise promise = notificationPermissionPromises.remove(requestCode);
172
221
  if (promise == null) {
173
222
  return false;
@@ -287,11 +336,24 @@ public class RNMappPluginModule extends NativeRNMappPluginModuleSpec implements
287
336
  FirebaseMessaging.getInstance().getToken().addOnCompleteListener(new OnCompleteListener<String>() {
288
337
  @Override
289
338
  public void onComplete(@NonNull Task<String> task) {
290
- promise.resolve(task.getResult());
339
+ settleTokenTask(task, promise);
291
340
  }
292
341
  });
293
342
  }
294
343
 
344
+ static void settleTokenTask(@NonNull Task<String> task, @NonNull Promise promise) {
345
+ if (task.isSuccessful()) {
346
+ promise.resolve(task.getResult());
347
+ return;
348
+ }
349
+
350
+ Exception exception = task.getException();
351
+ String message = exception != null && exception.getMessage() != null
352
+ ? exception.getMessage()
353
+ : "FCM registration failed";
354
+ promise.reject("FCM_REGISTRATION_FAILED", message, exception);
355
+ }
356
+
295
357
  // -------------------------------------------------------------------------
296
358
  // Alias
297
359
  // -------------------------------------------------------------------------
@@ -318,7 +380,7 @@ public class RNMappPluginModule extends NativeRNMappPluginModuleSpec implements
318
380
  @ReactMethod
319
381
  @Deprecated(forRemoval = true)
320
382
  public void engage2() {
321
- Appoxee.engage(application,null);
383
+ MappEngagementDispatcher.engageAsync(Objects.requireNonNull(application), null, null);
322
384
  }
323
385
 
324
386
  @ReactMethod
@@ -326,9 +388,7 @@ public class RNMappPluginModule extends NativeRNMappPluginModuleSpec implements
326
388
  AppoxeeOptions opt = createOptions(server, sdkKey, appID, tenantID);
327
389
  opt.setNotificationMode(NotificationMode.BACKGROUND_AND_FOREGROUND);
328
390
 
329
- new Handler(Looper.getMainLooper()).post(() -> {
330
- Appoxee.engage(Objects.requireNonNull(application), opt);
331
-
391
+ MappEngagementDispatcher.engageAsync(Objects.requireNonNull(application), opt, () -> {
332
392
  Appoxee.instance().subscribe(new AppoxeeObserver() {
333
393
  @Override
334
394
  public void onReadyStatusChanged(boolean status, MappResult<DevicePayload> result) {
@@ -344,9 +404,7 @@ public class RNMappPluginModule extends NativeRNMappPluginModuleSpec implements
344
404
  String appID, String tenantID) {
345
405
  AppoxeeOptions opt = createOptions(server, sdkKey, appID, tenantID);
346
406
 
347
- new Handler(Looper.getMainLooper()).post(() -> {
348
- Appoxee.engage(Objects.requireNonNull(application), opt);
349
-
407
+ MappEngagementDispatcher.engageAsync(Objects.requireNonNull(application), opt, () -> {
350
408
  Appoxee.instance().subscribe(new AppoxeeObserver() {
351
409
  @Override
352
410
  public void onReadyStatusChanged(boolean status, MappResult<DevicePayload> result) {
@@ -738,33 +796,41 @@ public class RNMappPluginModule extends NativeRNMappPluginModuleSpec implements
738
796
  });
739
797
  }
740
798
 
741
- /**
742
- * Stubbed: InApp statistics internal classes were removed in v7.
743
- * The @ReactMethod signature is preserved to avoid breaking the JS public API.
744
- */
745
799
  @ReactMethod
746
800
  public void inAppMarkAsRead(double templateId, String eventId) {
747
- // no-op in v7
801
+ updateInboxMessageStatus((long) templateId, MessageStatus.READ);
748
802
  }
749
803
 
750
- /**
751
- * @see #inAppMarkAsRead
752
- */
753
804
  @ReactMethod
754
805
  public void inAppMarkAsUnRead(double templateId, String eventId) {
755
- // no-op in v7
806
+ updateInboxMessageStatus((long) templateId, MessageStatus.UNREAD);
756
807
  }
757
808
 
758
- /**
759
- * @see #inAppMarkAsRead
760
- */
761
809
  @ReactMethod
762
810
  public void inAppMarkAsDeleted(double templateId, String eventId) {
763
- // no-op in v7
811
+ updateInboxMessageStatus((long) templateId, MessageStatus.DELETED);
764
812
  }
765
813
 
766
814
  /**
767
- * @see #inAppMarkAsRead
815
+ * Mapp Engage v7 updates inbox state using the SDK's InboxMessage object,
816
+ * so fetch the message by template ID before sending the status update.
817
+ * The legacy eventId argument is not required by the v7 API.
818
+ */
819
+ private void updateInboxMessageStatus(long templateId, MessageStatus status) {
820
+ final Appoxee appoxee = Appoxee.instance();
821
+ appoxee.fetchInboxMessage(templateId).enqueue(fetchResult -> {
822
+ if (fetchResult == null || !fetchResult.isSuccess() || fetchResult.getData() == null) {
823
+ return;
824
+ }
825
+
826
+ appoxee.updateInboxMessageStatus(fetchResult.getData(), status).enqueue(updateResult -> {
827
+ });
828
+ });
829
+ }
830
+
831
+ /**
832
+ * Stubbed: InApp statistics internal classes were removed in v7.
833
+ * The @ReactMethod signature is preserved to avoid breaking the JS public API.
768
834
  */
769
835
  @ReactMethod
770
836
  public void triggerStatistic(double templateId, String originalEventId,
package/app.plugin.js ADDED
@@ -0,0 +1,4 @@
1
+ 'use strict';
2
+
3
+ module.exports = require('./plugin/build').withMappEngage;
4
+
@@ -43,6 +43,11 @@ NSString *const MappRNInappMessage = @"com.mapp.inapp_message";
43
43
 
44
44
  -(void)startObserving {
45
45
  hasListeners = YES;
46
+ NSArray *events = [self.pendingEvents copy];
47
+ [self.pendingEvents removeAllObjects];
48
+ for (NSDictionary *event in events) {
49
+ [super sendEventWithName:event[@"name"] body:event[@"body"]];
50
+ }
46
51
  }
47
52
 
48
53
  -(void)stopObserving {
@@ -50,7 +55,22 @@ NSString *const MappRNInappMessage = @"com.mapp.inapp_message";
50
55
  }
51
56
 
52
57
  - (NSArray<NSString *> *)supportedEvents {
53
- return @[MappRNInitEvent, MappRNInboxMessageReceived, MappRNInboxMessagesReceived, MappRNLocationEnter, MappRNCustomLinkReceived, MappRNDeepLinkReceived, MappRNRichMessage,MappRNPushMessage, MappErrorMessage,MappRNInappMessage];
58
+ return @[MappRNInitEvent, MappRNInboxMessageReceived, MappRNInboxMessagesReceived, MappRNLocationEnter, MappRNLocationExit, MappRNCustomLinkReceived, MappRNDeepLinkReceived, MappRNRichMessage,MappRNPushMessage, MappErrorMessage,MappRNInappMessage];
59
+ }
60
+
61
+ - (void)sendEventWithName:(NSString *)name body:(id)body {
62
+ if (hasListeners) {
63
+ [super sendEventWithName:name body:body];
64
+ return;
65
+ }
66
+ if (!self.pendingEvents) {
67
+ self.pendingEvents = [NSMutableArray array];
68
+ }
69
+ // Bound the cold-start queue so repeated background callbacks cannot grow it forever.
70
+ if (self.pendingEvents.count >= 50) {
71
+ [self.pendingEvents removeObjectAtIndex:0];
72
+ }
73
+ [self.pendingEvents addObject:@{ @"name": name, @"body": body ?: [NSNull null] }];
54
74
  }
55
75
 
56
76
  - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
@@ -224,4 +244,3 @@ NSString *const MappRNInappMessage = @"com.mapp.inapp_message";
224
244
  }
225
245
  @end
226
246
 
227
-
@@ -4,7 +4,14 @@
4
4
  #import "AppoxeeInapp.h"
5
5
  #import "AppoxeeLocationManager.h"
6
6
  #import <UserNotifications/UNUserNotificationCenter.h>
7
+ #if RCT_NEW_ARCH_ENABLED
8
+ #import <RNMappPlugin/RNMappPlugin.h>
9
+ #endif
7
10
 
8
- @interface RNMappPluginModule : NSObject <RCTBridgeModule,AppoxeeInappDelegate, AppoxeeNotificationDelegate, AppoxeeLocationManagerDelegate >
11
+ @interface RNMappPluginModule : NSObject <RCTBridgeModule,AppoxeeInappDelegate, AppoxeeNotificationDelegate, AppoxeeLocationManagerDelegate
12
+ #if RCT_NEW_ARCH_ENABLED
13
+ , NativeRNMappPluginModuleSpec
14
+ #endif
15
+ >
9
16
 
10
17
  @end
@@ -1,9 +1,20 @@
1
1
  #import "RNMappPluginModule.h"
2
2
  #import "RNMappEventEmmiter.h"
3
+ #if RCT_NEW_ARCH_ENABLED
4
+ #import <ReactCommon/RCTTurboModule.h>
5
+ #endif
3
6
 
4
7
 
5
8
  @implementation RNMappPluginModule
6
9
 
10
+ #if RCT_NEW_ARCH_ENABLED
11
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
12
+ (const facebook::react::ObjCTurboModule::InitParams &)params
13
+ {
14
+ return std::make_shared<facebook::react::NativeRNMappPluginModuleSpecJSI>(params);
15
+ }
16
+ #endif
17
+
7
18
 
8
19
  - (void)setBridge:(RCTBridge *)bridge {
9
20
  [RNMappEventEmmiter shared].bridge = bridge;
@@ -35,20 +46,87 @@ RCT_EXPORT_METHOD(removeListeners:(NSInteger)count) {
35
46
  [[RNMappEventEmmiter shared] removeListeners:count];
36
47
  }
37
48
 
38
- #pragma mark Exported methods - Notifications
49
+ // Cross-platform TurboModule methods that need iOS-specific behavior or have no
50
+ // meaningful iOS equivalent. Keeping them here makes the generated spec safe to
51
+ // invoke under the New Architecture instead of relying on legacy interop.
52
+ RCT_EXPORT_METHOD(requestGeofenceLocationPermission:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
53
+ CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
54
+ if (status == kCLAuthorizationStatusNotDetermined) {
55
+ [[[CLLocationManager alloc] init] requestAlwaysAuthorization];
56
+ }
57
+ resolve(@(status == kCLAuthorizationStatusAuthorizedAlways));
58
+ }
59
+
60
+ RCT_EXPORT_METHOD(requestPostNotificationPermission:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
61
+ [[UNUserNotificationCenter currentNotificationCenter]
62
+ requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound)
63
+ completionHandler:^(BOOL granted, NSError *error) {
64
+ if (error) reject(@"NOTIFICATION_PERMISSION_ERROR", @"Unable to request notification permission", error);
65
+ else resolve(@(granted));
66
+ }];
67
+ }
68
+
69
+ RCT_EXPORT_METHOD(setRemoteMessage:(NSString *)msgJson resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
70
+ // iOS delivery is handled by APNs/Appoxee auto-integration, not FCM RemoteMessage JSON.
71
+ resolve(@NO);
72
+ }
73
+
74
+ RCT_EXPORT_METHOD(isPushFromMapp:(NSString *)msgJson resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
75
+ resolve(@NO);
76
+ }
39
77
 
40
- RCT_EXPORT_METHOD(engage: (NSString *)sdkKey projectId: (NSString *)projectId cepUrl:(NSString *)cepUrl appID:(NSString *)appID tenantID:(NSString *)tenantID) {
41
- SERVER serv = [self getServerKeyFor:cepUrl];
42
- [[Appoxee shared] engageWithLaunchOptions:nil andDelegate:[RNMappEventEmmiter shared] andSDKID:sdkKey with: serv];
78
+ RCT_EXPORT_METHOD(getToken:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
79
+ reject(@"APNS_TOKEN_UNAVAILABLE", @"Mapp auto-integration owns the native APNs token on iOS", nil);
43
80
  }
44
81
 
45
- RCT_REMAP_METHOD(autoengage,engage:(NSString *) server) {
82
+ RCT_EXPORT_METHOD(engage2) {}
83
+
84
+ RCT_EXPORT_METHOD(engageTestServer:(NSString *)cepUrl sdkKey:(NSString *)sdkKey googleProjectId:(NSString *)projectId server:(NSString *)server appID:(NSString *)appID tenantID:(NSString *)tenantID) {
85
+ [self engage:sdkKey googleProjectId:projectId server:server appID:appID tenantID:tenantID];
86
+ }
87
+
88
+ RCT_EXPORT_METHOD(onInitCompletedListener:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
89
+ resolve(@([[Appoxee shared] isReady]));
90
+ }
91
+
92
+ RCT_EXPORT_METHOD(setAttributeBoolean:(NSString *)key value:(BOOL)value) {
93
+ [[Appoxee shared] setNumberValue:@(value) forKey:key withCompletionHandler:nil];
94
+ }
95
+
96
+ RCT_EXPORT_METHOD(removeAttribute:(NSString *)attribute) {
97
+ // The vendored iOS SDK has no single-field removal API.
98
+ }
99
+
100
+ RCT_EXPORT_METHOD(getDeviceDmcInfo:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
101
+ [self getDeviceInfo:resolve reject:reject];
102
+ }
103
+
104
+ RCT_EXPORT_METHOD(lockScreenOrientation:(NSInteger)orientation) {}
105
+
106
+ RCT_EXPORT_METHOD(startGeofencing:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
107
+ [[AppoxeeLocationManager shared] enableLocationMonitoring];
108
+ resolve(@"started");
109
+ }
110
+
111
+ RCT_EXPORT_METHOD(stopGeofencing:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
112
+ [[AppoxeeLocationManager shared] disableLocationMonitoring];
113
+ resolve(@"stopped");
114
+ }
115
+
116
+ RCT_EXPORT_METHOD(triggerStatistic:(NSInteger)templateId originalEventId:(NSString *)originalEventId trackingKey:(NSString *)trackingKey displayMillis:(NSInteger)displayMillis reason:(NSString *)reason link:(NSString *)link) {}
117
+ RCT_EXPORT_METHOD(addAndroidListener:(NSString *)eventName) {}
118
+ RCT_EXPORT_METHOD(removeAndroidListeners:(NSInteger)count) {}
119
+
120
+ #pragma mark Exported methods - Notifications
121
+
122
+ RCT_EXPORT_METHOD(engage: (NSString *)sdkKey googleProjectId: (NSString *)projectId server:(NSString *)server appID:(NSString *)appID tenantID:(NSString *)tenantID) {
46
123
  SERVER serv = [self getServerKeyFor:server];
47
124
  [[Appoxee shared] engageAndAutoIntegrateWithLaunchOptions:nil andDelegate:[RNMappEventEmmiter shared] with:serv];
48
125
  [[Appoxee shared] addObserver: [RNMappEventEmmiter shared] forKeyPath:@"isReady" options:NSKeyValueObservingOptionNew context:nil];
126
+ [[AppoxeeInapp shared] engageWithDelegate:[RNMappEventEmmiter shared] with:[self getInappServerKeyFor:server]];
49
127
  }
50
128
 
51
- RCT_EXPORT_METHOD(getAlias:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
129
+ RCT_EXPORT_METHOD(getAlias:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
52
130
  [[Appoxee shared] getDeviceAliasWithCompletionHandler:^(NSError * _Nullable appoxeeError, id _Nullable data) {
53
131
  if (appoxeeError == nil && data != nil) {
54
132
  resolve(data);
@@ -58,24 +136,34 @@ RCT_EXPORT_METHOD(getAlias:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseR
58
136
  }];
59
137
  }
60
138
 
61
- RCT_EXPORT_METHOD(setAlias:(NSString *) alias) {
139
+ RCT_EXPORT_METHOD(setAlias:(NSString *) alias resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
62
140
  [[Appoxee shared] setDeviceAlias:alias withCompletionHandler:^(NSError * _Nullable appoxeeError, id _Nullable data) {
63
141
  if (appoxeeError != nil) {
64
- NSLog(@"%@", appoxeeError.debugDescription);
142
+ reject(@"SET_ALIAS_ERROR", @"Failed to set alias", appoxeeError);
143
+ } else {
144
+ resolve(@YES);
65
145
  }
66
146
  }];
67
147
  }
68
148
 
69
- RCT_EXPORT_METHOD(setAliasWithResend:(NSString *) alias withResendAttributes:(BOOL) resendAttributes) {
149
+ RCT_EXPORT_METHOD(setAliasWithResend:(NSString *) alias resendCustomAttributes:(BOOL) resendAttributes resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
70
150
  [[Appoxee shared] setDeviceAlias:alias withResendAttributes:resendAttributes withCompletionHandler:^(NSError * _Nullable appoxeeError, id _Nullable data) {
71
151
  if (appoxeeError != nil) {
72
- NSLog(@"%@", appoxeeError.debugDescription);
152
+ reject(@"SET_ALIAS_ERROR", @"Failed to set alias", appoxeeError);
153
+ } else {
154
+ resolve(@YES);
73
155
  }
74
156
  }];
75
157
  }
76
158
 
77
- RCT_EXPORT_METHOD(setToken:(NSString *) token) {
78
- [[Appoxee shared] didRegisterForRemoteNotificationsWithDeviceToken:[[NSData alloc] initWithBase64EncodedString:token options:NSUTF8StringEncoding]];
159
+ RCT_EXPORT_METHOD(setToken:(NSString *) token resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
160
+ NSData *deviceToken = [[NSData alloc] initWithBase64EncodedString:token options:0];
161
+ if (!deviceToken) {
162
+ reject(@"INVALID_APNS_TOKEN", @"setToken expects a base64-encoded native APNs device token, not an Expo push token", nil);
163
+ return;
164
+ }
165
+ [[Appoxee shared] didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
166
+ resolve(@YES);
79
167
  }
80
168
 
81
169
  RCT_EXPORT_METHOD(removeDeviceAlias) {
@@ -90,11 +178,11 @@ RCT_EXPORT_METHOD(logOut: (BOOL) pushEnabled) {
90
178
  [[Appoxee shared] logoutWithOptin:pushEnabled];
91
179
  }
92
180
 
93
- RCT_EXPORT_METHOD(isReady:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
181
+ RCT_EXPORT_METHOD(isReady:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
94
182
  resolve(@([[Appoxee shared] isReady]));
95
183
  }
96
184
 
97
- RCT_EXPORT_METHOD(isPushEnabled:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
185
+ RCT_EXPORT_METHOD(isPushEnabled:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
98
186
  [[Appoxee shared] isPushEnabled:^(NSError * _Nullable appoxeeError, id _Nullable data) {
99
187
  if (appoxeeError == nil) {
100
188
  resolve(data);
@@ -132,15 +220,17 @@ RCT_EXPORT_METHOD(incrementNumericKey: (NSString *) key value: (NSNumber *) numb
132
220
  }];
133
221
  }
134
222
 
135
- RCT_EXPORT_METHOD(setAttributes: (NSDictionary *)attributes) {
223
+ RCT_EXPORT_METHOD(setAttributes: (NSDictionary *)attributes resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
136
224
  [[Appoxee shared] setCustomAttributtes:attributes withCompletionHandler:^(NSError * _Nullable appoxeeError, id _Nullable data) {
137
225
  if (appoxeeError) {
138
- NSLog(@"%@", appoxeeError.debugDescription);
226
+ reject(@"SET_ATTRIBUTES_ERROR", @"Failed to set attributes", appoxeeError);
227
+ } else {
228
+ resolve(@YES);
139
229
  }
140
230
  }];
141
231
  }
142
232
 
143
- RCT_EXPORT_METHOD(getAttributes: (NSArray *)attributes and:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
233
+ RCT_EXPORT_METHOD(getAttributes: (NSArray *)attributes resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
144
234
  [[Appoxee shared] getCustomAttributes:attributes withCompletionHandler:^(NSError * _Nullable appoxeeError, id _Nullable data) {
145
235
  if (appoxeeError) {
146
236
  NSLog(@"%@", appoxeeError.debugDescription);
@@ -157,8 +247,8 @@ RCT_EXPORT_METHOD(setAttribute: (NSString *)key value: (NSString *) value) {
157
247
  }];
158
248
  }
159
249
 
160
- RCT_EXPORT_METHOD(setAttributeInt: (NSString *)key value: (NSNumber *) value) {
161
- [[Appoxee shared] setNumberValue:value forKey:key withCompletionHandler:^(NSError * _Nullable appoxeeError, id _Nullable data) {
250
+ RCT_EXPORT_METHOD(setAttributeInt: (NSString *)key value: (NSInteger) value) {
251
+ [[Appoxee shared] setNumberValue:@(value) forKey:key withCompletionHandler:^(NSError * _Nullable appoxeeError, id _Nullable data) {
162
252
  if(appoxeeError != nil) {
163
253
  NSLog(@"%@", appoxeeError.debugDescription);
164
254
  }
@@ -181,7 +271,7 @@ RCT_EXPORT_METHOD(addTag: (NSString *) tag) {
181
271
  }];
182
272
  }
183
273
 
184
- RCT_EXPORT_METHOD(getTags:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
274
+ RCT_EXPORT_METHOD(getTags:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
185
275
  [[Appoxee shared] fetchDeviceTags:^(NSError * _Nullable appoxeeError, id _Nullable data) {
186
276
  if (!appoxeeError && [data isKindOfClass:[NSArray class]]) {
187
277
  NSArray *deviceTags = (NSArray *)data;
@@ -192,7 +282,7 @@ RCT_EXPORT_METHOD(getTags:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRe
192
282
  }];
193
283
  }
194
284
 
195
- RCT_EXPORT_METHOD(getDeviceInfo:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
285
+ RCT_EXPORT_METHOD(getDeviceInfo:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
196
286
  [[Appoxee shared] deviceInformationwithCompletionHandler:^(NSError * _Nullable appoxeeError, id _Nullable data) {
197
287
  if (!appoxeeError && [data isKindOfClass:[APXClientDevice class]]) {
198
288
  APXClientDevice *device = (APXClientDevice *)data;
@@ -204,7 +294,7 @@ RCT_EXPORT_METHOD(getDeviceInfo:(RCTPromiseResolveBlock)resolve rejecter:(RCTPro
204
294
  }];
205
295
  }
206
296
 
207
- RCT_EXPORT_METHOD(getAttributeStringValue: (NSString *) key resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
297
+ RCT_EXPORT_METHOD(getAttributeStringValue: (NSString *) key resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
208
298
  [[Appoxee shared] fetchCustomFieldByKey:key withCompletionHandler:^(NSError * _Nullable appoxeeError, id _Nullable data) {
209
299
  NSLog(@"%@", data);
210
300
  if (!appoxeeError && [data isKindOfClass:[NSDictionary class]]) {
@@ -245,23 +335,18 @@ RCT_EXPORT_METHOD(clearNotifications) {
245
335
  [[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications];
246
336
  }
247
337
 
248
- RCT_EXPORT_METHOD(clearNotification: (NSNumber *) index ){
249
- [[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers: @[[index stringValue]]];
338
+ RCT_EXPORT_METHOD(clearNotification: (NSInteger) index ){
339
+ [[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers: @[[NSString stringWithFormat:@"%ld", (long)index]]];
250
340
  }
251
341
 
252
342
  #pragma mark Exported methods - Inapp
253
343
 
254
- RCT_REMAP_METHOD(engageInapp,engageInapp:(NSString *) server) {
255
- INAPPSERVER serv = [self getInappServerKeyFor:server];
256
- [[AppoxeeInapp shared] engageWithDelegate:[RNMappEventEmmiter shared] with:serv];
257
- }
258
-
259
- RCT_EXPORT_METHOD(fetchInboxMessage: (RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
344
+ RCT_EXPORT_METHOD(fetchInboxMessage: (RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
260
345
  [[AppoxeeInapp shared] fetchAPXInBoxMessages];
261
346
  resolve(@"Fetching, set event listener for iOS");
262
347
  }
263
348
 
264
- RCT_EXPORT_METHOD(fetchLatestInboxMessage: (RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
349
+ RCT_EXPORT_METHOD(fetchLatestInboxMessage: (RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
265
350
  [[AppoxeeInapp shared] fetchAPXInBoxMessages];
266
351
  resolve(@"Fetching, set event listener for iOS");
267
352
  }
@@ -270,28 +355,28 @@ RCT_EXPORT_METHOD(triggerInApp: (NSString *) event) {
270
355
  [[AppoxeeInapp shared] reportInteractionEventWithName:event andAttributes:nil];
271
356
  }
272
357
 
273
- RCT_EXPORT_METHOD(inAppMarkAsRead: (NSNumber * _Nonnull) templateId event: (NSString * _Nonnull) eventId) {
274
- APXInBoxMessage *message = [[RNMappEventEmmiter shared] getMessageWith:templateId event:eventId];
358
+ RCT_EXPORT_METHOD(inAppMarkAsRead: (NSInteger) templateId eventId: (NSString * _Nonnull) eventId) {
359
+ APXInBoxMessage *message = [[RNMappEventEmmiter shared] getMessageWith:@(templateId) event:eventId];
275
360
  if (message) {
276
361
  [message markAsRead];
277
362
  }
278
363
  }
279
364
 
280
- RCT_EXPORT_METHOD(inAppMarkAsUnRead: (NSNumber * _Nonnull) templateId event: (NSString * _Nonnull) eventId) {
281
- APXInBoxMessage *message = [[RNMappEventEmmiter shared] getMessageWith:templateId event:eventId];
365
+ RCT_EXPORT_METHOD(inAppMarkAsUnRead: (NSInteger) templateId eventId: (NSString * _Nonnull) eventId) {
366
+ APXInBoxMessage *message = [[RNMappEventEmmiter shared] getMessageWith:@(templateId) event:eventId];
282
367
  if (message) {
283
368
  [message markAsUnread];
284
369
  }
285
370
  }
286
371
 
287
- RCT_EXPORT_METHOD(inAppMarkAsDeleted: (NSNumber * _Nonnull) templateId event: (NSString * _Nonnull) eventId) {
288
- APXInBoxMessage *message = [[RNMappEventEmmiter shared] getMessageWith:templateId event:eventId];
372
+ RCT_EXPORT_METHOD(inAppMarkAsDeleted: (NSInteger) templateId eventId: (NSString * _Nonnull) eventId) {
373
+ APXInBoxMessage *message = [[RNMappEventEmmiter shared] getMessageWith:@(templateId) event:eventId];
289
374
  if (message) {
290
375
  [message markAsDeleted];
291
376
  }
292
377
  }
293
378
 
294
- RCT_EXPORT_METHOD(isDeviceRegistered:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
379
+ RCT_EXPORT_METHOD(isDeviceRegistered:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
295
380
  resolve(@([[Appoxee shared] isReady]));
296
381
  }
297
382
 
@@ -371,4 +456,3 @@ RCT_EXPORT_METHOD(stopGeoFencing) {
371
456
 
372
457
 
373
458
  @end
374
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-mapp-plugin",
3
- "version": "1.4.2",
3
+ "version": "2.0.0-beta.1",
4
4
  "description": "Mapp SDK for React Native.",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -16,10 +16,14 @@
16
16
  "ios/RNMappEventEmmiter.m",
17
17
  "ios/RNMappPlugin.xcodeproj/project.pbxproj",
18
18
  "ios/RNMappPluginModule.h",
19
- "ios/RNMappPluginModule.m",
19
+ "ios/RNMappPluginModule.mm",
20
+ "app.plugin.js",
21
+ "plugin/build/",
20
22
  "android/src/main/jni/",
21
23
  "specs/",
24
+ "BREAKING_CHANGES.md",
22
25
  "CHANGELOG.md",
26
+ "MIGRATION_2.0.md",
23
27
  "CustomEvent.js",
24
28
  "Mapp.js",
25
29
  "MappEventEmitter.js",
@@ -42,24 +46,41 @@
42
46
  "node": ">=20.19.4"
43
47
  },
44
48
  "peerDependencies": {
49
+ "@expo/config-plugins": ">=56.0.0",
45
50
  "react": "^19.2.3",
46
51
  "react-native": ">=0.84"
47
52
  },
53
+ "peerDependenciesMeta": {
54
+ "@expo/config-plugins": {
55
+ "optional": true
56
+ }
57
+ },
58
+ "dependencies": {
59
+ "@expo/plist": "^0.7.0"
60
+ },
48
61
  "devDependencies": {
49
62
  "@babel/preset-env": "^7.29.2",
50
63
  "@babel/preset-flow": "^7.27.1",
64
+ "@expo/config-plugins": "~56.0.14",
51
65
  "@react-native-community/cli": "^20.1.3",
52
- "@react-native/codegen": "0.84.1",
53
- "@react-native/gradle-plugin": "0.84.1",
66
+ "@react-native/codegen": "0.85.3",
67
+ "@react-native/gradle-plugin": "0.85.3",
68
+ "@types/jest": "^30.0.0",
69
+ "@types/node": "^24.13.3",
54
70
  "babel-jest": "^30.3.0",
55
71
  "jest": "^30.2.0",
56
72
  "react": "19.2.4",
57
- "react-native": "0.84.1"
73
+ "react-native": "0.85.3",
74
+ "ts-jest": "^29.4.12",
75
+ "typescript": "^6.0.3"
58
76
  },
59
77
  "scripts": {
78
+ "build:plugin": "tsc -p plugin/tsconfig.json",
79
+ "test:plugin": "jest --runInBand plugin/__tests__",
60
80
  "generate:codegen": "react-native codegen specs",
61
81
  "build:android": "cd android && ./gradlew assembleDebug",
62
- "test": "jest"
82
+ "test": "jest",
83
+ "prepare": "npm run build:plugin"
63
84
  },
64
85
  "codegenConfig": {
65
86
  "name": "RNMappPlugin",
@@ -73,10 +94,12 @@
73
94
  "jest": {
74
95
  "testEnvironment": "node",
75
96
  "testMatch": [
76
- "**/__tests__/**/*.test.js"
97
+ "**/__tests__/**/*.test.js",
98
+ "**/plugin/__tests__/**/*.test.ts"
77
99
  ],
78
100
  "transform": {
79
- "^.+\\.js$": "babel-jest"
101
+ "^.+\\.js$": "babel-jest",
102
+ "^.+\\.ts$": ["ts-jest", { "tsconfig": "plugin/tsconfig.json" }]
80
103
  },
81
104
  "moduleNameMapper": {
82
105
  "^react-native$": "<rootDir>/__mocks__/react-native.js"
@@ -0,0 +1,4 @@
1
+ import { ConfigPlugin } from '@expo/config-plugins';
2
+ import type { NormalizedMappExpoPluginProps } from './types';
3
+ export declare function updatePushHandling(androidManifest: any, pushHandling: NormalizedMappExpoPluginProps['android']['pushHandling']): any;
4
+ export declare const withMappEngageAndroid: ConfigPlugin<NormalizedMappExpoPluginProps['android']>;