禁用远程调试时,应用程序在启动时崩溃

Muk*_*oni 2 react-native react-native-ios

我正在尝试在手机(iPhone)上安装我的react-native应用程序.它安装正常,但随后在此错误消息时崩溃 -

undefined is not an object (evaluating 'navigator.userAgent.indexOf')

<unknown>
     :12:71
loadModuleImplementation
    require.js:213:12
<unknown>
    getScrollPosition.js:12:31
Run Code Online (Sandbox Code Playgroud)

如果我然后启用远程js调试,它重新加载,一切正常.我禁用远程调试,应用程序恢复崩溃.知道这里可能会发生什么吗?

更新 - 罪魁祸首代码在fbjs包中 - https://github.com/facebook/fbjs/blob/master/packages/fbjs/src/core/dom/getDocumentScrollElement.js

他们检查是否navigator已定义,然后尝试访问其上的第二级属性 - navigator.userAgent.indexOf.

我可以以navigator.userAgent某种方式假装或发送PR到fbjs.

Mic*_*eng 7

navigator是浏览器中可用的全局Web API.这在React Native中不可用,因为它不是Web浏览器.所有Web API都不是全局环境的一部分.这就是navigator.userAgent.indexOf抛出undefined错误的原因.

现在你的程序在远程调试JS时运行正常的原因是因为当你进行远程调试时,React Native将切换到使用Chrome提供的JavaScript引擎(或者你正在调试的任何内容)而不是核心引擎.因此,在调试时,您将可以访问浏览器通常具有的全局Web API.

这是一个非常棘手的问题,因为大多数人一直在调试开启的情况下经常会引起人们的注意.经验法则:React Native不是浏览器.不要使用在进行Web开发时通常使用的任何全局变量,并且您将避免大多数这些类型的错误.

如果您想在React Native的JavaScript引擎中看到这些全局变量是如何被填充的(通常是空对象),您将需要查看initializeCore.js.在这里你可以看到React Native会navigator像这样填充:

// 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'));
Run Code Online (Sandbox Code Playgroud)

编辑:回答后续行动并提供解决方法.

您可以对其进行填充,但在导入index.js(应用程序的根目录)中的任何其他文件之前,您需要执行此操作.这是它是如何在做node-libs-react-native与他们globals.js他们也设置了默认的用户代理字符串的文件.通过执行以下操作,您可以实现相同的结果:

  1. 创建文件来保存垫片,globals.js:

    global.navigator.userAgent = 'React Native';
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在导入任何其他文件之前导入/需要它index.js:

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

如果由于某种原因你想要userAgent不同或依赖于你是否正在调试,你可以添加自己的逻辑globals.js.