WebView Crash on Android 5-5.1 (API 21-22) Resources$NotFoundException: String resource ID #0x2040002
I am in the process of updating an Android app from API 27 to API 29 and I noticed that I get a crash when trying to render a WebView on an emulator based on 5.0 and/or 5.1. This issue does not happen on an emulator running 6.0 or higher (API 23-29).
I cannot seem to find any documentation about WebView behaviour that would affect 5.0 or 5.1 but I can confirm the problem doesn't happen when I run the app using API 27. I am at a loss as I don't know if this is an emulator problem or an actual API/device issue (I am thinking the latter).
The issue is the Activity and Fragment won't inflate at all, due to a missing String resource. Here is some of the stacktrace (it can't seem to find a String resource):
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.MyActivity}: android.view.InflateException: Binary XML file line #15: Error inflating class com.example.MyWebView
Caused by: android.view.InflateException: Binary XML file line #15: Error inflating class com.example.MyWebView...
Caused by: java.lang.reflect.InvocationTargetException...
Caused by: android.content.res.Resources$NotFoundException: String resource ID #0x2040002
Before the crash happens, there is some related warnings in the logs related to the resource:
W/chromium: [WARNING:resource_bundle.cc(315)] locale_file_path.empty()
E/eglCodecCommon: glUtilsParamSize: unknow param 0x000082da
E/eglCodecCommon: glUtilsParamSize: unknow param 0x00008cdf
E/eglCodecCommon: glUtilsParamSize: unknow param 0x00008824
W/chromium: [WARNING:proxy_service.cc(901)] PAC support disabled because there is no system implementation
W/chromium: [WARNING:data_reduction_proxy_settings.cc(403)] SPDY proxy OFF at startup
W/ResourceType: No known package when getting value for resource number 0x02040002
WebView:
public class MyWebView extends WebView {
public MyWebView (Context context) {
super(context);
initialize();
}
public MyWebView (Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
public MyWebView (Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize();
}
public MyWebView (Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initialize();
}
public MyWebView(Context context, AttributeSet attrs, int defStyleAttr, boolean privateBrowsing) {
super(context, attrs, defStyleAttr, privateBrowsing);
initialize();
}
private void initialize() {
this.clearCache(true);
this.clearHistory();
this.getSettings().setJavaScriptEnabled(true);
this.getSettings().setLoadsImagesAutomatically(true);
this.getSettings().setUseWideViewPort(true);
this.getSettings().setAllowContentAccess(false);
this.getSettings().setAllowFileAccess(false);
this.getSettings().setAllowFileAccessFromFileURLs(false);
this.getSettings().setAllowUniversalAccessFromFileURLs(false);
this.getSettings().setDomStorageEnabled(false);
this.getSettings().setAppCacheEnabled(false);
this.getSettings().setDatabaseEnabled(false);
this.getSettings().setGeolocationEnabled(false);
this.getSettings().setSaveFormData(false);
this.getSettings().setSupportMultipleWindows(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
this.getSettings().setSafeBrowsingEnabled(false);
}
}
}
Layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<com.example.MyWebView
android:id="@+id/my_web_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Any ideas what I am doing wrong or what may have changed in API 28 or 29 that could break this?
I went through the same trouble and actually what solved it was changing the context in the constructor to context.getApplicationContext()
.
After that it's building and rendering with no problems on Android 5.
It seems to be a bug with appcompat 1.1.0 - https://issuetracker.google.com/issues/141132133
While you can try downgrading appcompat or wait for a fix, you can also try
Using a custom WebView:
private fun Context.getLollipopFixWebView(): Context {
return if (Build.VERSION.SDK_INT in 21..22) {
createConfigurationContext(Configuration())
} else this
}
/**
* Workaround appcompat-1.1.0 bug https://issuetracker.google.com/issues/141132133
*/
class LollipopFixWebView(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) :
WebView(context.getLollipopFixWebView(), attrs, defStyle)
Or adding this workaround to the parent Activity of your WebView:
// Workaround appcompat-1.1.0 bug https://issuetracker.google.com/issues/141132133
override fun applyOverrideConfiguration(overrideConfiguration: Configuration) {
if (Build.VERSION.SDK_INT in 21..22) {
return
}
super.applyOverrideConfiguration(overrideConfiguration)
}
Credits and kudos to https://github.com/ankidroid/Anki-Android/issues/5507 There the guy believes it's happening to Android 7 as well but I couldn't replicate
Updates
The custom WebView solution may introduce a new problem: keyboard not showing for all Android versions.
So we'll need to set isFocusable
and isFocusableInTouchMode
to the custom WebView class prevent such problem
class LollipopFixWebView : WebView {
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context.getLollipopFixWebView(), attrs, defStyleAttr) {
isFocusable = true
isFocusableInTouchMode = true
}
}
Disclaimers
My minSdk
version is 21 (Lollipop) so can't guarantee my solution works for apps with lower minSdk version
Fixed in androidx.appcompat:appcompat:1.2.0-alpha02
Just update your app build.gradle
file with line:
implementation "androidx.appcompat:appcompat:1.2.0-alpha02"
It seems to be a bug with appcompat 1.1.0 - https://issuetracker.google.com/issues/141132133
Looking at #30 in that discussion, this solved my problem:
// add to gradle module:app
configurations.all {
resolutionStrategy {
force 'androidx.appcompat:appcompat:1.1.0-rc01'
}
}