diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index ae53f411fddc..ba0924f0ba7a 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -10,6 +10,7 @@ * [*] [Jetpack-only] Site Monitoring: Add Metrics, PHP Logs, and Web Server Logs under Site Monitoring [https://github.com/wordpress-mobile/WordPress-Android/issues/20067] * [**] Prevent images from temporarily disappearing when uploading media [https://github.com/WordPress/gutenberg/pull/57869] * [***] [Jetpack-only] Reader: introduced new UI/UX for content navigation and filtering [https://github.com/wordpress-mobile/WordPress-Android/pull/19978] +* [**] Prevents crashes when the webview state is too big [https://github.com/wordpress-mobile/WordPress-Android/pull/20139] 24.1 ----- diff --git a/WordPress/src/main/java/org/wordpress/android/ui/WebViewActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/WebViewActivity.java index 8770f417b37c..1999b39538e2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/WebViewActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/WebViewActivity.java @@ -14,8 +14,10 @@ import org.wordpress.android.R; import org.wordpress.android.WordPress; +import org.wordpress.android.analytics.AnalyticsTracker; import org.wordpress.android.util.extensions.CompatExtensionsKt; +import java.util.HashMap; import java.util.Map; /** @@ -28,6 +30,9 @@ public abstract class WebViewActivity extends LocaleAwareActivity { private static final String URL = "url"; + private static final String WEBVIEW_CHROMIUM_STATE = "WEBVIEW_CHROMIUM_STATE"; + private static final int WEBVIEW_CHROMIUM_STATE_THRESHOLD = 300 * 1024; // 300 KB + protected WebView mWebView; @Override @@ -84,8 +89,26 @@ protected void loadContent() { * save the webView state with the bundle so it can be restored */ @Override - protected void onSaveInstanceState(Bundle outState) { + protected void onSaveInstanceState(@NonNull Bundle outState) { mWebView.saveState(outState); + + // If the WebView state is too large, remove it from the bundle and track the error. This workaround is + // necessary since the Android system cannot handle large states without a crash. + // Note that Chromium `WebViewBrowserFragment` uses a similar workaround for this issue: + // https://source.chromium.org/chromium/chromium/src/+/27a9bbd3dcd7005ac9f3862dc2e356b557023de9 + byte[] webViewState = outState.getByteArray(WEBVIEW_CHROMIUM_STATE); + if (webViewState != null && webViewState.length > WEBVIEW_CHROMIUM_STATE_THRESHOLD) { + outState.remove(WEBVIEW_CHROMIUM_STATE); + + // Save the URL so it can be restored later + String url = mWebView.getUrl(); + outState.putString(URL, url); + + // Track the error to better understand the root of the issue + Map properties = new HashMap<>(); + properties.put(URL, url); + AnalyticsTracker.track(AnalyticsTracker.Stat.WEBVIEW_TOO_LARGE_PAYLOAD_ERROR, properties); + } super.onSaveInstanceState(outState); } @@ -93,9 +116,16 @@ protected void onSaveInstanceState(Bundle outState) { * restore the webView state saved above */ @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) { + protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); - mWebView.restoreState(savedInstanceState); + if (savedInstanceState.containsKey(WEBVIEW_CHROMIUM_STATE)) { + mWebView.restoreState(savedInstanceState); + } else { + String url = savedInstanceState.getString(URL); + if (url != null) { + mWebView.loadUrl(url); + } + } } @Override diff --git a/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java b/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java index 82b8a3b126f2..5a4e730ef599 100644 --- a/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java +++ b/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java @@ -1106,7 +1106,8 @@ public enum Stat { SITE_MONITORING_SCREEN_SHOWN, OPENED_SITE_MONITORING, SITE_MONITORING_TAB_SHOWN, - SITE_MONITORING_TAB_LOADING_ERROR + SITE_MONITORING_TAB_LOADING_ERROR, + WEBVIEW_TOO_LARGE_PAYLOAD_ERROR, } private static final List TRACKERS = new ArrayList<>(); diff --git a/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java b/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java index fcd096393664..08a9c022394b 100644 --- a/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java +++ b/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java @@ -2707,6 +2707,8 @@ public static String getEventNameForStat(AnalyticsTracker.Stat stat) { return "site_monitoring_tab_shown"; case SITE_MONITORING_TAB_LOADING_ERROR: return "site_monitoring_tab_loading_error"; + case WEBVIEW_TOO_LARGE_PAYLOAD_ERROR: + return "webview_too_large_payload_error"; } return null; }