reactnative-plugin-appice 1.7.43 → 1.7.45

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.
@@ -7,10 +7,13 @@
7
7
  #import <UserNotifications/UserNotifications.h>
8
8
  #import "Campaign.h"
9
9
  #import "TransactionalCampaign.h"
10
+ #import "AppICEConstantsPrivate.h"
10
11
  @implementation AppIceReactPlugin
11
12
 
12
13
  static BOOL isAppInitialized = NO;
13
14
  static NSDictionary *pendingDeeplink = nil;
15
+ static UNNotificationResponse *pendingDeeplinkResponse = nil;
16
+ static NSString *pendingSelectedAction = nil;
14
17
 
15
18
  RCT_EXPORT_MODULE()
16
19
  + (BOOL)requiresMainQueueSetup {
@@ -36,30 +39,32 @@ RCT_EXPORT_MODULE()
36
39
  return @{
37
40
  kAppICEPushNotificationClicked : kAppICEPushNotificationClicked,
38
41
  kAppICEInAppClicked : kAppICEInAppClicked,
39
- kn : @"n",
40
- kem : @"e",
41
- kph : @"p",
42
- ka : @"a",
43
- kg : @"g",
44
- ked : @"edt",
45
- ket : @"emt",
46
- km : @"m",
47
- kis_emp : @"em",
48
- kdob: @"d",
42
+ kAppICEPushNotificationActionButtonClicked : kAppICEPushNotificationActionButtonClicked,
43
+ kAppICEHTMLInAppClicked:kAppICEHTMLInAppClicked,
44
+ kn : NAME,
45
+ kem : EMAIL,
46
+ kph : PHONE,
47
+ ka : AGE,
48
+ kg : GENDER,
49
+ ked : EDUCATIONTYPE,
50
+ ket : EMPLOYMENTTYPE,
51
+ km : ISMARRIED,
52
+ kis_emp : ISEMPLOYED,
53
+ kdob: D,
49
54
 
50
- INBOX_MESSAGE : @"message",
51
- INBOX_TITLE : @"title",
52
- INBOX_MESSAGE_STATUS : @"messageStatus",
53
- INBOX_CAMPAIGN_TYPE : @"campType",
54
- INBOX_MESSAGE_LANGUAGE : @"messageLanguage",
55
- INBOX_MESSAGE_ID : @"id",
56
- INBOX_CAMPAIGN_ID : @"campId",
57
- INBOX_MESSAGE_CATEGORY : @"category",
58
- INBOX_MESSAGE_ICON : @"icon",
59
- INBOX_CUSTOM_DATA : @"cdata",
60
- INBOX_MESSAGE_EXPANDED_IMAGE :@"eni",
55
+ INBOX_MESSAGE : MESSAGE,
56
+ INBOX_TITLE : TITLE,
57
+ INBOX_MESSAGE_STATUS : MESSAGESTATUS,
58
+ INBOX_CAMPAIGN_TYPE : CAMPTYPE,
59
+ INBOX_MESSAGE_LANGUAGE : MESSAGELANGUAGE,
60
+ INBOX_MESSAGE_ID : CAMPAIGN_ID,
61
+ INBOX_CAMPAIGN_ID : CAMPAIGNID,
62
+ INBOX_MESSAGE_CATEGORY : CATEGORY,
63
+ INBOX_MESSAGE_ICON : ICON,
64
+ INBOX_CUSTOM_DATA : CDATA,
65
+ INBOX_MESSAGE_EXPANDED_IMAGE :ENI,
61
66
 
62
- DEMOGRAPHIC_INFO :@"customProperties",
67
+ DEMOGRAPHIC_INFO :DEMOGRAPHIC_INFO,
63
68
  @"TOP_N_PRODUCTS_VIEWED" : TOP_N_PRODUCTS_VIEWED,
64
69
  @"N_COMPLAINTS_RAISED" : N_COMPLAINTS_RAISED,
65
70
  @"PREF_LOGIN_DEVICE" : PREF_LOGIN_DEVICE,
@@ -77,10 +82,15 @@ RCT_EXPORT_MODULE()
77
82
  @"AVERAGE_TRANSACTION_AMOUNT" : AVERAGE_TRANSACTION_AMOUNT,
78
83
  @"FREQUENCY_OF_TRANSACTION": FREQUENCY_OF_TRANSACTION,
79
84
  @"TYPE_OF_TRANSACTION" : TYPE_OF_TRANSACTION,
80
- CAMP_ID : @"campId",
81
- ACTION_URL : @"actionUrl",
82
- ACTION_TYPE: @"actionType",
83
- CUSTOMDATA : @"customData"
85
+ CAMP_ID : CAMPAIGNID,
86
+ ACTION_URL : ACTIONURL,
87
+ ACTION_TYPE: ACTIONTYPE,
88
+ CUSTOMDATA : CUSTOMDATA,
89
+
90
+ ACTION_TYPE_CUSTOM: CUS,
91
+ ACTION_TYPE_DEEPLINK: DL,
92
+ ACTION_TYPE_REPLY: RLY,
93
+ ACTION_TYPE_REMIND_ME_LATER: RML
84
94
  };
85
95
  }
