From de5b9ef3ff99005bd92c81904e49f0ac039bc094 Mon Sep 17 00:00:00 2001 From: Franco Zalamena Date: Tue, 7 Apr 2026 15:48:35 +0100 Subject: [PATCH] Handle WebView render process crash gracefully Add onRenderProcessGone handler to both IterableWebViewClient and IterableInboxMessageFragment's WebViewClient to prevent app crashes when the Chromium renderer process dies. The handler logs the event, cleans up the WebView, and returns true to absorb the crash. Fixes #954 Co-Authored-By: Claude Opus 4.6 --- .../inbox/IterableInboxMessageFragment.java | 30 +++++++++++++++++++ .../iterableapi/IterableWebViewClient.java | 27 ++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/inbox/IterableInboxMessageFragment.java b/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/inbox/IterableInboxMessageFragment.java index ebf5d6e57..0598550e6 100644 --- a/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/inbox/IterableInboxMessageFragment.java +++ b/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/inbox/IterableInboxMessageFragment.java @@ -1,13 +1,16 @@ package com.iterable.iterableapi.ui.inbox; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.webkit.RenderProcessGoneDetail; import android.webkit.WebView; import android.webkit.WebViewClient; @@ -22,6 +25,7 @@ public class IterableInboxMessageFragment extends Fragment { public static final String ARG_MESSAGE_ID = "messageId"; public static final String STATE_LOADED = "loaded"; + private static final String TAG = "IterableInboxMsgFrag"; private String messageId; private WebView webView; @@ -100,5 +104,31 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) { } return true; } + + @Override + public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + boolean didCrash = detail.didCrash(); + Log.w(TAG, "WebView render process gone. didCrash: " + didCrash); + + // Clean up the WebView to prevent further issues + if (view != null) { + try { + view.destroy(); + } catch (Exception e) { + Log.e(TAG, "Error destroying WebView after render process gone", e); + } + } + + // Close the fragment's activity since the WebView is no longer usable + if (getActivity() != null) { + getActivity().finish(); + } + + // Return true to prevent the app from crashing + return true; + } + return super.onRenderProcessGone(view, detail); + } }; } diff --git a/iterableapi/src/main/java/com/iterable/iterableapi/IterableWebViewClient.java b/iterableapi/src/main/java/com/iterable/iterableapi/IterableWebViewClient.java index 203426fd5..ca91756e7 100644 --- a/iterableapi/src/main/java/com/iterable/iterableapi/IterableWebViewClient.java +++ b/iterableapi/src/main/java/com/iterable/iterableapi/IterableWebViewClient.java @@ -1,9 +1,13 @@ package com.iterable.iterableapi; +import android.os.Build; +import android.webkit.RenderProcessGoneDetail; import android.webkit.WebView; import android.webkit.WebViewClient; class IterableWebViewClient extends WebViewClient { + private static final String TAG = "IterableWebViewClient"; + IterableWebView.HTMLNotificationCallbacks inAppHTMLNotification; IterableWebViewClient(IterableWebView.HTMLNotificationCallbacks inAppHTMLNotification) { @@ -21,4 +25,25 @@ public void onPageFinished(WebView view, String url) { inAppHTMLNotification.setLoaded(true); view.postDelayed(inAppHTMLNotification::runResizeScript, 100); } -} \ No newline at end of file + + @Override + public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + boolean didCrash = detail.didCrash(); + IterableLogger.w(TAG, "WebView render process gone. didCrash: " + didCrash); + + // Clean up the WebView to prevent further issues + if (view != null) { + try { + view.destroy(); + } catch (Exception e) { + IterableLogger.e(TAG, "Error destroying WebView after render process gone", e); + } + } + + // Return true to prevent the app from crashing + return true; + } + return super.onRenderProcessGone(view, detail); + } +}