Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebView's injectJavaScript() method causes immediate crash #195

Open
shirakaba opened this issue May 7, 2018 · 6 comments
Open

WebView's injectJavaScript() method causes immediate crash #195

shirakaba opened this issue May 7, 2018 · 6 comments
Labels

Comments

@shirakaba
Copy link
Contributor

Description

Using the very same code from the master-branch UIExplorer's WebView examples, I found that WebView.prototype.injectJavaScript() causes an immediate crash, with the error:

undefined is not an object (evaluating 'UIManager.RCTWebView.Commands.injectJavaScript')
	 in injectJavaScript(at NetworkOverlay.js:195:6)
	 in injectJS(at VirtualizedSectionList.js:399:38)
	 in invokeGuardedCallback(at <unknown file>:0)
	 in invokeGuardedCallbackAndCatchFirstError(at View.js:139:2)
	 in executeDispatch(at <unknown file>:0)
	 in executeDispatchesInOrder(at ReactFiberScheduler.js:1179:6)
	 in executeDispatchesAndRelease(at <unknown file>:0)
	 in forEachAccumulated(at <unknown file>:0)
	 in processEventQueue(at toIterator.js:124:13)
	 in runEventQueueInBatch(at backend.js:471:48)
	 in handleTopLevel(at backend.js:478:13)
	 in <unknown>(at backend.js:422:43)
	 in perform(at backend.js:1732:17)
	 in batchedUpdatesWithControlledComponents(at ReactFiberScheduler.js:944:19)
	 in _receiveRootNodeIDEvent(at backend.js:421:16)
	 in receiveEvent(at backend.js:428:16)
	 in __callFunction(at MessageQueue.js:223:23)
	 in <unknown>(at MessageQueue.js:71:6)
	 in __guard(at MessageQueue.js:195:6)
	 in callFunctionReturnFlushedQueue(at MessageQueue.js:70:11)

WebView.macos.js

So although WebView.prototype.injectJavaScript() is present, UIManager.RCTWebView.Commands.injectJavaScript() is not.

Here's react-native-macos/Libraries/Components/WebView/WebView.macos.js.

Unfortunately, I can't figure out where it's requiring UIManager from; the closest I can get is react-native-macos/lib/UIManager.js.

Reproduction Steps and Sample Code

The UIExplorer repository can be used to reproduce this, or the following minimal example can be copied:

'use strict';

var React = require('React');
var ReactNative = require('react-native');
var {
  StyleSheet,
  Button,
  View,
  WebView,
} = ReactNative;

class InjectJS extends React.Component {
  webview = null;
  injectJS = () => {
    const script = 'document.write("Injected JS ")'; // eslint-disable-line quotes
    if (this.webview) {
      this.webview.injectJavaScript(script);
    }
  };
  render() {
    return (
      <View>
        <WebView
          ref={webview => {
            this.webview = webview;
          }}
          style={{
            backgroundColor: 'rgba(255,255,255,0.8)',
            height: 300,
          }}
          source={{ uri: 'https://en.wikipedia.org' }}
          scalesPageToFit={true}
        />
        <View style={styles.buttons}>
          <Button title="Inject JS" onPress={this.injectJS} />
        </View>
      </View>
    );
  }
}

var styles = StyleSheet.create({
  buttons: {
    flexDirection: 'row',
    height: 30,
    backgroundColor: 'black',
    alignItems: 'center',
    justifyContent: 'space-between',
  }
})

Additional Information

  • React Native version: react-native-macos v0.16.1
  • Platform: macOS
  • Development Operating System: macOS
  • Dev tools: Xcode 9.3

Comments

I notice that the "Inject JavaScript" demo is not displayed in UIExplorer (nor the "Messaging Test"); are these examples not yet fully implemented, and therefore is this behaviour to be expected?

@shirakaba
Copy link
Contributor Author

Potential root of problem

