PAYATHON 2026

React Native 中如何通过 npm 向 Gradle 传递 --offline?

技术老齐

可以用 process.argv.slice(2) 读取 gradle-offline,再按需添加 Gradle 参数。先确认项目使用的 React Native CLI 是否支持 --extra-params。支持该选项时,使用:

react-native run-android --extra-params=--offline

react-native run-android -- --offline 是否会把参数传给 Gradle,取决于 CLI 的实现。-- 只负责结束当前命令的选项解析,不保证后续参数会继续传递。

--offline 只能让 Gradle 使用已有的依赖缓存;缺少所需缓存时,构建仍会失败。

先确认 CLI 支持的参数

在项目目录执行:

npx react-native run-android --help

检查输出中是否包含:

--extra-params <string>

React Native Community CLI 的参数定义包含这个选项,对应的运行逻辑会将 extraParams 加入 Gradle 参数数组。

下面的脚本要求本地 CLI 支持该选项。由于没有指定 CLI 版本,请以项目内的 --help 输出为准。

npm 参数应该怎样读取

假设 package.json 中配置的是:

{
  "scripts": {
    "dev": "node dev.js"
  }
}

执行:

npm run dev gradle-offline

npm 会把 gradle-offline 作为位置参数传给 dev.js。也可以显式使用分隔符:

npm run dev -- gradle-offline

两种写法都可以用这段代码识别:

const args = process.argv.slice(2);
const isGradleOffline = args.includes('gradle-offline');

process.argv.includes('gradle-offline') 也能完成检测,使用 slice(2) 则可以排除 Node 可执行文件路径和脚本路径。

根据 npm 文档,位置参数会传给指定脚本;传递以 - 开头的选项时,应使用 npm 的 -- 分隔符。这里的分隔符用于从 npm 向 dev.js 传参,与 React Native CLI 向 Gradle 传参是两个环节。

跨平台脚本示例

可以通过当前 Node 可执行文件运行项目内的 React Native CLI JavaScript 入口,将命令参数放进数组。这样就不需要分别拼接 Unix 的环境变量赋值语句和 Windows 的 SET 命令。

以下示例假设 dev.js 位于项目根目录,环境文件位于项目内的 envs/.env.dev:

const { spawn } = require('child_process');
const path = require('path');

const projectRoot = __dirname;
const isGradleOffline = process.argv
  .slice(2)
  .includes('gradle-offline');

const cliPath = require.resolve('react-native/cli.js');

const cliArgs = [
  cliPath,
  'run-android',
  '--active-arch-only',
  '--appIdSuffix',
  'debug',
];

if (isGradleOffline) {
  cliArgs.push('--extra-params=--offline');
}

const child = spawn(process.execPath, cliArgs, {
  cwd: projectRoot,
  env: {
    ...process.env,
    ENVFILE: path.resolve(projectRoot, 'envs', '.env.dev'),
  },
  shell: false,
  stdio: 'inherit',
});

child.on('error', (error) => {
  console.error('无法启动 React Native CLI:', error.message);
  process.exitCode = 1;
});

child.on('close', (code, signal) => {
  if (signal) {
    console.error(`React Native CLI 被信号 ${signal} 终止`);
  }

  process.exitCode = code ?? 1;
});

使用方式:

# 正常构建
npm run dev

# 启用 Gradle 离线模式
npm run dev gradle-offline

# 同样启用 Gradle 离线模式
npm run dev -- gradle-offline

脚本中的几处处理需要注意:

  • process.execPath 指向当前 Node 可执行文件。CLI 路径和各项参数各占一个数组元素,即使路径包含空格,也不需要手动加引号。
  • env 保留了 process.env,以继承 PATH、JAVA_HOME、Android SDK 等配置,再设置 ENVFILE。
  • --extra-params=--offline 将选项和值放在同一个参数中,避免 CLI 将 --offline 识别为独立的 React Native CLI 选项。
  • 子进程启动失败或构建失败时,脚本会返回非零退出码。

这里使用的本地 CLI 入口是 react-native/cli.js,需要确认项目版本的安装结构与此一致。Windows 下直接执行 react-native.cmd 需要处理命令脚本的启动规则,通过 Node 执行 JavaScript 入口可以省去这部分处理。相关规则见 Node.js 子进程文档。

如果环境文件实际位于 /envs/.env.dev,请将 ENVFILE 改为对应路径。脚本只设置环境变量,文件如何加载取决于项目使用的环境配置工具。如果项目的 package.json 设置了 "type": "module",可将该 CommonJS 脚本命名为 dev.cjs,同时更新 npm script。

脚本中保留的 --appIdSuffix debug 用于确定启动应用的 ID 后缀,不会配置 Gradle 的构建变体。

如果 CLI 不支持 --extra-params

如果 CLI 没有实现参数转发,仅调整 spawn 的参数数组也无法转发参数。

可以直接调用项目内的 Gradle Wrapper,例如在 android 目录执行:

# macOS / Linux
./gradlew :app:installDebug --offline

Windows:

gradlew.bat :app:installDebug --offline

这里假设应用模块名为 app,目标任务为 installDebug。项目存在 product flavor 或自定义变体时,应替换为实际任务。

直接执行 Gradle 时,还需要单独处理 Metro 和应用启动,并传入相同的环境配置,因此无法完整替代 run-android 的行为。

离线构建成功需要哪些缓存

根据 Gradle 文档,--offline 会阻止依赖解析访问网络,改用已有缓存;缺少所需依赖时,构建会直接失败。

可以按以下步骤准备和验证缓存:

  1. 联网执行一次 npm run dev,完成实际目标变体和设备架构的构建。
  2. 保留相同的 GRADLE_USER_HOME 及其缓存,验证前不要清空缓存目录。
  3. 执行 npm run dev gradle-offline,确认这次构建所需的依赖已经齐全。

一次构建只会准备实际用到的依赖。更换构建变体、目标架构、依赖版本或仓库配置后,可能需要重新联网构建。

还需要提前准备 Gradle Wrapper 对应的 Gradle 分发包。Wrapper 文档说明,本地没有对应分发包时,Wrapper 会下载 Gradle;--offline 不能替代这一步。Android SDK、NDK 和项目依赖的其他工具也应提前安装。

--offline 控制的是 Gradle 的依赖解析,不能保证自定义构建任务或其他工具完全不联网,也不会自动启用构建输出缓存。离线构建能否成功,取决于本地是否已备齐当前构建所需的依赖和工具。

备注:内容仅供参考。