为什么 Android OS 8 WebVew with HTML select 标签会导致应用程序崩溃
Why does Android OS 8 WebVew with HTML select tag crash the app
我有一个混合 Cordova Android 应用程序,当用户在 Android WebView
运行 中点击下拉框时应用程序崩溃OS 8. 我创建了一个带有 <select>
标签的简单页面,该问题可重现。我有一个解决方法,就是对 select 发出我自己的弹出警报,但只是想知道这是否发生在其他人身上以及这是否是 OS8 WebView
错误。
下面是带有 <select>
标签的简单页面
https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_select
下面是我的崩溃日志
11:04:58.643 3208-3208/com.****.****E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.****.****, PID: 3208 android.content.res.Resources$NotFoundException: Resource ID #0x0
at android.content.res.ResourcesImpl.getValue(ResourcesImpl.java:195)
at android.content.res.Resources.loadXmlResourceParser(Resources.java:2133)
at android.content.res.Resources.getLayout(Resources.java:1142)
at android.view.LayoutInflater.inflate(LayoutInflater.java:421)
at android.widget.ArrayAdapter.createViewFromResource(ArrayAdapter.java:416)
at android.widget.ArrayAdapter.getView(ArrayAdapter.java:407)
at org.chromium.content.browser.input.SelectPopupAdapter.getView(SelectPopupAdapter.java:53)
at android.widget.AbsListView.obtainView(AbsListView.java:2372)
at android.widget.ListView.measureHeightOfChildren(ListView.java:1408)
at android.widget.ListView.onMeasure(ListView.java:1315)
at android.view.View.measure(View.java:21998)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6580)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.view.View.measure(View.java:21998)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6580)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.view.View.measure(View.java:21998)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6580)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1514)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:806)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:685)
at android.view.View.measure(View.java:21998)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6580)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.view.View.measure(View.java:21998)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6580)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.view.View.measure(View.java:21998)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6580)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at com.android.internal.policy.DecorView.onMeasure(DecorView.java:721)
at android.view.View.measure(View.java:21998)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2410)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1471)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1751)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1386)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6733)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911)
at android.view.Choreographer.doCallbacks(Choreographer.java:723)
at android.view.Choreographer.doFrame(Choreographer.java:658)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
我的问题和这个不一样
Trying to open SELECT tag in Android WebView crashes the application
2018 年 1 月 9 日更新:
我还没有找到解决方案,我的临时解决方法是删除标签并只使用输入。当用户 select 这个元素时,我们将事件传递给本机代码以弹出 selection 的对话框,并在用户输入 selection 后更新输入。
2018 年 3 月 23 日更新:
经过更多调查后,我注意到它只会在 WebView 位于片段中时崩溃,但不会在 Activity.
中崩溃
我从这个 post 中找到以下评论:
Trying to open SELECT tag in Android WebView crashes the application
"单击 SELECT 标记时,Android 使用本机 AlertDialog 在内部显示其选项。
Webview 必须使用 Activity 上下文创建,因为 AlertDialog 实例需要 Activity 上下文。"
我认为这是 Android 中的一个错误,可能没有正确处理 Fragment 的上下文。
2018 年 4 月 17 日更新:
正如 kenyee 所指出的,从这里 https://issuetracker.google.com/issues/77246450,Google 说
You mustn't subclass the resources object - this was never supported and was only possible by accident (which is why it's now marked deprecated). The framework needs to know about all the resources objects so that it can update them when webview is loaded (since webview adds additional paths to the asset manager).
编辑 2018 年 11 月 29 日
看来这个问题困扰了很多人。
- 我尝试并测试过的解决方案是不子class资源。
- 更新编译 sdk 和支持的库版本对某些人有效。
- 向资源添加包装器 class 可能会奏效,我在初步调查期间尝试过这种方法,它解决了 Select 崩溃问题,当您单击并按住文本时仍然崩溃查看弹出"COPY"、"PASTE"选项。
我在 Android 8.0 上遇到了同样的问题。
最后我解决了。
尝试将您的 compileSdkVersion 更新为 26,
并将 com.android.support:appcompat-v7 更新为 26.
您似乎正在为 Textview 设置整数值。尝试使用 String.valueOf(value)
在 Textview 中设置值。
我深入研究了崩溃日志。虽然这个答案没有解决你的问题,但你可能会得到一些有用的见解
- Webiview 使用 this layout file select_dialog_singlechoice.xml for inflating Spinner item using ArrayAdaper
- 您收到资源未找到异常 from here
- 这意味着当您点击 select 标签时,您的 Webview 无法定位此资源文件
我不确定为什么它会在 Android 8.0 上发生,但我无法在 Android 8.0 模拟器上重现此问题
经过一些调查,我已将问题隔离到仅在 OS8 上的 Fragment 内的 WebView 中。我的解决方法是针对该特定流程使用 Activity 而不是 Fragment。在我看来,Fragment 有一个 Android 缺陷。
看起来像这个错误:
https://issuetracker.google.com/issues/77246450
不要子类化资源...显然不会修复。
也许您在 Activity
class 中使用自定义 ContextWrapper
。在我的例子中,我覆盖了 attachBaseContext
方法。检查此方法并使用 super.attachBaseContext(newBase)
.
如果有人仍然遇到这个问题,我发现甚至不是我的代码是 class 资源 class 而是 Google 支持库版本我正在使用的。更新了支持库版本,效果非常好!
不久前实际上找到了一个解决方法,它允许我们继续子类化 Resources
而不会导致我们的 WebView 崩溃。需要注意的是我们不能让我们的 WebView 看到我们的资源子类或与之交互,我们必须以编程方式创建 WebView。第一步是在 Resources 子类中公开方法以拉回原始资源。
假设我们的资源子类称为 CustomResourcesWrapper
,我们的 ContextWrapper
子类称为 CustomContextWrapper
。
首先我们更新 CustomResourcesWrapper
以便我们可以访问原始 Resources
对象
public class CustomResourcesWrapper {
public static Resources findOriginalResources(Context context) {
if (context.getResources() instanceof CustomResourcesWrapper) {
return ((CustomResourcesWrapper) context.getResources()).getOriginalResources();
}
if (context instanceof ContextWrapper) {
return findOriginalResources(((ContextWrapper) context).getBaseContext());
}
return context.getResources();
}
private Resources getOriginalResources() {
return originalResources;
}
}
我们还假设 CustomContextWrapper
看起来像这样...
public class CustomContextWrapper extends ContextWrapper {
private final Resources wrappedResources;
public CustomContextWrapper(Context base, Resources resources) {
super(base);
this.wrappedResources = resources;
}
@Override
public Resources getResources() {
return wrappedResources;
}
}
然后我们为"unwrap"我们的自定义资源创建一个静态辅助方法并隐藏它们
// the method name is a bit of a misnomer,
// we're actually unwrapping, then re-wrapping
public static Context unwrapCustomContext(Context wrapped) {
Resources originalResources = CustomResourcesWrapper.findOriginalResources(wrapped);
Context customUnwrappedContext = new CustomContextWrapper(wrapped, originalResources);
return new ContextThemeWrapper(customUnwrappedContext, android.support.v7.appcompat.R.style.Theme_AppCompat_Light);
}
当需要创建 WebView 时,确保我们传递给它的 Context
通过上述方法运行,即 WebView webView = new WebView(unwrapCustomContext(context))
。我不是 100% 确定为什么,但是 ContextThemeWrapper
是这个 hack 的必需部分。
在 AndroidX 领域(限制为最低 compileSDKVersion 28),我也在带有弹出微调器的 Marshmallow 模拟器上遇到了这个问题。我不会去资源附近的任何地方,所以这仍然是支持库之一的平台问题。
我设法让它工作 - 不是通过将 webview 移动到 Activity(尽管我确实尝试过,这是不必要的), - 而是通过使用包装上下文和标准 AppCompat 以编程方式添加它主题:
val webView = WebView(ContextThemeWrapper(activity, R.style.Theme_AppCompat_Light))
binding.webViewContainer.addView(webView)
我不明白 wtf 是怎么回事,但现在可以了。祝大家好运!
编辑
我对此进行了更多研究,发现了对我造成问题的依赖性。 material 组件库的一个特定版本实际上在 webviews 中引入了这一点(准确地说是 1.1.0-alpha06)。 I have asked a question on it here,带有示例项目。
我有一个混合 Cordova Android 应用程序,当用户在 Android WebView
运行 中点击下拉框时应用程序崩溃OS 8. 我创建了一个带有 <select>
标签的简单页面,该问题可重现。我有一个解决方法,就是对 select 发出我自己的弹出警报,但只是想知道这是否发生在其他人身上以及这是否是 OS8 WebView
错误。
下面是带有 <select>
标签的简单页面
https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_select
下面是我的崩溃日志
11:04:58.643 3208-3208/com.****.****E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.****.****, PID: 3208 android.content.res.Resources$NotFoundException: Resource ID #0x0
at android.content.res.ResourcesImpl.getValue(ResourcesImpl.java:195)
at android.content.res.Resources.loadXmlResourceParser(Resources.java:2133)
at android.content.res.Resources.getLayout(Resources.java:1142)
at android.view.LayoutInflater.inflate(LayoutInflater.java:421)
at android.widget.ArrayAdapter.createViewFromResource(ArrayAdapter.java:416)
at android.widget.ArrayAdapter.getView(ArrayAdapter.java:407)
at org.chromium.content.browser.input.SelectPopupAdapter.getView(SelectPopupAdapter.java:53)
at android.widget.AbsListView.obtainView(AbsListView.java:2372)
at android.widget.ListView.measureHeightOfChildren(ListView.java:1408)
at android.widget.ListView.onMeasure(ListView.java:1315)
at android.view.View.measure(View.java:21998)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6580)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.view.View.measure(View.java:21998)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6580)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.view.View.measure(View.java:21998)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6580)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1514)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:806)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:685)
at android.view.View.measure(View.java:21998)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6580)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.view.View.measure(View.java:21998)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6580)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.view.View.measure(View.java:21998)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6580)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at com.android.internal.policy.DecorView.onMeasure(DecorView.java:721)
at android.view.View.measure(View.java:21998)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2410)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1471)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1751)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1386)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6733)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911)
at android.view.Choreographer.doCallbacks(Choreographer.java:723)
at android.view.Choreographer.doFrame(Choreographer.java:658)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
我的问题和这个不一样
Trying to open SELECT tag in Android WebView crashes the application
2018 年 1 月 9 日更新: 我还没有找到解决方案,我的临时解决方法是删除标签并只使用输入。当用户 select 这个元素时,我们将事件传递给本机代码以弹出 selection 的对话框,并在用户输入 selection 后更新输入。
2018 年 3 月 23 日更新: 经过更多调查后,我注意到它只会在 WebView 位于片段中时崩溃,但不会在 Activity.
中崩溃我从这个 post 中找到以下评论:
Trying to open SELECT tag in Android WebView crashes the application
"单击 SELECT 标记时,Android 使用本机 AlertDialog 在内部显示其选项。 Webview 必须使用 Activity 上下文创建,因为 AlertDialog 实例需要 Activity 上下文。"
我认为这是 Android 中的一个错误,可能没有正确处理 Fragment 的上下文。
2018 年 4 月 17 日更新:
正如 kenyee 所指出的,从这里 https://issuetracker.google.com/issues/77246450,Google 说
You mustn't subclass the resources object - this was never supported and was only possible by accident (which is why it's now marked deprecated). The framework needs to know about all the resources objects so that it can update them when webview is loaded (since webview adds additional paths to the asset manager).
编辑 2018 年 11 月 29 日 看来这个问题困扰了很多人。
- 我尝试并测试过的解决方案是不子class资源。
- 更新编译 sdk 和支持的库版本对某些人有效。
- 向资源添加包装器 class 可能会奏效,我在初步调查期间尝试过这种方法,它解决了 Select 崩溃问题,当您单击并按住文本时仍然崩溃查看弹出"COPY"、"PASTE"选项。
我在 Android 8.0 上遇到了同样的问题。 最后我解决了。 尝试将您的 compileSdkVersion 更新为 26, 并将 com.android.support:appcompat-v7 更新为 26.
您似乎正在为 Textview 设置整数值。尝试使用 String.valueOf(value)
在 Textview 中设置值。
我深入研究了崩溃日志。虽然这个答案没有解决你的问题,但你可能会得到一些有用的见解
- Webiview 使用 this layout file select_dialog_singlechoice.xml for inflating Spinner item using ArrayAdaper
- 您收到资源未找到异常 from here
- 这意味着当您点击 select 标签时,您的 Webview 无法定位此资源文件
我不确定为什么它会在 Android 8.0 上发生,但我无法在 Android 8.0 模拟器上重现此问题
经过一些调查,我已将问题隔离到仅在 OS8 上的 Fragment 内的 WebView 中。我的解决方法是针对该特定流程使用 Activity 而不是 Fragment。在我看来,Fragment 有一个 Android 缺陷。
看起来像这个错误: https://issuetracker.google.com/issues/77246450
不要子类化资源...显然不会修复。
也许您在 Activity
class 中使用自定义 ContextWrapper
。在我的例子中,我覆盖了 attachBaseContext
方法。检查此方法并使用 super.attachBaseContext(newBase)
.
如果有人仍然遇到这个问题,我发现甚至不是我的代码是 class 资源 class 而是 Google 支持库版本我正在使用的。更新了支持库版本,效果非常好!
不久前实际上找到了一个解决方法,它允许我们继续子类化 Resources
而不会导致我们的 WebView 崩溃。需要注意的是我们不能让我们的 WebView 看到我们的资源子类或与之交互,我们必须以编程方式创建 WebView。第一步是在 Resources 子类中公开方法以拉回原始资源。
假设我们的资源子类称为 CustomResourcesWrapper
,我们的 ContextWrapper
子类称为 CustomContextWrapper
。
首先我们更新 CustomResourcesWrapper
以便我们可以访问原始 Resources
对象
public class CustomResourcesWrapper {
public static Resources findOriginalResources(Context context) {
if (context.getResources() instanceof CustomResourcesWrapper) {
return ((CustomResourcesWrapper) context.getResources()).getOriginalResources();
}
if (context instanceof ContextWrapper) {
return findOriginalResources(((ContextWrapper) context).getBaseContext());
}
return context.getResources();
}
private Resources getOriginalResources() {
return originalResources;
}
}
我们还假设 CustomContextWrapper
看起来像这样...
public class CustomContextWrapper extends ContextWrapper {
private final Resources wrappedResources;
public CustomContextWrapper(Context base, Resources resources) {
super(base);
this.wrappedResources = resources;
}
@Override
public Resources getResources() {
return wrappedResources;
}
}
然后我们为"unwrap"我们的自定义资源创建一个静态辅助方法并隐藏它们
// the method name is a bit of a misnomer,
// we're actually unwrapping, then re-wrapping
public static Context unwrapCustomContext(Context wrapped) {
Resources originalResources = CustomResourcesWrapper.findOriginalResources(wrapped);
Context customUnwrappedContext = new CustomContextWrapper(wrapped, originalResources);
return new ContextThemeWrapper(customUnwrappedContext, android.support.v7.appcompat.R.style.Theme_AppCompat_Light);
}
当需要创建 WebView 时,确保我们传递给它的 Context
通过上述方法运行,即 WebView webView = new WebView(unwrapCustomContext(context))
。我不是 100% 确定为什么,但是 ContextThemeWrapper
是这个 hack 的必需部分。
在 AndroidX 领域(限制为最低 compileSDKVersion 28),我也在带有弹出微调器的 Marshmallow 模拟器上遇到了这个问题。我不会去资源附近的任何地方,所以这仍然是支持库之一的平台问题。
我设法让它工作 - 不是通过将 webview 移动到 Activity(尽管我确实尝试过,这是不必要的), - 而是通过使用包装上下文和标准 AppCompat 以编程方式添加它主题:
val webView = WebView(ContextThemeWrapper(activity, R.style.Theme_AppCompat_Light))
binding.webViewContainer.addView(webView)
我不明白 wtf 是怎么回事,但现在可以了。祝大家好运!
编辑 我对此进行了更多研究,发现了对我造成问题的依赖性。 material 组件库的一个特定版本实际上在 webviews 中引入了这一点(准确地说是 1.1.0-alpha06)。 I have asked a question on it here,带有示例项目。