禁用远程调试时应用程序在启动时崩溃
App crashes on start when remote debugging is disabled
我正在尝试在 phone (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
如果我随后启用远程 js 调试,它会重新加载并且一切正常。我禁用远程调试,应用程序又崩溃了。知道这里会发生什么吗?
更新 - 罪魁祸首代码在 fbjs 包中 - https://github.com/facebook/fbjs/blob/master/packages/fbjs/src/core/dom/getDocumentScrollElement.js
他们检查 navigator
是否已定义,然后尝试访问其上的第二层 属性 - navigator.userAgent.indexOf
.
我可以通过某种方式伪造 navigator.userAgent
或向 fbjs 发送 PR。
navigator
是一个在浏览器中可用的全球网络 API。这在 React Native 中不可用,因为它不是网络浏览器。所有 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'));
编辑:回答后续并给出解决方法。
您可以填充它,但您需要在将任何其他文件导入 index.js
(应用程序的根目录)之前执行此操作。这是 how it's done in node-libs-react-native
with their globals.js 文件,他们也在其中设置了默认用户代理字符串。对此进行调整,您可以通过执行以下操作获得相同的结果:
创建文件来保存你的垫片,globals.js
:
global.navigator.userAgent = 'React Native';
Import/Require 在将您的任何其他文件导入 index.js
:
之前
import { AppRegistry } from "react-native";
import globals from "./globals";
import App from "./App";
AppRegistry.registerComponent("RNSandbox", () => App);
如果出于某种原因您希望 userAgent
有所不同或取决于您是否正在调试,您可以将自己的逻辑添加到 globals.js
。
我正在尝试在 phone (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
如果我随后启用远程 js 调试,它会重新加载并且一切正常。我禁用远程调试,应用程序又崩溃了。知道这里会发生什么吗?
更新 - 罪魁祸首代码在 fbjs 包中 - https://github.com/facebook/fbjs/blob/master/packages/fbjs/src/core/dom/getDocumentScrollElement.js
他们检查 navigator
是否已定义,然后尝试访问其上的第二层 属性 - navigator.userAgent.indexOf
.
我可以通过某种方式伪造 navigator.userAgent
或向 fbjs 发送 PR。
navigator
是一个在浏览器中可用的全球网络 API。这在 React Native 中不可用,因为它不是网络浏览器。所有 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'));
编辑:回答后续并给出解决方法。
您可以填充它,但您需要在将任何其他文件导入 index.js
(应用程序的根目录)之前执行此操作。这是 how it's done in node-libs-react-native
with their globals.js 文件,他们也在其中设置了默认用户代理字符串。对此进行调整,您可以通过执行以下操作获得相同的结果:
创建文件来保存你的垫片,
globals.js
:global.navigator.userAgent = 'React Native';
Import/Require 在将您的任何其他文件导入
之前index.js
:import { AppRegistry } from "react-native"; import globals from "./globals"; import App from "./App"; AppRegistry.registerComponent("RNSandbox", () => App);
如果出于某种原因您希望 userAgent
有所不同或取决于您是否正在调试,您可以将自己的逻辑添加到 globals.js
。