Skip to content

Commit 1784c9a

Browse files
ishita-gambhir-adobenamArora3112Naman Arora
authored
[Messaging] Staging to Main for Messaging 7.2.0 release (#528)
* PropositionItem class added along with unified track functionality (#507) * proposition item classes, track funcitonality etc * proposition item uuid added * json proposition item removed * removed unused guide * added htmlProposition , jsonPropositon item class * removed unused apis of content card * generatePropositionInteractionXdm removed * ios implementation of track functionality * uuid vs proposition map added * MessagingProposition class fixes * get proposition for surfaces android fixes * ios get proposition for surface fixes * getproposition for surface updates * MessagingView commented code removed * removed proposition cache with parent * clear cache in update proposition * message util clean up * proposition Item tracking usage refactored * activityID extraction function reusable * white space fixes * added read me for track api usage * removed unnecessary checks before calling track api for android native * refactored extra null checks before calling track api at ios native side * Addeed ios and android logs for null cases * added comments and logs for android native code * marked the trackContentCardInteraction and trackContentCardDisplay as deprecated * added tests for propositionItem.track * read me updated for proposition Item track usage --------- Co-authored-by: Naman Arora <[email protected]> * add handleJavascriptMessage in AEPMessaging (#519) * Messaging - handle javascript message * add js event listener and ios * typecaste Message object * address PR comments * refactor log statements * address PR comments * revert env file id changes * clear js handler when onDismiss is called * messaging version bump for 7.2.0 release (#526) * typecaste to Message object (#527) * read me updates regarding deprecated apis --------- Co-authored-by: namArora3112 <[email protected]> Co-authored-by: Naman Arora <[email protected]>
1 parent 2e43601 commit 1784c9a

23 files changed

+932
-73
lines changed

apps/AEPSampleAppNewArchEnabled/app/MessagingView.tsx

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,24 @@ governing permissions and limitations under the License.
1313
import React from 'react';
1414
import {Button, Text, View, ScrollView} from 'react-native';
1515
import {MobileCore} from '@adobe/react-native-aepcore';
16-
import {Messaging, PersonalizationSchema} from '@adobe/react-native-aepmessaging'
16+
import {
17+
Messaging,
18+
PersonalizationSchema,
19+
MessagingEdgeEventType,
20+
PropositionItem,
21+
Message,
22+
ContentCard,
23+
HTMLProposition,
24+
JSONPropositionItem
25+
} from '@adobe/react-native-aepmessaging'
26+
import { MessagingProposition } from '@adobe/react-native-aepmessaging';
1727
import styles from '../styles/styles';
1828
import { useRouter } from 'expo-router';
1929

2030
const SURFACES = ['android-cbe-preview', 'cbe/json', 'android-cc'];
2131
const SURFACES_WITH_CONTENT_CARDS = ['android-cc'];
2232

33+
2334
const messagingExtensionVersion = async () => {
2435
const version = await Messaging.extensionVersion();
2536
console.log(`AdobeExperienceSDK: Messaging version: ${version}`);
@@ -33,21 +44,24 @@ const refreshInAppMessages = () => {
3344
const setMessagingDelegate = () => {
3445
Messaging.setMessagingDelegate({
3546
onDismiss: msg => console.log('dismissed!', msg),
36-
onShow: msg => console.log('show', msg),
47+
onShow: msg => {
48+
console.log('show', msg);
49+
msg.handleJavascriptMessage('myInappCallback', (content: string) => {
50+
console.log('Received webview content in onShow:', content);
51+
});
52+
},
3753
shouldShowMessage: () => true,
3854
shouldSaveMessage: () => true,
3955
urlLoaded: (url, message) => console.log(url, message),
4056
});
4157
console.log('messaging delegate set');
4258
};
43-
4459
const getPropositionsForSurfaces = async () => {
4560
const messages = await Messaging.getPropositionsForSurfaces(SURFACES);
46-
console.log(JSON.stringify(messages));
61+
console.log('getPropositionsForSurfaces', JSON.stringify(messages));
4762
};
48-
4963
const trackAction = async () => {
50-
MobileCore.trackAction('tuesday', {full: true});
64+
MobileCore.trackAction('iamjs', {full: true});
5165
};
5266

5367
const updatePropositionsForSurfaces = async () => {
@@ -75,7 +89,8 @@ const trackContentCardInteraction = async () => {
7589
for (const proposition of propositions) {
7690
for (const propositionItem of proposition.items) {
7791
if (propositionItem.schema === PersonalizationSchema.CONTENT_CARD) {
78-
Messaging.trackContentCardInteraction(proposition, propositionItem);
92+
// Cast to ContentCard for the legacy tracking method
93+
Messaging.trackContentCardInteraction(proposition, propositionItem as any);
7994
console.log('trackContentCardInteraction', proposition, propositionItem);
8095
}
8196
}
@@ -93,14 +108,35 @@ const trackContentCardDisplay = async () => {
93108
for (const proposition of propositions) {
94109
for (const propositionItem of proposition.items) {
95110
if (propositionItem.schema === PersonalizationSchema.CONTENT_CARD) {
96-
Messaging.trackContentCardDisplay(proposition, propositionItem);
111+
// Cast to ContentCard for the legacy tracking method
112+
Messaging.trackContentCardDisplay(proposition, propositionItem as any);
97113
console.log('trackContentCardDisplay', proposition, propositionItem);
98114
}
99115
}
100116
}
101117
}
102118
}
103119

120+
121+
// Method demonstrating unified tracking using PropositionItem methods
122+
const unifiedTrackingExample = async () => {
123+
const messages = await Messaging.getPropositionsForSurfaces(SURFACES);
124+
for (const surface of SURFACES) {
125+
const propositions = messages[surface] || [];
126+
127+
for (const proposition of propositions) {
128+
const propositionWrapper = new MessagingProposition(proposition);
129+
if (propositionWrapper.items.length > 0) {
130+
const propositionItem = propositionWrapper.items[0];
131+
propositionItem.track(MessagingEdgeEventType.DISPLAY);
132+
propositionItem.track('content_card_clicked', MessagingEdgeEventType.INTERACT, null);
133+
}
134+
}
135+
}
136+
}
137+
138+
139+
104140
function MessagingView() {
105141
const router = useRouter();
106142

@@ -125,6 +161,7 @@ function MessagingView() {
125161
<Button title="trackAction()" onPress={trackAction} />
126162
<Button title="trackPropositionInteraction()" onPress={trackContentCardInteraction} />
127163
<Button title="trackContentCardDisplay()" onPress={trackContentCardDisplay} />
164+
<Button title="Unified Tracking Example" onPress={unifiedTrackingExample} />
128165
</ScrollView>
129166
</View>
130167
);

packages/messaging/README.md

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,53 @@ for (let item in proposition.items) {
201201
}
202202
```
203203

204+
205+
### PropositionItem.track
206+
207+
A unified tracking API is available for any proposition item (Content Cards, HTML, JSON, code-based items). You can use the same track() method regardless of content type, making your code more consistent and maintainable.
208+
209+
#### Using PropositionItem.track (recommended)
210+
211+
**Syntax**
212+
213+
```javascript
214+
// Track display event
215+
propositionItem.track(MessagingEdgeEventType.DISPLAY);
216+
217+
// Track interaction with custom data + event + optional tokens
218+
propositionItem.track(
219+
interaction /* string | null */,
220+
MessagingEdgeEventType.INTERACT /* enum value */,
221+
[/* tokens */] /* string[] | null */
222+
);
223+
```
224+
225+
When using `getPropositionsForSurfaces`, the returned objects can be wrapped with `MessagingProposition` to get typed items and convenient tracking via `PropositionItem.track(...)`.
226+
227+
```javascript
228+
import { Messaging, MessagingProposition, MessagingEdgeEventType } from '@adobe/react-native-aepmessaging';
229+
230+
const SURFACES = ['mobileapp://my-surface'];
231+
const messages = await Messaging.getPropositionsForSurfaces(SURFACES);
232+
233+
for (const surface of SURFACES) {
234+
const propositions = messages[surface] || [];
235+
236+
for (const proposition of propositions) {
237+
const msgProp = new MessagingProposition(proposition);
238+
239+
if (msgProp.items.length > 0) {
240+
const propositionItem = msgProp.items[0];
241+
242+
// Track interaction with custom data
243+
propositionItem.track('content_card_clicked', MessagingEdgeEventType.INTERACT, null);
244+
// Track with tokens for sub-item tracking
245+
propositionItem.track('button_click', MessagingEdgeEventType.INTERACT, ['token-1', 'token-2']);
246+
}
247+
}
248+
}
249+
```
250+
204251
### getLatestMessage
205252

206253
Retrieves the most recently displayed message object
@@ -340,6 +387,20 @@ var message: Message;
340387
message.clear();
341388
```
342389
390+
### handleJavascriptMessage
391+
392+
Registers a javascript interface for the provided handler name to the WebView associated with the InAppMessage presentation to handle Javascript messages. When the registered handlers are executed via the HTML the result will be passed back to the associated handler.
393+
394+
**Syntax**
395+
396+
```typescript
397+
handleJavascriptMessage(handlerName: string, handler: (content: string) => void);
398+
```
399+
400+
**Example**
401+
402+
It can be used for the native handling of JavaScript events. Please refer to the [tutorial](./tutorials/In-App%20Messaging.md#native-handling-of-javascript-events) for more information.
403+
343404
## Programmatically control the display of in-app messages
344405
345406
App developers can now create a type `MessagingDelegate` in order to be alerted when specific events occur during the lifecycle of an in-app message.
@@ -440,6 +501,8 @@ function otherWorkflowFinished() {
440501
441502
### trackContentCardDisplay
442503
504+
Deprecated in 7.2.0: Use `Proposition.track(...)` instead. This API will be removed in a future release.
505+
443506
Tracks a Display interaction with the given ContentCard
444507
445508
**Syntax**
@@ -449,6 +512,8 @@ Messaging.trackContentCardDisplay(proposition, contentCard);
449512
450513
### trackContentCardInteraction
451514
515+
Deprecated in 7.2.0: Use `Proposition.track(...)` instead. This API will be removed in a future release.
516+
452517
Tracks a Click interaction with the given ContentCard
453518
454519
**Syntax**
@@ -458,5 +523,4 @@ Messaging.trackContentCardInteraction(proposition, contentCard);
458523
459524
460525
## Tutorials
461-
[Content Cards](./tutorials/ContentCards.md)
462-
526+
[Native handling of Javascript Events](./tutorials/In-App%20Messaging.md)

packages/messaging/__tests__/MessagingTests.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,17 @@ describe('Messaging', () => {
8787
expect(spy).toHaveBeenCalledWith(id);
8888
});
8989

90+
it('handleJavascriptMessage is called', async () => {
91+
const spy = jest.spyOn(NativeModules.AEPMessaging, 'handleJavascriptMessage');
92+
let id = 'id';
93+
let autoTrack = true;
94+
let message = new Message({id, autoTrack});
95+
let handlerName = 'handlerName';
96+
let handler = jest.fn();
97+
await message.handleJavascriptMessage(handlerName, handler);
98+
expect(spy).toHaveBeenCalledWith(id, handlerName);
99+
});
100+
90101
it('should call updatePropositionsForSurfaces', async () => {
91102
const spy = jest.spyOn(NativeModules.AEPMessaging, 'updatePropositionsForSurfaces');
92103
await Messaging.updatePropositionsForSurfaces([
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
Copyright 2025 Adobe. All rights reserved.
3+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License. You may obtain a copy
5+
of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
7+
Unless required by applicable law or agreed to in writing, software distributed under
8+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9+
OF ANY KIND, either express or implied. See the License for the specific language
10+
governing permissions and limitations under the License.
11+
*/
12+
13+
import { NativeModules } from 'react-native';
14+
import { MessagingEdgeEventType, PropositionItem, PropositionItemData, PersonalizationSchema } from '../src';
15+
16+
describe('PropositionItem', () => {
17+
const uuid = 'activity-uuid-123';
18+
const id = 'item-abc';
19+
const activityID = uuid; // mirrors native mapping
20+
21+
const baseData: PropositionItemData = {
22+
id,
23+
uuid,
24+
activityID,
25+
schema: PersonalizationSchema.CONTENT_CARD,
26+
data: { foo: 'bar' },
27+
};
28+
29+
beforeEach(() => {
30+
jest.clearAllMocks();
31+
});
32+
33+
it('track(eventType) calls native with null interaction and tokens', () => {
34+
const item = new PropositionItem(baseData);
35+
item.track(MessagingEdgeEventType.DISPLAY);
36+
37+
expect(NativeModules.AEPMessaging.trackPropositionItem).toHaveBeenCalledWith(
38+
activityID,
39+
null,
40+
MessagingEdgeEventType.DISPLAY,
41+
null
42+
);
43+
});
44+
45+
it('track(interaction, eventType, tokens=null) forwards interaction', () => {
46+
const item = new PropositionItem(baseData);
47+
item.track('click', MessagingEdgeEventType.INTERACT, null);
48+
49+
expect(NativeModules.AEPMessaging.trackPropositionItem).toHaveBeenCalledWith(
50+
activityID,
51+
'click',
52+
MessagingEdgeEventType.INTERACT,
53+
null
54+
);
55+
});
56+
57+
it('track(interaction, eventType, tokens[]) forwards tokens array', () => {
58+
const item = new PropositionItem(baseData);
59+
const tokens = ['t1', 't2'];
60+
item.track('click', MessagingEdgeEventType.INTERACT, tokens);
61+
62+
expect(NativeModules.AEPMessaging.trackPropositionItem).toHaveBeenCalledWith(
63+
activityID,
64+
'click',
65+
MessagingEdgeEventType.INTERACT,
66+
tokens
67+
);
68+
});
69+
70+
it('track(null, eventType, tokens[]) supports null interaction with tokens', () => {
71+
const item = new PropositionItem(baseData);
72+
const tokens = ['a'];
73+
item.track(null, MessagingEdgeEventType.DISPLAY, tokens);
74+
75+
expect(NativeModules.AEPMessaging.trackPropositionItem).toHaveBeenCalledWith(
76+
activityID,
77+
null,
78+
MessagingEdgeEventType.DISPLAY,
79+
tokens
80+
);
81+
});
82+
});
83+
84+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
Copyright 2025 Adobe. All rights reserved.
3+
This file is licensed to you under the Apache License, Version 2.0 (the
4+
"License"); you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
7+
or agreed to in writing, software distributed under the License is
8+
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF
9+
ANY KIND, either express or implied. See the License for the specific
10+
language governing permissions and limitations under the License.
11+
*/
12+
package com.adobe.marketing.mobile.reactnative.messaging;
13+
14+
class RCTAEPMessagingConstants {
15+
static final String MESSAGE_ID_KEY = "messageId";
16+
static final String HANDLER_NAME_KEY = "handlerName";
17+
static final String CONTENT_KEY = "content";
18+
static final String ON_JAVASCRIPT_MESSAGE_EVENT = "onJavascriptMessage";
19+
}

0 commit comments

Comments
 (0)