禁用远程调试时应用程序在启动时崩溃 [英] App crashes on start when remote debugging is disabled

查看:78
本文介绍了禁用远程调试时应用程序在启动时崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在我的手机 (iPhone) 上安装我的 react-native 应用程序.它安装没问题,但在开始时崩溃并显示此错误消息 -

I am trying to install my react-native app on my phone (iPhone). It installs alright but then crashes on start with this error message -

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

<unknown>
     :12:71
loadModuleImplementation
    require.js:213:12
<unknown>
    getScrollPosition.js:12:31

如果我随后启用远程 js 调试,它会重新加载并且一切正常.我禁用了远程调试,应用程序又崩溃了.知道这里会发生什么吗?

If i then enable remote js debugging, it reloads and everything works fine. I disable remote debugging, the app goes back to crashing. Any idea what might be happening here?

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

Update - The culprit code is in fbjs package - https://github.com/facebook/fbjs/blob/master/packages/fbjs/src/core/dom/getDocumentScrollElement.js

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

They check if navigator is defined or not and then try to access the second level property on it - navigator.userAgent.indexOf.

我可以以某种方式伪造 navigator.userAgent 或向 fbjs 发送 PR.

I can either fake navigator.userAgent somehow or send a PR to fbjs.

推荐答案

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

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.

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

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.

这是一个非常棘手的问题,当大多数人在开发时一直打开调试时,它经常会绊倒人们.经验法则:React Native 不是浏览器.不要使用您在进行 Web 开发时通常会使用的任何全局变量,这样可以避免大多数此类陷阱错误.

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.

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

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'));

回答后续问题并提供解决方法.

To answer the follow-up and give a workaround.

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

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. 创建文件来保存你的垫片,globals.js:

global.navigator.userAgent = 'React Native';

  • 在导入 index.js 中的任何其他文件之前导入/要求它:

  • 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);
    

  • 如果出于某种原因您希望 userAgent 不同或依赖于您是否正在调试,您可以将自己的逻辑添加到 globals.js.

    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.

    这篇关于禁用远程调试时应用程序在启动时崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