Giter Site home page Giter Site logo

wkwebview crashes about origami HOT 23 CLOSED

hotforfeature avatar hotforfeature commented on July 30, 2024
wkwebview crashes

from origami.

Comments (23)

hotforfeature avatar hotforfeature commented on July 30, 2024 1

I think it's a WKWebView bug with something <paper-textarea> is doing. It only happens when creating the element from document.createElement(). It doesn't happen when the markup is parsed by the browser (that's why wrapping it works).

I'd actually recommend opening a bug on https://github.com/PolymerElements/paper-input. They can do more investigating to figure out why that error is thrown when creating a textarea programmatically.

There may not be anything the Polymer team can do with their element, but it'd be the starting point to create a bug with Apple and link details. Should also help raise awareness incase someone tries to use <paper-textarea> with another framework like Angular that uses document.createElement().

from origami.

hotforfeature avatar hotforfeature commented on July 30, 2024

I have experience with UIWebView and WKWebView in the Angular 2 context, but not with Polymer.

I would assume UIWebView (the default for cordova-based projects) would have memory issues, but not WKWebView. If this is a cordova project I'd first do a sanity check and make sure the plugins you have to force WKWebView are working.

Next, are you serving ES6 or ES5-compiled in the web view, and are you using WeakMaps in your components? That's my first big warning flag with memory issues and ES6 since polyfilled WeakMaps are notorious for memory leaks.

If you're positive WKWebView is working and you don't have any obvious ES6-related memory leak areas like WeakMap, the next step I'd do is to take a JS memory profile of the WKWebView until you get the error and see what objects are eating up the memory.

I haven't heard of nor seen anything yet with Polymer or Angular and memory leaks, nor have I seen anything yet with Origami that could cause a leak. They are notoriously difficult bugs to find though...

from origami.

BorntraegerMarc avatar BorntraegerMarc commented on July 30, 2024

Thanks for the answer. It's not a cordova app but a normal web app, which gets called with wkwebview.

Just one question: what do you mean with "WeakMaps in your components"?

Are there different build options with polymer build to include or exclude these?

from origami.

hotforfeature avatar hotforfeature commented on July 30, 2024

The WeakMap is a type of Map in JavaScript that stores values by weak object reference instead of strings. That means when an object gets garbage collected, the WeakMap reference and value are also garbage collected.

Polyfills for a WeakMap have no way to do this natively, which results in a small memory leak on older browsers (or if the polyfill is being used instead of the native WeakMap). They're not a hidden feature or anything, you'd know if you were using them so I'm gonna guess they aren't the cause.

I think I'm a bit confused on how your web app is being called. Just through Safari or Chrome on iOS like a normal webpage? Or are you using a separate native app to view the webpage? What iOS version are you on?

from origami.

BorntraegerMarc avatar BorntraegerMarc commented on July 30, 2024

The app gets called in two separate ways:

  1. Like a normal web page through Google chrome
  2. Through our native iOS app with WkWebView

So our approach was to build only a native app for iOS to fill the gaps of the ServiceWorker (like to enable push notifications, offline support, etc.). Which Safari, obviously doesn't have but chrome does.

On Google chrome (all versions) the app works without issues. Still need to run the JS Profile though...

And on our Safari native app the web app crashes after approximately 5-7 seconds on interaction. So the process:

  1. The app loads within 3 seconds
  2. The user logs in
  3. The user starts using the app for about 5 seconds
  4. Total crash happens without error message. So screen just gets blank.

This is the browser version of WkWebView (verified with http://www.whoishostingthis.com/tools/user-agent/):

Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_2 like Mac OS X) AppleWebKit/603.2.4 (KHTML, like Gecko) Mobile/14F89

So we're serving the Polymer ES6 bundled directory. Generated like described in https://github.com/hotforfeature/origami/blob/master/docs/production-build.md. Because Safari 10 should be able to handle ES6.

The behavior can get reproduced with both WkWebView and native Safari.

I will test now the behavior with ES5...

from origami.

BorntraegerMarc avatar BorntraegerMarc commented on July 30, 2024

Update: We have identified that the root cause for the out of ram issue is this line of code:

@ViewChild('messageInput') private messageInput: ElementRef;

const targetElement = this.messageInput.nativeElement.shadowRoot.querySelector('#input').shadowRoot.querySelector('#textarea');

And targetElement is null. Surprising thing is that this error only happens on safari iOS. @hotforfeature is there another way we need to access the shadow root on safari iOS?

from origami.

BorntraegerMarc avatar BorntraegerMarc commented on July 30, 2024

After some debugging we found out the following:
We wrote these debug statements:

       const msgInputElem: any = this.messageInput.nativeElement;
       var targetElement: any;

       console.debug(msgInputElem);
       console.debug(Polymer.dom);
       console.debug(‘Polymer.dom(this.messageInput.nativeElement):‘);
       console.debug(Polymer.dom(this.messageInput.nativeElement));
       console.debug(‘Polymer.dom(this.messageInput.nativeElement).shadowRoot:‘);
       console.debug(Polymer.dom(this.messageInput.nativeElement).shadowRoot);

       // shadowRoot not supported by all browsers
       if(this.messageInput.nativeElement.shadowRoot) {
           targetElement = msgInputElem.shadowRoot.querySelector(‘#input’).shadowRoot.querySelector(‘#textarea’);
       } else if (Polymer.dom(this.messageInput.nativeElement)) {
           targetElement = Polymer.dom(this.messageInput.nativeElement);
           console.debug(‘check’);

           if(targetElement) {
               console.debug(‘node.querySelector --> ‘);
               const node = Polymer.dom(this.messageInput.nativeElement).node;
               console.debug(node.querySelector);
               const input = node.querySelector(‘#input’);
               console.debug(‘input’);
               console.debug(input);
               console.debug(‘.querySelector(#textarea)‘);
               console.debug(input.querySelector(‘#textarea’));

               targetElement = input.querySelector(‘#textarea’);
               console.debug(targetElement);
           }
       }

This code generates the following output:
untitled

What I have troubles understanding, is why console.debug(input); results into null. But on safari desktop the above code works. So I thought it is maybe an angular/polymer issue on WkWebView?

from origami.

hotforfeature avatar hotforfeature commented on July 30, 2024

I'm still not entirely convinced WKWebView is being used here, since I would expect to see the word Safari/x at the end of the user agent string after Mobile/14F89. I would use this SO answer example to do some deeper checking and ensure WKWebView is being used.

Polymer.dom should be deprecated for the most part. It really only serves as a legacy patch for Polymer 1.x/2.x elements that need to use Polymer.dom for 1.x features. shadowRoot is natively available on Safari and polyfilled when using webcomponentsjs. Can you add a line for console.log('shadowRoot', 'shadowRoot' in document.createElement('div'));?

Finally, are you using webcomponentjs at all, and if so, are you using webcomponentsReady() from Origami before bootstrapping in main.ts?

from origami.

BorntraegerMarc avatar BorntraegerMarc commented on July 30, 2024

Thanks again for your great support @hotforfeature. Here are my answers:

Running this code:

console.log(‘shadowRoot’, ‘shadowRoot’ in document.createElement(‘div’));

Gave the output: shadowRoot - true

Running this code:

    if (navigator.platform.substr(0,2) === 'iP'){
      //iOS (iPhone, iPod or iPad)
      var lte9 = /constructor/i.test(window.HTMLElement);
      var nav = window.navigator, ua = nav.userAgent, idb = !!window.indexedDB;
      if (ua.indexOf('Safari') !== -1 && ua.indexOf('Version') !== -1 && !nav.standalone){      
        //Safari (WKWebView/Nitro since 6+)
console.log('Safari');
      } else if ((!idb && lte9) || !window.statusbar.visible) {
        //UIWebView
console.log('UIWebView');
      } else if ((window.webkit && window.webkit.messageHandlers) || !lte9 || idb){
        //WKWebView
console.log('WKWebView');
      }
    }

Gave the output "WKWebView". Additionally we ran the test on http://www.whoishostingthis.com/tools/user-agent/ again and got exactly the same: Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_2 like Mac OS X) AppleWebKit/603.2.4 (KHTML, like Gecko) Mobile/14F89
Tested with an hardware iPhone 5 with a WKWebView native app. I'm 110% sure that we are testing it with a WKWebView application.

Are you sure that shadow root is available in WKWebView? Because accessing it with this.messageInput.nativeElement.shadowRoot gives us null. This is the reason we went back to using Polymer.dom.

Yes we are using webcomponentjs: <script src="assets/bower_components/webcomponentsjs/webcomponents-loader.js"></script> and we are listening for webcomponentsReady() from Origami:

webcomponentsReady().then(() => {
  if (environment.production) {
    enableProdMode();
  }

  platformBrowserDynamic().bootstrapModule(AppModule, {
    enableLegacyTemplate: false
  }).then(() => {
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register('/worker-basic.min.js');
    }
  });
}).catch(error => {
  // No WebComponent support and webcomponentsjs is not loaded
  console.error(error);
});

from origami.

BorntraegerMarc avatar BorntraegerMarc commented on July 30, 2024

Got the idea to use Polymer.dom from here: https://stackoverflow.com/questions/43937386/queryselector-not-working-in-shadow-dom-in-polymer-2

from origami.

hotforfeature avatar hotforfeature commented on July 30, 2024

iOS 10 WKWebView natively supports Shadow DOM, so yes you should be good to go.

shadowRoot will be null if .attachShadow({ mode: 'open' }) hasn't been called yet. Perhaps that's where the problem lies.

Ahh, I see something I didn't catch in your screenshot:
screen shot 2017-06-26 at 12 07 55 pm

I'm betting your element is defining attributes on itself via setAttribute() in its constructor before the connectedCallback() is called (attached() in legacy Polymer). This is throwing an error, which stops the element from being instantiated and attachShadow() from being called.

from origami.

BorntraegerMarc avatar BorntraegerMarc commented on July 30, 2024

Hmm, the thing is: It's not my element. It's a PolymerElement. This is what's behind @ViewChild('messageInput'):

<paper-textarea #messageInput autocomplete="on" label="{{'chat.type' | translate}}" id="newMessage" class="form-control create-message-input"
                    name="newMessage" no-label-float max-rows="5" auto-validate="false" (keydown)="createMessageInputKeyPressed($event)"
                    (keypress)="createMessageInputKeyPressed($event)" formControlName="newMessage"></paper-textarea>

So I kinda doubt that google messed up the setAttribute() method. Additionally we made sure that exactly this line is causing the error. So we commented out const targetElement = this.messageInput.nativeElement.shadowRoot.querySelector('#input').shadowRoot.querySelector('#textarea');

I'm working on a open repository now, where the error could get reproduced.

from origami.

BorntraegerMarc avatar BorntraegerMarc commented on July 30, 2024

OK, finished our experiments now. We ran the following tests:

  1. We generated a normal polymer project with Polymer starter kit and everything worked as excpected. So the error only comes up if angular (or origami) is included
  2. We created this minimal origami project: https://github.com/BorntraegerMarc/polymer-chat and the WKWebView crashes at the exact same component. Because of this: https://github.com/BorntraegerMarc/polymer-chat/blob/master/src/app/message/input/message-input.component.html#L3
  3. If you completely comment out the paper-textarea component from the HTML it works without issue. So the TS reference @ViewChild('messageInput') has no influence on it. when we commented out @ViewChild the same issue persisted. Ony when commenting out the HTML code the app started to work again.

For easy testing purposes we created the following iOS native app project: https://github.com/kmyllyvi/WKWebViewTester you can just clone & run it.
Which is just a WKWebView project. How to test:

  1. Clone and install the minimal origami project
  2. Clone and install the WKWebView project
  3. Start angular with ng serve
  4. Start the ios app project on an iPhone simulator and navigate to http://localhost:3000 (you can enter the URL in the actual app)

Maybe you see something @hotforfeature that I have missed?

from origami.

BorntraegerMarc avatar BorntraegerMarc commented on July 30, 2024

The issue can also be reproduced if you just generate a brand new angular project and add origami to it and then add the HTML line <paper-textarea label="test"></paper-textarea>

from origami.

BorntraegerMarc avatar BorntraegerMarc commented on July 30, 2024

Issue only is with paper-textarea. paper-input works perfectly

from origami.

hotforfeature avatar hotforfeature commented on July 30, 2024

Thanks for the details @BorntraegerMarc, I'll test it out as soon as I can

from origami.

BorntraegerMarc avatar BorntraegerMarc commented on July 30, 2024

Thx

from origami.

hotforfeature avatar hotforfeature commented on July 30, 2024

The prognosis does not look good. I tried stripping everything (including Origami and polyfills) from the demo app. The only thing I couldn't take out was the reflect shim and zone.js.

The Problem

Adding the <paper-textarea> to index.html was fine, but the DefaultDomRenderer2 could not create it without throwing the error "A newly constructed custom element must not have attributes".

This is the cause for things breaking. While document.createElement() lets you continue, the element it returns is actually an HTMLUnknownElement, and so naturally it doesn't open its Shadow DOM from extending Polymer.Element.

Raw vs Programmatic Element Creation

There are two ways to "create" an element: raw HTML and programatically. A Polymer project goes through raw HTML. It provides it directly to the browser to render.

Angular does things programmatically and calls document.createElement(). This is why you can do weird things like <paper-item class$="[[binding]]"> in Polymer but not Angular. class$ is not a valid attribute and throws an error when calling element.setAttribute('class$', '[[binding]]').

Not Just Angular!

So far, all the tests have just been isolated on <paper-textarea>. I'm testing with both this element and <paper-input>, since they're similar. <paper-input> is perfectly chill with document.createElement().

I've ruled out Origami as the problem, so I thought maybe something with zone.js or the reflect shim was adding attributes at element creation. I decided to turn to pure Polymer and take both of these and any other weird Angular shenanigans out of the picture.

https://raw-dot-custom-elements.appspot.com/PolymerElements/paper-input/v2.0.0/paper-input/demo/index.html

This is the demo file that we should navigate to within the WKWebView. It'll load up just fine and <paper-textarea> works. Inspect the console and run the following:

window.onerror = function(err) { debugger; console.log('error', err) };
var ele = document.createElement('paper-textarea');
console.log(ele instanceof HTMLUnknownElement);
console.log(ele instanceof customElements.get('paper-textarea'));

Output:

[Log] error – "NotSupportedError (DOM Exception 9): A newly constructed custom element must not have attributes"
[Error] NotSupportedError (DOM Exception 9): A newly constructed custom element must not have attributes
	createElement
	Console Evaluation (Console Evaluation 4:3)
	evaluateWithScopeExtension
	_evaluateOn
	_evaluateAndWrap
	evaluate
[Log] true
[Log] false

Thoughts

So, good news and bad news. This isn't a bug with Origami or Angular (hooray!). Bad news is this may be some sort of bug with WKWebView. Neither Safari nor Chrome report these attribute errors, nor do I see anything in <paper-textarea> that is doing something wrong.

I'm curious if this is a problem with the word "textarea". Maybe WKWebView sees that and is adding some textarea-specific attributes when it shouldn't be. I would take the next steps:

  1. Copy and paste paper-textarea's source and give it a new selector without the word "textarea" in it. See if that's the cause of pain.
  2. Create a new Polymer element that wraps paper-textarea. Since that Polymer element is "raw HTML", it can bypass document.createElement().

One of those two solutions may get paper-textarea working for you on WKWebView. If not, well you can always file a bug with Apple.. but good luck there :(

from origami.

BorntraegerMarc avatar BorntraegerMarc commented on July 30, 2024

Thanks for looking at this @hotforfeature. I'm gonna close the issue since it is not an issue with origami. But will update this issue as soon as we have tried out your suggestions.

from origami.

BorntraegerMarc avatar BorntraegerMarc commented on July 30, 2024

@hotforfeature OK, so I've tried renaming the element to paper-marci and the exact same error is happening. Here the code: https://github.com/BorntraegerMarc/paper-input

So your first suggestion

Copy and paste paper-textarea's source and give it a new selector without the word "textarea" in it. See if that's the cause of pain.

And couldn't even move to the second suggestion. My next step would be to file a bug with apple. Unless you got any more insights from my test?

from origami.

hotforfeature avatar hotforfeature commented on July 30, 2024

When I'm talking about wrapping, I mean to create a small element such as this:

<dom-module id="paper-wrapped">
  <template>
    <paper-textarea value="{{value}}"></paper-textarea>
  </template>
  <script>
    Polymer({
      is: 'paper-wrapped',
      properties: {
        value: {
          type: String,
          notify: true      
       }
      }
    });
  </script>
</dom-module>

Then try using <paper-wrapped> in Angular instead of <paper-textarea>. If it works, then you'll need to add additional input properties that you need to bind from Angular to the wrapped textarea.

The reason this might work is because the wrapper element's template (and <paper-textarea> element) is consumed all at once by the document instead of programmatically created by Angular.

from origami.

BorntraegerMarc avatar BorntraegerMarc commented on July 30, 2024

Heck, that did it @hotforfeature It fully works now 🎉
means, it is a weird WKWebView / angular bug?

from origami.

BorntraegerMarc avatar BorntraegerMarc commented on July 30, 2024

@hotforfeature FYI: if you wrap the component with all attributes, it still does not work. The property autocorrect seems to be causing the problem. Only if you remove that one property in the wrapped component it seems to work. (you don't even need to use the attribute in your element. It's already enough to provoke the crash if autocorrect is defined as an attribute)

from origami.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.