-
Notifications
You must be signed in to change notification settings - Fork 40
[MOB-11954] restructure RNIterableAPIModule to delegate functionality to RNIterableAPIModuleImpl #693
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[MOB-11954] restructure RNIterableAPIModule to delegate functionality to RNIterableAPIModuleImpl #693
Conversation
…o RNIterableAPIModuleImpl
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR restructures the RNIterableAPIModule to delegate its functionality to a new RNIterableAPIModuleImpl class. This refactoring separates the React Native bridge interface from the core implementation logic, preparing for future architectural changes that will split functionality between new and legacy architectures.
- Extracts all implementation logic from RNIterableAPIModule into RNIterableAPIModuleImpl
- Transforms RNIterableAPIModule into a thin wrapper that delegates calls to the implementation
- Maintains the same public API while enabling code reuse for upcoming architecture splits
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| RNIterableAPIModuleImpl.java | New implementation class containing all the core functionality moved from RNIterableAPIModule |
| RNIterableAPIModule.java | Refactored to delegate all method calls to RNIterableAPIModuleImpl instance |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java
Outdated
Show resolved
Hide resolved
| } | ||
|
|
||
| @Override | ||
| public void onInboxUpdated() { |
Copilot
AI
Aug 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The onInboxUpdated method should not be public as it appears to be a callback method that should only be called internally. This method should have package-private or private visibility.
| public void onInboxUpdated() { | |
| void onInboxUpdated() { |
11 new issues
This is from Qlty Cloud, the successor to Code Climate Quality. Learn more. |
| // This is just here to match the TS types and let the JS thread know when we are done initializing | ||
| promise.resolve(true); | ||
| @ReactMethod | ||
| public void initialize2WithApiKey(String apiKey, ReadableMap configReadableMap, String apiEndPointOverride, String version, Promise promise) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| @ReactMethod | ||
| public void trackPushOpenWithCampaignId(Integer campaignId, Integer templateId, String messageId, Boolean appAlreadyRunning, ReadableMap dataFields) { | ||
| RNIterableInternal.trackPushOpenWithCampaignId(campaignId, templateId, messageId, optSerializedDataFields(dataFields)); | ||
| public void trackPushOpenWithCampaignId(double campaignId, Double templateId, String messageId, boolean appAlreadyRunning, ReadableMap dataFields) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| finalCampaignId, | ||
| finalTemplateId | ||
| ); | ||
| public void updateSubscriptions(ReadableArray emailListIds, ReadableArray unsubscribedChannelIds, ReadableArray unsubscribedMessageTypeIds, ReadableArray subscribedMessageTypeIds, double campaignId, double templateId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| } | ||
|
|
||
| IterableApi.getInstance().trackInAppClose(inAppMessage, clickedUrl, closeAction, inAppCloseLocation); | ||
| public void trackInAppClose(String messageId, double location, double source, @Nullable String clickedUrl) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| public void initializeWithApiKey(String apiKey, ReadableMap configReadableMap, String version, Promise promise) { | ||
| IterableLogger.d(TAG, "initializeWithApiKey: " + 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); | ||
| } | ||
|
|
||
| IterableApi.initialize(reactContext, apiKey, configBuilder.build()); | ||
| IterableApi.getInstance().setDeviceAttribute("reactNativeSDKVersion", version); | ||
|
|
||
| IterableApi.getInstance().getInAppManager().addListener(this); | ||
|
|
||
| // 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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| public void initialize2WithApiKey(String apiKey, ReadableMap configReadableMap, String apiEndPointOverride, String version, 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); | ||
| } | ||
|
|
||
| // Set the API endpoint override if provided | ||
| // if (apiEndPointOverride != null && !apiEndPointOverride.isEmpty()) { | ||
| // configBuilder.setApiEndpoint(apiEndPointOverride); | ||
| // } | ||
|
|
||
| IterableApi.initialize(reactContext, apiKey, configBuilder.build()); | ||
| IterableApi.getInstance().setDeviceAttribute("reactNativeSDKVersion", version); | ||
|
|
||
| IterableApi.getInstance().getInAppManager().addListener(this); | ||
|
|
||
| // 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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| IterableApi.getInstance().trackPurchase(total, Serialization.commerceItemsFromReadableArray(items), optSerializedDataFields(dataFields)); | ||
| } | ||
|
|
||
| public void trackPushOpenWithCampaignId(double campaignId, Double templateId, String messageId, boolean appAlreadyRunning, ReadableMap dataFields) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| RNIterableInternal.trackPushOpenWithCampaignId((int) campaignId, templateId != null ? templateId.intValue() : null, messageId, optSerializedDataFields(dataFields)); | ||
| } | ||
|
|
||
| public void updateSubscriptions(ReadableArray emailListIds, ReadableArray unsubscribedChannelIds, ReadableArray unsubscribedMessageTypeIds, ReadableArray subscribedMessageTypeIds, double campaignId, double templateId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| IterableApi.getInstance().trackInAppClick(message, clickedUrl, inAppOpenLocation); | ||
| } | ||
|
|
||
| public void trackInAppClose(String messageId, double location, double source, @Nullable String clickedUrl) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // This is just here to match the TS types and let the JS thread know when we are done initializing | ||
| promise.resolve(true); | ||
| @ReactMethod | ||
| public void initialize2WithApiKey(String apiKey, ReadableMap configReadableMap, String apiEndPointOverride, String version, Promise promise) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| @ReactMethod | ||
| public void trackPushOpenWithCampaignId(Integer campaignId, Integer templateId, String messageId, Boolean appAlreadyRunning, ReadableMap dataFields) { | ||
| RNIterableInternal.trackPushOpenWithCampaignId(campaignId, templateId, messageId, optSerializedDataFields(dataFields)); | ||
| public void trackPushOpenWithCampaignId(double campaignId, Double templateId, String messageId, boolean appAlreadyRunning, ReadableMap dataFields) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| finalCampaignId, | ||
| finalTemplateId | ||
| ); | ||
| public void updateSubscriptions(ReadableArray emailListIds, ReadableArray unsubscribedChannelIds, ReadableArray unsubscribedMessageTypeIds, ReadableArray subscribedMessageTypeIds, double campaignId, double templateId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| } | ||
|
|
||
| IterableApi.getInstance().trackInAppClose(inAppMessage, clickedUrl, closeAction, inAppCloseLocation); | ||
| public void trackInAppClose(String messageId, double location, double source, @Nullable String clickedUrl) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| public void initializeWithApiKey(String apiKey, ReadableMap configReadableMap, String version, Promise promise) { | ||
| IterableLogger.d(TAG, "initializeWithApiKey: " + 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); | ||
| } | ||
|
|
||
| IterableApi.initialize(reactContext, apiKey, configBuilder.build()); | ||
| IterableApi.getInstance().setDeviceAttribute("reactNativeSDKVersion", version); | ||
|
|
||
| IterableApi.getInstance().getInAppManager().addListener(this); | ||
|
|
||
| // 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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| public void initialize2WithApiKey(String apiKey, ReadableMap configReadableMap, String apiEndPointOverride, String version, 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. | ||
|
|
||
| IterableApi.initialize(reactContext, apiKey, configBuilder.build()); | ||
| IterableApi.getInstance().setDeviceAttribute("reactNativeSDKVersion", version); | ||
|
|
||
| IterableApi.getInstance().getInAppManager().addListener(this); | ||
|
|
||
| // 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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| IterableApi.getInstance().trackPurchase(total, Serialization.commerceItemsFromReadableArray(items), optSerializedDataFields(dataFields)); | ||
| } | ||
|
|
||
| public void trackPushOpenWithCampaignId(double campaignId, Double templateId, String messageId, boolean appAlreadyRunning, ReadableMap dataFields) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| RNIterableInternal.trackPushOpenWithCampaignId((int) campaignId, templateId != null ? templateId.intValue() : null, messageId, optSerializedDataFields(dataFields)); | ||
| } | ||
|
|
||
| public void updateSubscriptions(ReadableArray emailListIds, ReadableArray unsubscribedChannelIds, ReadableArray unsubscribedMessageTypeIds, ReadableArray subscribedMessageTypeIds, double campaignId, double templateId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| IterableApi.getInstance().trackInAppClick(message, clickedUrl, inAppOpenLocation); | ||
| } | ||
|
|
||
| public void trackInAppClose(String messageId, double location, double source, @Nullable String clickedUrl) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
…ableapimodule-so-that-its-major-func
| // This is just here to match the TS types and let the JS thread know when we are done initializing | ||
| promise.resolve(true); | ||
| @ReactMethod | ||
| public void initialize2WithApiKey(String apiKey, ReadableMap configReadableMap, String apiEndPointOverride, String version, Promise promise) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| @ReactMethod | ||
| public void trackPushOpenWithCampaignId(Integer campaignId, Integer templateId, String messageId, Boolean appAlreadyRunning, ReadableMap dataFields) { | ||
| RNIterableInternal.trackPushOpenWithCampaignId(campaignId, templateId, messageId, optSerializedDataFields(dataFields)); | ||
| public void trackPushOpenWithCampaignId(double campaignId, Double templateId, String messageId, boolean appAlreadyRunning, ReadableMap dataFields) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| finalCampaignId, | ||
| finalTemplateId | ||
| ); | ||
| public void updateSubscriptions(ReadableArray emailListIds, ReadableArray unsubscribedChannelIds, ReadableArray unsubscribedMessageTypeIds, ReadableArray subscribedMessageTypeIds, double campaignId, double templateId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| } | ||
|
|
||
| IterableApi.getInstance().trackInAppClose(inAppMessage, clickedUrl, closeAction, inAppCloseLocation); | ||
| public void trackInAppClose(String messageId, double location, double source, @Nullable String clickedUrl) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| public void initializeWithApiKey(String apiKey, ReadableMap configReadableMap, String version, Promise promise) { | ||
| IterableLogger.d(TAG, "initializeWithApiKey: " + 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); | ||
| } | ||
|
|
||
| IterableApi.initialize(reactContext, apiKey, configBuilder.build()); | ||
| IterableApi.getInstance().setDeviceAttribute("reactNativeSDKVersion", version); | ||
|
|
||
| IterableApi.getInstance().getInAppManager().addListener(this); | ||
|
|
||
| // 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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| public void initialize2WithApiKey(String apiKey, ReadableMap configReadableMap, String apiEndPointOverride, String version, 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. | ||
|
|
||
| IterableApi.initialize(reactContext, apiKey, configBuilder.build()); | ||
| IterableApi.getInstance().setDeviceAttribute("reactNativeSDKVersion", version); | ||
|
|
||
| IterableApi.getInstance().getInAppManager().addListener(this); | ||
|
|
||
| // 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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| IterableApi.getInstance().trackPurchase(total, Serialization.commerceItemsFromReadableArray(items), optSerializedDataFields(dataFields)); | ||
| } | ||
|
|
||
| public void trackPushOpenWithCampaignId(double campaignId, Double templateId, String messageId, boolean appAlreadyRunning, ReadableMap dataFields) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| RNIterableInternal.trackPushOpenWithCampaignId((int) campaignId, templateId != null ? templateId.intValue() : null, messageId, optSerializedDataFields(dataFields)); | ||
| } | ||
|
|
||
| public void updateSubscriptions(ReadableArray emailListIds, ReadableArray unsubscribedChannelIds, ReadableArray unsubscribedMessageTypeIds, ReadableArray subscribedMessageTypeIds, double campaignId, double templateId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| IterableApi.getInstance().trackInAppClick(message, clickedUrl, inAppOpenLocation); | ||
| } | ||
|
|
||
| public void trackInAppClose(String messageId, double location, double source, @Nullable String clickedUrl) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just skimmed. Let me know if you need a deeper review. Confirmed both legacy and new architecture run successfully.
🔹 JIRA Ticket(s) if any
✏️ Description
Restructure RNIterableAPIModule to delegate functionality to RNIterableAPIModuleImpl. This is to minimize duplicate code when splitting the functionality between new architecture and legacy architecture later on.
Testing
Testing Legacy Architecture
Enable Legacy Architecture:
# Check example/android/gradle.properties newArchEnabled=falseBuild and run:
Verify app launches and do a quick click through of various items
Testing New Architecture
Enable new architecture:
# Edit example/android/gradle.properties newArchEnabled=trueClean and rebuild:
Verify app launches and do a quick click through of various items