Guard WebViewActivity against MissingWebViewPackageException#2994
Guard WebViewActivity against MissingWebViewPackageException#2994jim-daf wants to merge 1 commit into
Conversation
When the Android System WebView package is missing, disabled, or being updated, inflating the WebView throws an AndroidRuntimeException wrapping WebViewFactory.MissingWebViewPackageException. The activity then dies with no useful feedback for the user. Wrap the inflation and initial load in try/catch, log the failure, show a localized message and finish gracefully so the user can recover by reinstalling or enabling Android System WebView.
There was a problem hiding this comment.
Pull request overview
This PR hardens WebViewActivity against crashes caused by devices missing/disabled Android System WebView (reported in #1256) by handling the failure gracefully instead of letting onCreate crash the process.
Changes:
- Wrap
setContentView(activity_webview)+LilicoWebView.loadUrl(...)in a try/catch and finish the activity after showing an error toast. - Add a new user-facing string (
webview_unavailable) for the toast message.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| app/src/main/java/com/flowfoundation/wallet/page/common/WebViewActivity.kt | Adds exception handling around WebView inflation/loading, logs, toasts, and finishes instead of crashing. |
| app/src/main/res/values/strings.xml | Adds the localized message shown when WebView is unavailable. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| try { | ||
| setContentView(R.layout.activity_webview) | ||
| findViewById<LilicoWebView>(R.id.webview).apply { | ||
| loadUrl(this@WebViewActivity.url!!) | ||
| } | ||
| } catch (e: AndroidRuntimeException) { | ||
| loge(e) | ||
| toast(R.string.webview_unavailable, Toast.LENGTH_LONG) | ||
| finish() | ||
| } catch (e: Exception) { | ||
| loge(e) | ||
| toast(R.string.webview_unavailable, Toast.LENGTH_LONG) | ||
| finish() |
There was a problem hiding this comment.
The new broad catch (e: Exception) will also catch unrelated failures (e.g., url!! NPE if the intent extra is missing after process death / external launch) and then shows webview_unavailable, which would be misleading and make debugging harder. Consider validating url before entering the WebView inflate/load block (and handling a missing URL separately), and limit the webview_unavailable toast to the specific WebView-provider failure (e.g., only for the known WebView inflation exception), while letting unexpected exceptions surface or showing a generic error.
| } catch (e: AndroidRuntimeException) { | ||
| loge(e) | ||
| toast(R.string.webview_unavailable, Toast.LENGTH_LONG) | ||
| finish() | ||
| } catch (e: Exception) { | ||
| loge(e) | ||
| toast(R.string.webview_unavailable, Toast.LENGTH_LONG) | ||
| finish() |
There was a problem hiding this comment.
Both catch blocks have identical handling. If the intent is just to guard WebView inflation, this can be simplified (single catch + type/cause check, or a small helper) to avoid duplication and reduce the chance the handlers diverge later.
| toast(R.string.webview_unavailable, Toast.LENGTH_LONG) | ||
| finish() | ||
| } catch (e: Exception) { | ||
| loge(e) | ||
| toast(R.string.webview_unavailable, Toast.LENGTH_LONG) |
There was a problem hiding this comment.
toast(R.string.webview_unavailable, Toast.LENGTH_LONG) does not match the toast(msgRes: Int = 0, msg: String? = null, duration: Int = ...) helper signature (the second positional parameter is msg: String?). This should be passed as a named argument (duration = Toast.LENGTH_LONG) or by providing msg = null explicitly; otherwise this will not compile.
| toast(R.string.webview_unavailable, Toast.LENGTH_LONG) | |
| finish() | |
| } catch (e: Exception) { | |
| loge(e) | |
| toast(R.string.webview_unavailable, Toast.LENGTH_LONG) | |
| toast(R.string.webview_unavailable, duration = Toast.LENGTH_LONG) | |
| finish() | |
| } catch (e: Exception) { | |
| loge(e) | |
| toast(R.string.webview_unavailable, duration = Toast.LENGTH_LONG) |
Closes #1256
What is happening
WebViewActivity.onCreatecallssetContentView(R.layout.activity_webview)and thenloadUrlon the inflatedLilicoWebView. On a small but nonzero share of devices the system WebView package is missing, disabled, or partially updated, and inflating any view that depends on it throwsandroid.util.AndroidRuntimeException: java.lang.RuntimeException: Cannot load WebView. BecauseonCreatelets the exception escape, the process crashes and the user sees a generic Android error dialog with no idea what to do about it.The Firebase report linked in #1256 has this exact stack trace, with the failure originating from
MissingWebViewPackageExceptioninside the platform code.What this PR does
It wraps the inflate and
loadUrlcalls in a small try/catch. When the WebView package is missing the activity logs the error, shows a localized toast pointing the user at the Play Store entry for Android System WebView, and finishes itself instead of crashing. The same handler also catches the broaderExceptionso future variants of the same problem do not slip through.The new string
webview_unavailableis added tovalues/strings.xmlonly. Translators can pick it up later through the normal localization flow.