Skip to content

Commit e071e89

Browse files
Merge branch 'master' into feature/SDK-107-app-already-runnig
2 parents c04740d + 780a351 commit e071e89

4 files changed

Lines changed: 54 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
1414
- Requires the host activity to use a `Theme.AppCompat` descendant when the toolbar is enabled.
1515
- Added `appAlreadyRunning` field to `trackPushOpen`. New `trackPushOpen(int, int, String, boolean, JSONObject)` overload sends the value through; existing overloads default to `false`.
1616

17+
### Fixed
18+
- Fixed a `TransactionTooLargeException` crash when displaying in-app messages with oversized HTML payloads. The HTML is no longer serialized into the fragment's saved instance state; it is reloaded from storage on recreation. In-apps with missing HTML now dismiss gracefully without registering tracking events, and a warning is logged for HTML payloads exceeding the recommended size.
19+
1720
## [3.8.0]
1821
### Added
1922
- New `IterableInAppDisplayMode` enum to control how in-app messages interact with system bars. Configure via `IterableConfig.Builder.setInAppDisplayMode()`:

iterableapi/src/main/java/com/iterable/iterableapi/IterableInAppDisplayer.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99

1010
class IterableInAppDisplayer {
1111

12+
// Large HTML payloads risk a TransactionTooLargeException and other display issues.
13+
private static final int IN_APP_HTML_SIZE_WARNING_THRESHOLD = 250 * 1024;
14+
1215
private final IterableActivityMonitor activityMonitor;
1316

1417
IterableInAppDisplayer(IterableActivityMonitor activityMonitor) {
@@ -34,6 +37,12 @@ boolean showMessage(@NonNull IterableInAppMessage message, IterableInAppLocation
3437
return false;
3538
}
3639

40+
String html = message.getContent().html;
41+
if (html != null && html.length() > IN_APP_HTML_SIZE_WARNING_THRESHOLD) {
42+
IterableLogger.w(IterableInAppManager.TAG, "In-App message HTML payload is " + html.length() +
43+
" bytes, exceeding the recommended size. This may cause display issues.");
44+
}
45+
3746
Activity currentActivity = activityMonitor.getCurrentActivity();
3847
if (currentActivity != null) {
3948
// Try FragmentActivity path first (backward compatibility)

iterableapi/src/main/java/com/iterable/iterableapi/IterableInAppFragmentHTMLNotification.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
public class IterableInAppFragmentHTMLNotification extends DialogFragment implements IterableWebView.HTMLNotificationCallbacks {
4242
private static final String BACK_BUTTON = "itbl://backButton";
4343
private static final String TAG = "IterableInAppFragmentHTMLNotification";
44-
private static final String HTML_STRING = "HTML";
4544
private static final String BACKGROUND_ALPHA = "BackgroundAlpha";
4645
private static final String INSET_PADDING = "InsetPadding";
4746
private static final String CALLBACK_ON_CANCEL = "CallbackOnCancel";
@@ -87,8 +86,12 @@ public static IterableInAppFragmentHTMLNotification createInstance(@NonNull Stri
8786

8887
public static IterableInAppFragmentHTMLNotification createInstance(@NonNull String htmlString, boolean callbackOnCancel, @NonNull IterableHelper.IterableUrlCallback clickCallback, @NonNull IterableInAppLocation location, @NonNull String messageId, @NonNull Double backgroundAlpha, @NonNull Rect padding, @NonNull boolean shouldAnimate, IterableInAppMessage.InAppBgColor inAppBgColor) {
8988
notification = new IterableInAppFragmentHTMLNotification();
89+
// HTML is kept in-memory (not in the Bundle) so it isn't serialized into the
90+
// FragmentManager's saved state, which would overflow the Binder transaction limit
91+
// (TransactionTooLargeException) for large payloads. On process-death recreation it is
92+
// reloaded from storage by messageId in onCreate().
93+
notification.htmlString = htmlString;
9094
Bundle args = new Bundle();
91-
args.putString(HTML_STRING, htmlString);
9295
args.putBoolean(CALLBACK_ON_CANCEL, callbackOnCancel);
9396
args.putString(MESSAGE_ID, messageId);
9497
args.putDouble(BACKGROUND_ALPHA, backgroundAlpha);
@@ -140,7 +143,6 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
140143
Bundle args = getArguments();
141144

142145
if (args != null) {
143-
htmlString = args.getString(HTML_STRING, null);
144146
callbackOnCancel = args.getBoolean(CALLBACK_ON_CANCEL, false);
145147
messageId = args.getString(MESSAGE_ID);
146148
backgroundAlpha = args.getDouble(BACKGROUND_ALPHA);
@@ -150,6 +152,14 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
150152
shouldAnimate = args.getBoolean(IN_APP_SHOULD_ANIMATE);
151153
}
152154

155+
// On process-death recreation the HTML is gone from memory; reload it from storage.
156+
if (htmlString == null && messageId != null) {
157+
IterableInAppMessage message = IterableApi.sharedInstance.getInAppManager().getMessageById(messageId);
158+
if (message != null) {
159+
htmlString = message.getContent().html;
160+
}
161+
}
162+
153163
notification = this;
154164
displayMode = resolveDisplayMode();
155165
}
@@ -194,6 +204,12 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
194204
applyWindowGravity(getDialog().getWindow(), "onCreateView");
195205
}
196206

207+
if (htmlString == null || htmlString.isEmpty()) {
208+
IterableLogger.e(TAG, "Unable to load in-app HTML for message " + messageId + "; dismissing without tracking");
209+
dismissAllowingStateLoss();
210+
return null;
211+
}
212+
197213
webView = createWebViewSafely(getContext());
198214
if (webView == null) {
199215
dismissAllowingStateLoss();

iterableapi/src/test/java/com/iterable/iterableapi/IterableInAppHTMLNotificationTest.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static android.os.Looper.getMainLooper;
2020
import static junit.framework.Assert.assertEquals;
2121
import static junit.framework.Assert.assertNotNull;
22+
import static junit.framework.Assert.assertNull;
2223
import static junit.framework.Assert.assertTrue;
2324
import static org.robolectric.Shadows.shadowOf;
2425

@@ -56,6 +57,28 @@ public void testDoNotCrashOnResizeAfterDismiss() {
5657
notification.resize(500.0f);
5758
}
5859

60+
// ===== Oversized HTML Payload Tests (SDK-419) =====
61+
62+
@Test
63+
public void testHtmlNotStoredInFragmentArguments() {
64+
Rect padding = new Rect(0, -1, 0, -1);
65+
IterableInAppFragmentHTMLNotification notification = IterableInAppFragmentHTMLNotification.createInstance(
66+
"<html><body>Test</body></html>", false, uri -> {
67+
}, IterableInAppLocation.IN_APP, "msg1", 0.0, padding, false, new IterableInAppMessage.InAppBgColor(null, 0.0f));
68+
69+
assertNull("HTML should not be persisted in fragment arguments", notification.getArguments().getString("HTML"));
70+
}
71+
72+
@Test
73+
public void testEmptyHtmlDismissesWithoutShowing() {
74+
IterableInAppDisplayer.showIterableFragmentNotificationHTML(activity, "", "msg1", null, 0.0, new Rect(), true, new IterableInAppMessage.InAppBgColor(null, 0.0f), false, IterableInAppLocation.IN_APP);
75+
shadowOf(getMainLooper()).idle();
76+
77+
// onCreateView dismisses early when HTML is empty, so the fragment is torn down and
78+
// the static instance is cleared in onDestroy — nothing is shown.
79+
assertNull("Notification should be dismissed when HTML is empty", IterableInAppFragmentHTMLNotification.getInstance());
80+
}
81+
5982
// ===== Resize Debouncing Tests =====
6083

6184
@Test

0 commit comments

Comments
 (0)