I see there's a module bundled into index.macos.bundle.js that corresponds to react-native-macos/Libraries/ReactNative/UIManager.js. It has some role in setting up the UIManager.RCTWebView.Commands, and therefore may explain why UIManager.RCTWebView.Commands.injectJavaScript is undefined:

/**
 * Copies the ViewManager constants and commands into UIManager. This is
 * only needed for iOS, which puts the constants in the ViewManager
 * namespace instead of UIManager, unlike Android.
 */
if (Platform.OS === 'ios') {
// ...
  defineLazyObjectProperty(viewConfig, 'Commands', {
    // ...
  }
} else if (Platform.OS === 'android' && UIManager.AndroidLazyViewManagersEnabled) {
// ...
}

Just a guess, but perhaps the if (Platform.OS === 'ios') clause should extend to macos too? Will try out.

Extending UIManager.Command initialisation to macos

I replaced the platform check with:

if (Platform.OS === 'ios' || Platform.OS === 'macos')

And indeed, it stops the crash, suggesting that I'm on the right track – but my document.write("Whatever") still isn't occurring, so I'm a bit perplexed.

@ptmt
Copy link
Owner

ptmt commented May 9, 2018

Thanks for reporting this. Hopefully, this will be fixed in latest version, which is in alpha now. I'll keep you posted.

@shirakaba
Copy link
Contributor Author

shirakaba commented May 9, 2018

@ptmt Thank you! Do you have any estimate of when the latest version's release might be?

I found that JS injection is now mysteriously working on my end. As far as I am aware, the only thing I changed, beyond the if (Platform.OS === 'ios' || Platform.OS === 'macos') amendment, is altering my Xcode project's info.plist's ATS settings by adding NSAllowsArbitraryLoadsInWebContent: YES. Of course, I was only ever working on HTTPS websites to begin with, so it's illogical that this might be exactly what fixed it. Maybe just a restart and a rebuild helped out.

Whether it would work now even without the amendment for macos, I don't know; I shall have to investigate next time I'm touching that part of the code.

@ptmt On a similar note: Not sure how much you've experimented with the WebView implementation, but did you ever find that the related injectedJavaScript prop worked? I can't get it working on my end. May be related to the StackOverflow post injectedJavaScript is not working in Webview of react native, where a commenter suggests adding the mixedContentMode prop. Seems to also suggest that the NSAllowsArbitraryLoadsInWebContent setting really did help. If I can't get it working after adding mixedContentMode, I'll file a separate issue for it.

Edit: looks like mixedContentMode is a purely Android concept, and thus didn't produce any difference.

@shirakaba
Copy link
Contributor Author

shirakaba commented May 18, 2018

I have ported the react-native-wkwebview project to macOS, including the pull request that adds injectJavaScript support based on WKUserContentController.addUserScript(). While it doesn't close this issue, it's an alternative for anyone seeking both WKWebView and a reliable injectedJavaScript prop. Being a third-party module, I think it has no dependency upon the seemingly-broken UIManager.js that I patched above.

@ptmt
Copy link
Owner

ptmt commented May 20, 2018

That is amazing news! Thanks a lot. I think it's the right choice, having this as 3rd party mode. It also might be updated later to other react-native implementations, if any.

Do you have any estimate of when the latest version's release might be?

Not yet, unfortunately. It works in my case, but a few parts such text inputs are broken.

@shirakaba
Copy link
Contributor Author

A note to myself (and anyone else heading down my rather individual path here) in future: WKWebView renames the WebView.injectJavaScript() method to WebView.evaluateJavaScript(). I discovered this simply by printing out the keys on my WKWebView ref:

console.log(`Keys of WKWebView`, Object.keys(this.webView));

There was no need for me to alter react-native-macos/Libraries/ReactNative/UIManager.js after migrating to WKWebView.

Note that there is still a prop named injectJavaScript, however, which allows one to specify which JavaScript code to execute before loading the page.

@aleclarson aleclarson added the bug label Jan 28, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants