reactnative-plugin-appice 1.7.47 → 1.7.49

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.
@@ -97,7 +97,7 @@ dependencies {
97
97
  annotationProcessor "androidx.lifecycle:lifecycle-compiler:2.3.1"
98
98
 
99
99
  //appice
100
- implementation "appice.io.android:sdk:2.6.44"
100
+ implementation "appice.io.android:sdk:2.6.46"
101
101
 
102
102
  //glide
103
103
  implementation "com.github.bumptech.glide:glide:4.11.0"
@@ -97,15 +97,6 @@
97
97
  android:permission="android.permission.BIND_JOB_SERVICE">
98
98
  </service>
99
99
 
100
- <receiver
101
- android:protectionLevel="signature"
102
- android:name="semusi.context.ui.Carousel.CarouselEventReceiver"
103
- android:exported="false">
104
- <intent-filter>
105
- <action android:name="io.appice.CAROUSELNOTIFICATIONFIRED" />
106
- </intent-filter>
107
- </receiver>
108
-
109
100
  <receiver
110
101
  android:name="semusi.ruleengine.pushmanager.AppICEMessageHandler"
111
102
  android:exported="true"
@@ -3,6 +3,8 @@ package com.appice.react;
3
3
  import static com.appice.react.AppIceReactPluginModule.isDeviceReadyFlag;
4
4
  import static com.appice.react.AppIceReactPluginModule.pendingEventQueue;
5
5
 
6
+ import static semusi.ruleengine.pushmanager.NotificationClickHandler.K_PAYLOAD;
7
+
6
8
  import android.content.Context;
7
9
  import android.content.Intent;
8
10
  import android.os.Bundle;
@@ -56,6 +58,8 @@ public class AppICEUtils {
56
58
  }
57
59
 
58
60
 
61
+ // removed old logic that became overcomplicated with AI. later on when I reworked think
62
+ //of using different approach which flushevent when flag got updated
59
63
  protected static void flushEventQueue(ReactApplicationContext ctx) {
60
64
  if (!isDeviceReadyFlag || pendingEventQueue.isEmpty()) {
61
65
  printLog("ActionPushDebug flushEventQueue", "Nothing to flush. flag=" + isDeviceReadyFlag + " queueSize=" + pendingEventQueue.size());
@@ -513,118 +517,101 @@ public class AppICEUtils {
513
517
  }
514
518
  }
515
519
 
520
+ // this function will handle both normal push and action button push.
521
+ // through listner user will identify.
516
522
  public static void handleClickOnPush(Intent intent, Context context) {
517
- try {
518
- if (intent != null) {
519
- if (intent.getExtras() != null) {
520
- Bundle bundle = intent.getExtras();
521
- if (bundle != null) {
522
-
523
- NotificationClickHandler pushClickData = NotificationClickHandler.fromBundle(bundle);
524
- String payload = pushClickData.getPayload();
525
-
526
- int pos = bundle.getInt("pos", -1);
527
- int notificationId = bundle.getInt("n", 0);
528
-
529
- if (pos == -1) {
530
- CampaignCampsReceiver campsReceiver = new CampaignCampsReceiver();
531
- campsReceiver.sendCallback(bundle, context);
532
- intent.removeExtra("pos");
533
- } else {
534
- handleActionClick(payload, notificationId, intent, pushClickData, pos, context);
535
- }
536
- }else
537
- printLog("ActionPushDebug", " | bundle is null ");
538
- }
539
- } else
540
- printLog("ActionPushDebug", " | intent is null ");
541
- } catch (Throwable e) {
542
- printLog("ActionPushDebug"," | exception in null ");
523
+ if (intent == null) {
524
+ printLog("ActionPushDebug", "Intent is null");
525
+ return;
543
526
  }
544
- }
545
527
 
546
- private static void handleActionClick(String aiContent, int notificationId, Intent intent, NotificationClickHandler pushClickData, int pos, Context context) {
547
- if (aiContent == null || aiContent.isEmpty()) {
528
+ Bundle bundle = intent.getExtras();
529
+ if (bundle == null) {
530
+ printLog("ActionPushDebug", "Bundle is null");
548
531
  return;
549
532
  }
533
+
534
+ NotificationClickHandler pushClickData = null;
535
+
550
536
  try {
551
- JSONObject payloadJson = new JSONObject(aiContent);
552
- payloadJson.put("notificationId", notificationId);
553
- payloadJson.put("selectedIndex", pos);
554
- Campaign campaign = ContextSdk.handlePush(payloadJson.toString(), context);
555
- Action selectedAction = campaign != null ? campaign.getSelectedAction() : null;
556
- if (selectedAction != null) {
557
- payloadJson.put("selectedAction", selectedAction.toJson());
558
- } else {
559
- ContextSdk.pushNotificationClicked(payloadJson.toString(), context);
537
+ pushClickData = NotificationClickHandler.fromBundle(bundle);
538
+ String payload = pushClickData.getPayload();
539
+
540
+ if (!Utility.isValidObject(payload)) {
541
+ return;
560
542
  }
561
- handleCampaignAction(campaign,context);
562
- pushClickData.deleteKeyFromIntent(intent, NotificationClickHandler.K_PAYLOAD);
563
- } catch (Exception e) {
564
- printLog("ActionPushDebug","Action button: action click failed - " + e.getMessage());
565
- }
566
- }
567
543
 
568
- private static void handleCampaignAction(Campaign campaign, Context context) {
569
- if (campaign == null) {
570
- printLog("ActionPushDebug","Action button: campaign is null");
571
- return;
572
- }
544
+ JSONObject payloadJson = new JSONObject(payload);
545
+ int pos = bundle.getInt("pos", -1);
546
+ int notificationId = bundle.getInt("n", -1);
573
547
 
574
- try {
575
- Action selectedAction = campaign.getSelectedAction();
576
- if (selectedAction == null) {
577
- printLog("ActionPushDebug","Action button: selectedAction is null");
548
+ // Notification body click
549
+ if (pos == -1) {
550
+ if (ContextSdk.isPayloadHaveExternalUrl(payload)) {
551
+ ContextSdk.pushNotificationClicked(payload, context);
552
+ ContextSdk.handleExternalUrl(payload, context);
553
+ return;
554
+ }
555
+
556
+ CampaignCampsReceiver campsReceiver = new CampaignCampsReceiver();
557
+ campsReceiver.sendCallback(bundle, context);
578
558
  return;
579
559
  }
580
- String actionType = selectedAction.getActionType() != null ? selectedAction.getActionType().toLowerCase(Locale.ROOT) : null;
581
- String actionContent = selectedAction.getActionContent();
582
- String actionTitle = selectedAction.getActionTitle();
583
- String actionURL = selectedAction.getActionUrl();
584
560
 
585
- printLog("ActionPushDebug","Action button clicked - type: " + actionType + ", title: " + actionTitle);
561
+ // Notification action button click
562
+ if (notificationId >= 0) {
563
+ payloadJson.put("notificationId", notificationId);
564
+ }
565
+ payloadJson.put("selectedIndex", pos);
566
+
567
+ Campaign campaign = ContextSdk.handlePush(payloadJson.toString(), context);
586
568
 
587
- if (actionType == null) {
588
- printLog("ActionPushDebug","Action button: action type is null");
569
+ if (campaign == null) {
589
570
  return;
590
571
  }
591
572
 
592
- switch (actionType) {
593
- case "lp":
594
- Utility.openExternalLinkUrl(actionURL, context);
595
- break;
596
- case "dl":
597
- Utility.openDeepLinkUrl(actionURL, context);
598
- break;
599
- case "cp":
600
- ContextSdk.copyToClipboard(actionContent, context);
601
- break;
602
- case "sh":
603
- ContextSdk.shareActionContent(actionContent, actionContent, context);
604
- break;
605
- case "cus":
606
- WritableMap params = Arguments.createMap();
607
- JSONObject campaignJson = campaign.toJson();
608
- if (campaignJson != null && campaignJson.length() > 0) {
609
- String campaignStr = campaignJson.toString();
610
- params.putString(EnumConstants.APPICE_PUSH_NOTIFICATION_ACTION_BUTTON_CLICKED.getValue(), campaignStr);
611
-
612
- printLog("ActionPushDebug onActionButtonClicked", "action button clicked | campaign: " + campaignStr);
613
- printLog("ActionPushDebug onActionButtonClicked", "isDeviceReadyFlag: " + isDeviceReadyFlag);
614
- printLog("ActionPushDebug onActionButtonClicked", "queue size before send: " + pendingEventQueue.size());
615
- AppIceReactPluginModule.sendEvent(EnumConstants.APPICE_PUSH_NOTIFICATION_ACTION_BUTTON_CLICKED.getValue(), params);
616
- printLog("ActionPushDebug onActionButtonClicked", "queue size after send: " + pendingEventQueue.size());
617
- } else {
618
- printLog("ActionPushDebug onActionButtonClicked", "campaignJson is null or empty — event NOT sent");
619
- }
620
- break;
621
- default:
622
- printLog("ActionPushDebug","Action button: unknown action type - " + actionType);
623
- break;
573
+ Action action = campaign.getSelectedAction();
574
+ if (action == null) {
575
+ return;
576
+ }
577
+
578
+ String type = action.getActionType();
579
+
580
+ if (Utility.isValidObject(type) && (type.equalsIgnoreCase("lp") || type.equalsIgnoreCase("dl"))) {
581
+ Map<String, Object> map = new HashMap<>();
582
+ map.put("campid", campaign.getCampId());
583
+ map.put("abt", action.getActionTitle());
584
+ map.put("mid", campaign.getMessageId());
585
+ ContextSdk.tagEventObj("Campaign_Clicked", map, context);
586
+
587
+ if (type.equalsIgnoreCase("lp")) {
588
+ Utility.openExternalLinkUrl(action.getActionUrl(), context);
589
+ } else {
590
+ Utility.openDeepLinkUrl(action.getActionUrl(), context);
591
+ }
592
+ return;
624
593
  }
625
594
 
595
+ WritableMap params = Arguments.createMap();
596
+ String campaignStr = campaign.toJson().toString();
597
+
598
+ params.putString(EnumConstants.APPICE_PUSH_NOTIFICATION_ACTION_BUTTON_CLICKED.getValue(), campaignStr);
599
+
600
+ printLog("ActionPushDebug onActionButtonClicked", "action button clicked | campaign: " + campaignStr);
601
+ printLog("ActionPushDebug onActionButtonClicked", "isDeviceReadyFlag: " + isDeviceReadyFlag);
602
+ printLog("ActionPushDebug onActionButtonClicked", "queue size before send: " + pendingEventQueue.size());
603
+
604
+ AppIceReactPluginModule.sendEvent(EnumConstants.APPICE_PUSH_NOTIFICATION_ACTION_BUTTON_CLICKED.getValue(), params);
605
+
606
+ printLog("ActionPushDebug onActionButtonClicked", "queue size after send: " + pendingEventQueue.size());
607
+
626
608
  } catch (Exception e) {
627
- printLog("ActionPushDebug","Action button: handleCampaignAction failed - " + e.getMessage());
609
+ printLog("ActionPushDebug","Notification click handling failed: " + e.getMessage());
610
+ } finally {
611
+ // Executes even when an earlier branch returns.
612
+ if (pushClickData != null) {
613
+ pushClickData.deleteKeyFromIntent(intent, K_PAYLOAD);
614
+ }
628
615
  }
629
616
  }
630
- }
617
+ }
@@ -46,9 +46,7 @@ public class CampaignCampsReceiver extends BroadcastReceiver {
46
46
  }
47
47
  }
48
48
  printLog("CampaignEvent |","sendCallback |isHTMLInApp "+isHTMLInApp+"| campaignStr "+campaignStr);
49
-
50
49
  if (isHTMLInApp){
51
-
52
50
  if (Utility.isValidObject(campaignStr)) {
53
51
  WritableMap params = Arguments.createMap();
54
52
  params.putString(EnumConstants.APPICE_HTML_INAPP_NOTIFICATION_CLICKED.getValue(), campaignStr);
package/campaign.js CHANGED
@@ -1,39 +1,11 @@
1
- const { Linking, Platform } = require('react-native');
2
1
 
3
- async function handleClickOnPush(campaign) {
4
- if (campaign && campaign._data) {
5
- campaign = campaign._data;
6
- }
7
-
8
- const url = campaign.actionUrl || campaign.acu || campaign.eurl;
9
- const actionType = campaign.actionType || campaign.act || campaign.et;
10
-
11
- if (!url || typeof url !== 'string') {
12
- console.log('Error: URL is not provided.');
13
- return;
14
- }
15
-
16
- const httpUrls = url.startsWith('http://') || url.startsWith('https://');
17
-
18
- if (httpUrls) {
19
- try {
20
- if (Platform.OS === 'ios') {
21
- campaign = normalizeCampaignPayloadForPlatform(campaign);
22
- return campaign;
23
- // iOS handle redirection on native side for landing page.
24
- }
25
-
26
- await Linking.openURL(url);
27
- console.log(`Successfully opened URL: ${url}`);
28
- } catch (error) {
29
- console.log('Error while opening URL:', error?.message || error);
30
- }
31
- }
2
+ const { Platform } = require('react-native');
32
3
 
33
- if (actionType === 'dl' && !httpUrls) {
34
- // handle custom deeplink
4
+ async function handleClickOnPush(campaign) {
5
+ // not removing this fucntion, as UBI is using it for IOS and IOS was returning campaign class object without checking anything
6
+ campaign = normalizeCampaignPayloadForPlatform(campaign);
35
7
  return campaign;
36
- }
8
+
37
9
  }
38
10
 
39
11
 
@@ -73,7 +45,7 @@ class Campaign {
73
45
  // if parse fails, keep eventData as-is (object expected)
74
46
  data = eventData || {};
75
47
  }
76
-
48
+
77
49
  // Keep app-side listener thin by normalizing payload shape in campaign layer.
78
50
  data = normalizeCampaignPayloadForPlatform(data);
79
51
  const isLegacy = data && (data.camp_id || data.eurl || data.et || data.abt || data.act || data.acc);
@@ -81,6 +53,7 @@ class Campaign {
81
53
  if (isLegacy) {
82
54
  // Map legacy fields into _data in a normalized way
83
55
  this._data.campId = data.campId || data.camp_id || '';
56
+ this._data.mid = data.mid || '';
84
57
  this._data.actionType = data.actionType || data.et || data.act || '';
85
58
  this._data.actionUrl = data.actionUrl || data.eurl || data.acu || '';
86
59
  this._data.actionContent = data.actionContent || data.acc || '';
@@ -94,8 +67,9 @@ class Campaign {
94
67
  this._data.customData = data.customData || data.cdata || data.custom || {};
95
68
 
96
69
  // Actions mapping (legacy may have abt/act/acc/acu)
97
- this._data.actions = Array.isArray(data.actions)
98
- ? data.actions.map((action) => ({
70
+ const actions = data.actions || data.actionButtons;
71
+ this._data.actions = Array.isArray(actions)
72
+ ? actions.map((action) => ({
99
73
  actionTitle: action.actionTitle || action.abt || '',
100
74
  actionType: action.actionType || action.act || '',
101
75
  actionContent: action.actionContent || action.acc || '',
@@ -117,6 +91,7 @@ class Campaign {
117
91
  // ===========================
118
92
  toCampaign(jsonData) {
119
93
  this._data.campId = jsonData.campId || jsonData.camp_id || '';
94
+ this._data.mid = jsonData.mid || '';
120
95
  this._data.nh = jsonData.title || jsonData.nh || '';
121
96
  this._data.nd = jsonData.description || jsonData.nd || '';
122
97
  this._data.end = jsonData.expandedDescription || jsonData.end || '';
@@ -131,8 +106,9 @@ class Campaign {
131
106
  this._data.expiry = jsonData.expiry || 0;
132
107
  this._data.customData = jsonData.customData || jsonData.custom || {};
133
108
  // Actions array mapping
134
- this._data.actions = Array.isArray(jsonData.actions)
135
- ? jsonData.actions.map(function (action) {
109
+ const actions = jsonData.actions || jsonData.actionButtons;
110
+ this._data.actions = Array.isArray(actions)
111
+ ? actions.map(function (action) {
136
112
  return {
137
113
  actionTitle: action.actionTitle || action.abt || '',
138
114
  actionType: action.actionType || action.act || '',
@@ -215,6 +191,9 @@ class Campaign {
215
191
  getCampaignId() {
216
192
  return this._data.campId || this._data.camp_id || '';
217
193
  }
194
+ getMid() {
195
+ return this._data.mid || '';
196
+ }
218
197
  getActionUrl() {
219
198
  return this._data.actionUrl || this._data.acu || this._data.eurl || '';
220
199
  }
@@ -243,6 +222,23 @@ class Campaign {
243
222
  return this._data.selectedActionUrl;
244
223
  }
245
224
 
225
+ // ===========================
226
+ // Campaign Click Tracking
227
+ // ===========================
228
+ async pushActionNotificationClicked(AppICE) {
229
+ const dataObj = {
230
+ campid: this.getCampaignId(),
231
+ abt: this.getSelectedActionTitle(),
232
+ mid: this.getMid()
233
+ };
234
+
235
+ try {
236
+ await AppICE.tagEvent('Campaign_Clicked', dataObj);
237
+ } catch (error) {
238
+ console.error('Campaign_Clicked tracking failed:', error);
239
+ }
240
+ }
241
+
246
242
  // Convert to JSON
247
243
  toJSON() {
248
244
  return this._data;
@@ -17,7 +17,7 @@
17
17
  "install": "^0.13.0",
18
18
  "react": "18.0.0",
19
19
  "react-native": "0.69.4",
20
- "reactnative-plugin-appice": "1.7.43",
20
+ "reactnative-plugin-appice": "1.7.48",
21
21
  "react-native-mmkv": "2.12.2"
22
22
  },
23
23
  "devDependencies": {
@@ -457,7 +457,7 @@ RCT_EXPORT_METHOD(synchronizeInbox:(int)timeout callback:(RCTResponseSenderBlock
457
457
  @"messageExpiryTime": @(inboxMessage.messageExpiryTime),
458
458
  @"campType": inboxMessage.campType,
459
459
  @"expandedImage": inboxMessage.expandedImage, //messageExpandedImage replaced to expandedImage as discussed
460
- @"actionButtons": actionButtons
460
+ @"actions": actionButtons
461
461
  };
462
462
  } else {
463
463
  return @{};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reactnative-plugin-appice",
3
- "version": "1.7.47",
3
+ "version": "1.7.49",
4
4
  "description": "appICE React Native SDK",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -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.27"
26
+ s.dependency "AppICE-IOS-SDK", "1.8.28"
27
27
  # ...
28
28
  # s.dependency "..."
29
29
  end