86
96
  - (dispatch_queue_t)methodQueue {
@@ -113,6 +123,7 @@ RCT_EXPORT_METHOD(startContext:(NSString *)appID
113
123
  [[NSUserDefaults standardUserDefaults] removeObjectForKey:kappICEToken];
114
124
  }
115
125
  [self setClickCallback];
126
+ [self setHTMLInAppClickListener];
116
127
  }
117
128
 
118
129
  /**
@@ -248,26 +259,13 @@ RCT_EXPORT_METHOD(setUser:(NSDictionary*)userProfile)
248
259
  * when Called in killed state isAppInitialized will be false and deeplink is stored and will be handled after the App is initialized.
249
260
  ===========================*/
250
261
 
251
- + (void)pushNotificationClicked:(NSDictionary *)userInfo {
252
- @try {
253
-
254
- if (!isAppInitialized) {
255
- RCTLog(@"Deeplink Push : not isAppInitialized" );
256
- // App is not initialized, store the deeplink for later processing
257
- [self storePendingDeeplink:userInfo];
258
- } else {
259
- // App is initialized, handle deeplinks in the click handler
260
- RCTLog(@"Deeplink Push : pushNotificationClicked deeplink handled" );
261
- [self storePendingDeeplink:userInfo];
262
- [self processPendingDeeplink];
262
+ + (void)pushNotificationClicked:(id)response {
263
+ @try {
264
+ [self storePendingDeeplink:response];
265
+ [self processPendingDeeplink]; // processPendingDeeplink itself enforces init rules
266
+ } @catch (NSException *exception) {
267
+ RCTLog(@"Deeplink Push : pushNotificationClicked exception %@", exception);
263
268
  }
264
-
265
- NSDictionary *event = @{ kAppICEPushNotificationClicked : userInfo};
266
- [[NSNotificationCenter defaultCenter] postNotificationName:kAppICEPushNotificationClicked object:nil userInfo:event];
267
- } @catch (NSException *exception) {
268
- RCTLog(@"Deeplink Push : pushNotificationClicked exception %@",exception);
269
- }
270
-
271
269
  }
272
270
 
273
271
  RCT_EXPORT_METHOD(inAppClicked:(NSDictionary*)userInfo)
@@ -295,6 +293,24 @@ RCT_EXPORT_METHOD(inAppClicked:(NSDictionary*)userInfo)
295
293
  }];
296
294
 
297
295
  }
296
+
297
+ /**
298
+
299
+ Registers a listener for HTML In-App campaign click events.
300
+ This method listens for HTML In-App click actions from the AppICE SDK.
301
+
302
+ * Convert campaign object into dictionary format
303
+ * Post notification with campaign data
304
+
305
+ */
306
+ - (void)setHTMLInAppClickListener
307
+ {
308
+ [[appICE sharedInstance] handleHTMLInAppClickListener:^(Campaign * _Nullable campaign) {
309
+ NSDictionary *cData = campaign ? [campaign toDictionary] : @{};
310
+ RCTLog(@"***** HTML INapp click *** %@", cData);
311
+ [[NSNotificationCenter defaultCenter] postNotificationName:kAppICEHTMLInAppClicked object:nil userInfo:cData];
312
+ }];
313
+ }
298
314
  RCT_EXPORT_METHOD(setInternalId:(NSString*) internalId)
