App crashes on start when remote debugging is disabled

ぐ巨炮叔叔 提交于 2019-12-06 07:26:22

navigator is a global Web API available in browsers. This is not available in React Native as it's not a web browser. All of the Web APIs are not part of the global environment. This is why navigator.userAgent.indexOf is throwing the undefined error.

Now the reason why your program runs fine when debugging JS remotely is because React Native will switch to using the JavaScript engine provided by Chrome (or whatever you are debugging through) instead of the core one when you remote debug. So when debugging, you will have access to the global Web API that browsers normally have.

This is a very tricky gotcha that will often trip people up as most people develop with debugging turned on all the time. Rule of thumb: React Native is not a browser. Don't use any of the globals that you would normally use when doing web development and you'll avoid most of these types of gotcha errors.

If you would like to see how these globals are polyfilled (often with empty objects) in React Native's JavaScript engine, you'll want to look at initializeCore.js. Here you can see that React Native will polyfill navigator like this:

// Set up Geolocation
let navigator = global.navigator;
if (navigator === undefined) {
  global.navigator = navigator = {};
}

// see https://github.com/facebook/react-native/issues/10881
polyfillObjectProperty(navigator, 'product', () => 'ReactNative');
polyfillObjectProperty(navigator, 'geolocation', () => require('Geolocation'));

Edit: To answer the follow-up and give a workaround.

You can shim it, but you need to do it before importing any of your other files in index.js (the root of your application). This is how it's done in node-libs-react-native with their globals.js file where they too set a default user agent string. Adapting that, you can achieve the same result by doing the following:

  1. Create file to hold your shims, globals.js:

    global.navigator.userAgent = 'React Native';
    
  2. Import/Require it prior to importing any of your other files in index.js:

    import { AppRegistry } from "react-native";
    import globals from "./globals";
    import App from "./App";
    
    AppRegistry.registerComponent("RNSandbox", () => App);
    

If for some reason you want the userAgent to be different or be dependent on whether you are debugging or not, you can add your own logic to the globals.js.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!