Skip to content

Conversation

@Ayyanchira
Copy link
Member

@Ayyanchira Ayyanchira commented Jan 12, 2026

🔹 JIRA Ticket(s) if any

✏️ Description

Adds listners for Embedded Messages for Android

@Ayyanchira Ayyanchira requested a review from lposen January 12, 2026 21:08
@github-actions
Copy link

github-actions bot commented Jan 12, 2026

Lines Statements Branches Functions
Coverage: 61%
61.44% (400/651) 38.52% (99/257) 58.64% (139/237)

@qltysh
Copy link

qltysh bot commented Jan 12, 2026

Qlty

Coverage Impact

⬇️ Merging this pull request will decrease total coverage on loren/embedded/master by 1.29%.

Modified Files with Diff Coverage (2)

RatingFile% DiffUncovered Line #s
Coverage rating: A Coverage rating: D
src/embedded/classes/IterableEmbeddedManager.ts15.8%82-439
Coverage rating: A Coverage rating: A
src/core/classes/Iterable.ts71.4%1097, 1104
Total30.8%
🤖 Increase coverage with AI coding...

In the `sdk-223-listener-android` branch, add test coverage for this new code:

- `src/core/classes/Iterable.ts` -- Lines 1097 and 1104
- `src/embedded/classes/IterableEmbeddedManager.ts` -- Line 82-439

🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

* subscription.remove();
* ```
*/
addMessagesUpdatedListener(callback: () => void) {
Copy link
Contributor

@lposen lposen Jan 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should instead have onEmbeddedMessageUpdate and handle the unsubscribe function internally, as this is how we have done other listeners in the app.

We can then add this to the removeAllEventListeners function in Iterable.ts,

Comment on lines 129 to 194
IterableApi.getInstance().getEmbeddedManager().addUpdateListener(this);
IterableApi.getInstance().getEmbeddedManager().syncMessages();

// MOB-10421: Figure out what the error cases are and handle them appropriately
// This is just here to match the TS types and let the JS thread know when we are done initializing
promise.resolve(true);
}

public void initialize2WithApiKey(String apiKey, ReadableMap configReadableMap, String version, String apiEndPointOverride, Promise promise) {
IterableLogger.d(TAG, "initialize2WithApiKey: " + apiKey);
IterableConfig.Builder configBuilder = Serialization.getConfigFromReadableMap(configReadableMap);

if (configReadableMap.hasKey("urlHandlerPresent") && configReadableMap.getBoolean("urlHandlerPresent") == true) {
configBuilder.setUrlHandler(this);
}

if (configReadableMap.hasKey("customActionHandlerPresent") && configReadableMap.getBoolean("customActionHandlerPresent") == true) {
configBuilder.setCustomActionHandler(this);
}

if (configReadableMap.hasKey("inAppHandlerPresent") && configReadableMap.getBoolean("inAppHandlerPresent") == true) {
configBuilder.setInAppHandler(this);
}

if (configReadableMap.hasKey("authHandlerPresent") && configReadableMap.getBoolean("authHandlerPresent") == true) {
configBuilder.setAuthHandler(this);
}

// NOTE: There does not seem to be a way to set the API endpoint
// override in the Android SDK. Check with @Ayyanchira and @evantk91 to
// see what the best approach is.

IterableConfig config = configBuilder.build();
IterableApi.initialize(reactContext, apiKey, config);

// Update retry policy on existing authManager if it was already created
// This fixes the issue where retryInterval is not respected after
// re-initialization
// TODO [SDK-197]: Fix the root cause of this issue, instead of this hack
try {
// Use reflection to access package-private fields and methods
java.lang.reflect.Field configRetryPolicyField = config.getClass().getDeclaredField("retryPolicy");
configRetryPolicyField.setAccessible(true);
Object retryPolicy = configRetryPolicyField.get(config);

if (retryPolicy != null) {
java.lang.reflect.Method getAuthManagerMethod = IterableApi.getInstance().getClass().getDeclaredMethod("getAuthManager");
getAuthManagerMethod.setAccessible(true);
IterableAuthManager authManager = (IterableAuthManager) getAuthManagerMethod.invoke(IterableApi.getInstance());

if (authManager != null) {
// Update the retry policy field on the authManager
java.lang.reflect.Field authRetryPolicyField = authManager.getClass().getDeclaredField("authRetryPolicy");
authRetryPolicyField.setAccessible(true);
authRetryPolicyField.set(authManager, retryPolicy);
IterableLogger.d(TAG, "Updated retry policy on existing authManager");
}
}
} catch (Exception e) {
IterableLogger.e(TAG, "Failed to update retry policy: " + e.getMessage());
}

IterableApi.getInstance().setDeviceAttribute("reactNativeSDKVersion", version);

IterableApi.getInstance().getInAppManager().addListener(this);
IterableApi.getInstance().getEmbeddedManager().addUpdateListener(this);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These puts themselves as listeners to updateListener at bridge. This will bridge to receive callback when list of EmbeddedMessages change.

@Override
public void onMessagesUpdated() {
IterableLogger.d(TAG, "onMessagesUpdated");
sendEvent(EventName.receivedIterableEmbeddedMessagesChanged.name(), null);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the callback that should trigger the call on TS level indicating its time to check local messages as sync has been performed.

@Override
public void onEmbeddedMessagingDisabled() {
IterableLogger.d(TAG, "onEmbeddedMessagingDisabled");
sendEvent(EventName.receivedIterableEmbeddedMessagingDisabled.name(), null);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

During the sync, if native code recognize feature disablement, this callback will be invoked. sendEvent will then call method on EventName.receivedIterableEmbeddedMessagingDisabled. TS layer also needs to be there where TS layer have list of listener it calls to indicate this disabled feature notice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants