Why does Android OS 8 WebVew with HTML select tag crash the app

前端 未结 9 2604
傲寒
傲寒 2020-12-15 20:24

I\'ve got a hybrid Cordova Android app, and the app crashes when user tap on a drop-down box in my WebView running on Android OS 8. I\'ve created a simple page

相关标签:
9条回答
  • 2020-12-15 21:13

    After some investigation, I've isolated the issue to WebView inside Fragment on OS8 only. My workaround is to use Activity instead of Fragment for that particular flow. It seems to me an Android defect in Fragment.

    0 讨论(0)
  • 2020-12-15 21:14

    I digged into crash logs. Though this answer does not solve your problem, you might get some useful insights

    • Webiview uses this layout file select_dialog_singlechoice.xml for inflating Spinner item using ArrayAdaper
    • You are getting Resource not found Exception from here
    • It means that Your Webview is not able to locate this resource file when you click on select tag

    I am not sure why it's happening on Android 8.0,i was not able to reproduce this on Android 8.0 emulator though

    0 讨论(0)
  • 2020-12-15 21:14

    Actually found a workaround for this a little while ago that allowed us to continue subclassing Resources and not crash our WebViews. The caveat is we can't let our WebView see or interact with our resources subclass AND we must create the WebView programmaticaly. The first step is exposing method in the Resources subclass to pull the original resources back out.

    Lets say our resources subclass is called CustomResourcesWrapper and our ContextWrapper subclass is called CustomContextWrapper.

    First we update the CustomResourcesWrapper so we can access the original Resources object

    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;
        }
    }
    

    We're also assuming the CustomContextWrapper looks something like this...

    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;
        }
    }
    

    Then we create a static helper method to "unwrap" our custom resources and hide them

    // 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);
    }
    

    When it comes time to create a WebView, do it ensure the Context we pass to it runs through the above method i.e. WebView webView = new WebView(unwrapCustomContext(context)). I'm not 100% sure why, but the ContextThemeWrapper is a required part of this hack.

    0 讨论(0)
提交回复
热议问题