299
315
  {
300
316
  [[appICE sharedInstance] setInternalId:internalId];
@@ -542,34 +558,129 @@ RCT_EXPORT_METHOD(getMediaThumbnail:(NSDictionary *)inboxMessageDict mediaData:(
542
558
  * @param userInfo - NSDictionary
543
559
  * Store the pending deeplink info in the static variable for later processing
544
560
  -----------------------------------------------------------------------------*/
545
- + (void)storePendingDeeplink:(NSDictionary *)userInfo {
561
+ + (void)storePendingDeeplink:(id)response {
546
562
  @try {
547
- // Store the pending deeplink info in the static variable for later processing
548
- pendingDeeplink = userInfo;
549
- RCTLog(@"Deeplink Push : storePendingDeeplink called" );
563
+ // Store the pending deeplink info in the static variable for later processing
564
+ // Old flow: NSDictionary userInfo
565
+ if ([response isKindOfClass:[NSDictionary class]]) {
566
+ // Old flow
567
+ pendingDeeplink = (NSDictionary *)response;
568
+ pendingDeeplinkResponse = nil;
569
+ pendingSelectedAction = nil;
570
+ RCTLog(@"Deeplink Push : storePendingDeeplink old flow pendingDeeplink: %@", pendingDeeplink);
571
+ return;
572
+ }
573
+ if ([response isKindOfClass:[UNNotificationResponse class]]) {
574
+ // New flow
575
+ pendingDeeplinkResponse = (UNNotificationResponse *)response;
576
+ pendingDeeplink = pendingDeeplinkResponse.notification.request.content.userInfo;
577
+ pendingSelectedAction = [self resolvedActFromResponse:pendingDeeplinkResponse];
578
+ RCTLog(@"Deeplink Push : storePendingDeeplink selectedAct: %@ actionIdentifier: %@",
579
+ pendingSelectedAction, pendingDeeplinkResponse.actionIdentifier);
580
+ return;
581
+ }
582
+ pendingDeeplink = nil;
583
+ pendingDeeplinkResponse = nil;
584
+ pendingSelectedAction = nil;
550
585
  } @catch (NSException *exception) {
551
586
  RCTLog(@"Deeplink Push : storePendingDeeplink exception %@",exception);
552
587
  }
553
588
  }
554
589
 
590
+ + (NSString *)resolvedActFromResponse:(UNNotificationResponse *)response {
591
+ // Maps iOS actionIdentifier -> payload action "act" value for routing.
592
+ if (![response isKindOfClass:[UNNotificationResponse class]]) return @"";
593
+
594
+ NSString *identifier = response.actionIdentifier ?: @"";
595
+ if ([identifier isEqualToString:UNNotificationDefaultActionIdentifier]) {
596
+ return DEFAULT;
597
+ }
598
+ NSDictionary *userInfo = response.notification.request.content.userInfo;
599
+ NSDictionary *message = userInfo[DATA][MESSAGE];
600
+ NSArray *actions = [message[ACTIONS] isKindOfClass:[NSArray class]] ? message[ACTIONS] : @[];
601
+ for (id a in actions) {
602
+ if (![a isKindOfClass:[NSDictionary class]]) continue;
603
+ NSDictionary *action = (NSDictionary *)a;
604
+ NSString *abt = [action[ABT] isKindOfClass:[NSString class]] ? action[ABT] : @"";
605
+ NSString *act = [action[ACT] isKindOfClass:[NSString class]] ? action[ACT] : @"";
606
+ if ([abt caseInsensitiveCompare:identifier] == NSOrderedSame) {
607
+ return act.lowercaseString;
608
+ }
609
+ }
610
+ // fallback: if identifier itself equals act
611
+ NSString *idLower = identifier.lowercaseString;
612
+ for (id a in actions) {
613
+ if (![a isKindOfClass:[NSDictionary class]]) continue;
614
+ NSString *act = [a[ACT] isKindOfClass:[NSString class]] ? [a[ACT] lowercaseString] : @"";
615
+ if ([act isEqualToString:idLower]) return act;
616
+ }
617
+ return @""; // unknown action
618
+ }
619
+
555
620
  /*----------------------------------------------------------------------------
556
621
  processPendingDeeplink
557
622
  * Process the pending deeplink if it exists and the app is initialized
623
+ * Flow A: Legacy wrapper input (NSDictionary userInfo).
624
+ Behavior is unchanged: process only after React/SDK initialization.
625
+ * Flow B: New wrapper input (UNNotificationResponse).
626
+ Routing is based on resolved payload action type.
627
+ 1. Normal push click (default action) -> preserve old behavior.
628
+ 2. RML/RLY/DIS action buttons -> allow kill/background processing path.
629
+ 3. Other action buttons -> process only after initialization.
558
630
  * Clear the pending deeplink after processing
559
631
  -----------------------------------------------------------------------------*/
560
632
  + (void)processPendingDeeplink {
561
633
  @try {
562
-
563
- RCTLog(@"Deeplink Push : processPendingDeeplink called isAppInitialized: %d , pendingDeeplink: %@",isAppInitialized,pendingDeeplink);
564
- if (isAppInitialized && pendingDeeplink) {
565
- RCTLog(@"Deeplink Push : handled in stored data");
566
- [[appICE sharedInstance] handleClickOnPush:pendingDeeplink OpenDeepLink:YES];
567
- pendingDeeplink = nil;
568
- }
634
+ BOOL didProcess = NO;
635
+ //Flow A
636
+ if (pendingDeeplink && !pendingDeeplinkResponse) {
637
+ if (isAppInitialized) {
638
+ [[appICE sharedInstance] handleClickOnPush:pendingDeeplink OpenDeepLink:YES];
639
+ NSDictionary *event = @{ kAppICEPushNotificationClicked : pendingDeeplink };
640
+ [[NSNotificationCenter defaultCenter] postNotificationName:kAppICEPushNotificationClicked
641
+ object:nil
642
+ userInfo:event];
643
+ didProcess = YES;
644
+ }
645
+ }
646
+ // Flow B:
647
+ if (!didProcess && pendingDeeplinkResponse) {
648
+ NSString *act = (pendingSelectedAction ?: @"").lowercaseString;
649
+ // B1) Normal push click (default action) -> preserve old behavior.
650
+ if ([act isEqualToString:DEFAULT]) {
651
+ if (isAppInitialized && pendingDeeplink) {
652
+ [[appICE sharedInstance] handleClickOnPush:pendingDeeplink OpenDeepLink:YES];
653
+ NSDictionary *event = @{ kAppICEPushNotificationClicked : pendingDeeplink };
654
+ [[NSNotificationCenter defaultCenter] postNotificationName:kAppICEPushNotificationClicked
655
+ object:nil
656
+ userInfo:event];
657
+ didProcess = YES;
658
+ }
659
+ }
660
+ // B2) RML/RLY/DIS action buttons -> allow kill/background processing path.
661
+ else if ([act isEqualToString:RML] ||
662
+ [act isEqualToString:RLY] ||
663
+ [act isEqualToString:DIS]) {
664
+ [self handlePush:pendingDeeplinkResponse openDeepLink:YES];
665
+ didProcess = YES;
666
+ }
667
+ // B3) Other action buttons -> process only after initialization.
668
+ else {
669
+ if (isAppInitialized) {
670
+ [self handlePush:pendingDeeplinkResponse openDeepLink:YES];
671
+ didProcess = YES;
672
+ }
673
+ }
674
+ }
675
+ if (didProcess) {
676
+ pendingDeeplink = nil;
677
+ pendingDeeplinkResponse = nil;
678
+ pendingSelectedAction = nil;
679
+ RCTLog(@"Deeplink Push : pending cleared");
680
+ }
569
681
  } @catch (NSException *exception) {
570
682
  RCTLog(@"Deeplink Push : processPendingDeeplink exception %@",exception);
571
683
  } @finally {
572
- pendingDeeplink = nil;
573
684
  RCTLog(@"Deeplink Push : finally processPendingDeeplink pendingDeeplink set as nil");
574
685
  }
575
686
 
@@ -628,7 +739,7 @@ RCT_EXPORT_METHOD(getUserForIds:(NSArray*)userIds callback:(RCTResponseSenderBlo
628
739
  NSDictionary *formattedMessage = [getUserData toDictionary];
629
740
  [formattedGetUser addObject:formattedMessage];
630
741
  }
631
- NSLog(@"[getUserDetails]: Formatted getUser Messages: %@", formattedGetUser);
742
+ RCTLog(@"[getUserDetails]: Formatted getUser Messages: %@", formattedGetUser);
632
743
  [self returnResult:formattedGetUser withCallback:callback andError:nil];
633
744
 
634
745
  }
@@ -647,7 +758,7 @@ RCT_EXPORT_METHOD(getCampaigns:(NSString *)type callback:(RCTResponseSenderBlock
647
758
 
648
759
  for (Campaign *campaign in campaigns) {
649
760
  NSDictionary *formatedCampaign = campaign.toDictionary;
650
- NSLog(@"Campaign: Formatted getCampaigns: %@", formatedCampaign);
761
+ RCTLog(@"Campaign: Formatted getCampaigns: %@", formatedCampaign);
651
762
  [formattedCampaigns addObject:formatedCampaign];
652
763
  }
653
764
  [self returnResult:formattedCampaigns withCallback:callback andError:nil];
@@ -721,7 +832,54 @@ RCT_EXPORT_METHOD(scheduleTransactionalCampaign:(NSString *)payloadJson)
721
832
  [[appICE sharedInstance] scheduleCampaign:tCampaign];
722
833
  }
723
834
  } @catch (NSException *exception) {
724
-
835
+
836
+ }
837
+ }
838
+
839
+ #pragma mark - In-app display state
840
+
841
+ // React Native API to resume in-app rendering after it was paused/suspended.
842
+ RCT_EXPORT_METHOD(resumeInApp)
843
+ {
844
+ [[appICE sharedInstance] resumeInApp];
845
+ }
846
+
847
+ // React Native API to temporarily suspend in-app rendering.
848
+ RCT_EXPORT_METHOD(suspendInApp)
849
+ {
850
+ [[appICE sharedInstance] suspendInApp];
851
+ }
852
+
853
+ // React Native API to discard queued or active in-app state.
854
+ RCT_EXPORT_METHOD(discardInApp)
855
+ {
856
+ [[appICE sharedInstance] discardInApp];
857
+ }
858
+
859
+ // React Native API to dismiss the currently visible in-app.
860
+ RCT_EXPORT_METHOD(dismissInApp)
861
+ {
862
+ [[appICE sharedInstance] dismissInApp];
863
+ }
864
+
865
+ // Handles push click responses from app delegate paths, including kill-state/cold-start handoff.
866
+ // Emits `kAppICEPushNotificationActionButtonClicked` with campaign payload for JS listeners.
867
+ +(void)handlePush:(id)response openDeepLink:(BOOL)openDeepLink {
868
+ @try {
869
+ RCTLog(@"handlePushFromAppDelegate: Entered are");
870
+ [[appICE sharedInstance] pushNotificationClicked:response openDeepLink:openDeepLink];
871
+ Campaign *campaign = [[appICE sharedInstance] handleClickCallback:response];
872
+
873
+ NSDictionary *campaignDict = campaign ? [campaign toDictionary] : @{};
874
+ RCTLog(@"handlePushFromAppDelegate: Campaign data: %@", campaignDict);
875
+
876
+ // Post an event with the campaign data so JS can process it.
877
+ NSDictionary *event = @{ kAppICEPushNotificationActionButtonClicked : campaignDict };
878
+ [[NSNotificationCenter defaultCenter] postNotificationName:kAppICEPushNotificationActionButtonClicked
879
+ object:nil
880
+ userInfo:event];
881
+ } @catch (NSException *exception) {
882
+ RCTLog(@"handlePushFromAppDelegate exception: %@", exception);
725
883
  }
726
884
  }
727
885
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reactnative-plugin-appice",
3
- "version": "1.7.43",
3
+ "version": "1.7.45",
4
4
  "description": "appICE React Native SDK",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -9,6 +9,7 @@
9
9
  "android",
10
10
  "index.js",
11
11
  "campaign.js",
12
+ "TransactionalCampaign.js",
12
13
  "ios",
13
14
  "reactnative-plugin-appice.podspec"
14
15
  ],
@@ -23,7 +23,7 @@ Pod::Spec.new do |s|
23
23
  s.requires_arc = true
24
24
 
25
25
  s.dependency "React"
26
- s.dependency "AppICE-IOS-SDK", "1.8.20"
26
+ s.dependency "AppICE-IOS-SDK", "1.8.23"
27
27
  # ...
28
28
  # s.dependency "..."
29
29
  end
File without changes
File without changes