This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.
使用危险的 mod
编辑页面
了解危险的 mod,以及在创建配置插件时如何使用它们。
Expo 中的危险 mod 通过字符串操作和正则表达式直接访问原生项目文件。虽然现有 mod 插件是推荐的方式,但危险 mod 作为一种逃生口,可用于那些无法通过现有 mod 插件实现的修改。
为什么它们被认为是危险的?
自动化的直接源代码修改通常并不能很好地组合使用。比如,如果一个危险 mod 替换了源文件中的文本,而后续另一个危险 mod 预期原始文本仍然存在(也许它会把原始文本作为正则表达式的锚点),那么它很可能无法产生预期结果——取决于它的实现方式,它可能会抛出错误或记录日志。其他类型的 mod 较少出现这类问题,不过像 withAndroidManifest 和 withPodfile 这种直接操作源文件的 mod 也可能发生这种情况。
与可安全多次运行的标准 mod 不同,危险 mod 很少能保证幂等。多次运行同一个危险 mod 可能会产生不同结果、导致重复修改,甚至彻底破坏目标文件。
何时使用危险 mod
在以下情况下可以考虑使用危险 mod:
- 无法通过标准 mod 实现修改:你需要的修改不受现有 mod 插件支持,例如
withAndroidManifest、withPodfile等;或者某个库需要标准插件未涵盖的特定原生修改。 - 兼容旧版 Expo SDK: 你针对的是不包含所需 mod 插件的旧版 Expo SDK。
- 需要使用正则表达式或替换函数修改文本:你需要进行现有 mod 插件不支持的复杂文本修改。例如,当某个库更改名称时,Expo 会在内部使用危险 mod 来重构大型文件系统。
如何使用危险 mod
在实际场景中,你可以按照创建 config plugin 章节中的标准 config plugin 使用方式,直接在项目中使用本节描述的示例 config plugin。不过,对于名为 withPodfile 的现有 mod 插件来说,你并不需要使用危险 mod。下面的示例只是为了演示如何创建和使用危险 mod。
让我们看一个示例 config plugin,它用于修改原生目录(ios)中的文件。当你在 Expo 项目中使用 Continuous Native Generation 时,这很有用。在这个 config plugin 的帮助下,原生文件(ios/Podfile)会在每次运行 npx expo prebuild 命令时更新,无论你是手动运行还是通过 EAS Build 运行)。当现有 mod 插件无法编辑和更新原生目录中的文件时,这个示例就是一个理想用例。
按照创建 config plugin 章节中的目录结构和创建步骤(步骤 3、4 和 5),我们假设这个 config plugin 创建在 Expo 项目的 plugins 目录中:
在上面的示例中,插件 withCustomPodfile 会在 prebuild 过程中,自动向你项目的原生 ios/Podfile 中添加一个 CocoaPod 依赖。它使用 withDangerousMod 直接访问原生文件系统,并在原生项目生成之后、安装任何 CocoaPod 依赖之前运行。
Podfile 需要直接进行文本修改,这通过 addCustomMod 函数中的正则表达式模式完成。这个过程还要求将 CocoaPod 依赖插入到 Podfile 的特定位置,也就是在 use_expo_modules! 语句之后。
withDangerousMod 语法和要求
使用 withDangerousMod 需要以下参数:
- 一个原生平台(android 或 ios)
- 一个异步函数,接收具有文件系统访问权限的
config对象 - 用于访问原生目录中内容的相对文件名/路径
- 读取现有文件、修改其内容,并将其写回文件
- (可选)在插件于 prebuild 过程中执行时,为成功和失败状态记录自定义消息
下面的代码片段提供了所需字段的骨架,以及在使用 withDangerousMod 时 config plugin 可以如何组织:
import { ConfigPlugin, withDangerousMod } from 'expo/config-plugins'; import fs from 'fs/promises'; import path from 'path'; const myPlugin: ConfigPlugin = config => { return withDangerousMod(config, [ 'platform', // 1. "ios" | "android" async config => { // 2. 异步修改函数 // 3. 构建文件路径 const filePath = path.join( config.modRequest.platformProjectRoot, // 原生项目根目录 'path/to/file' // 目标文件的相对路径 ); try { // 4. 读取现有文件,修改其内容,并将其写回文件 let contents = await fs.readFile(filePath, 'utf8'); contents = modifyContents(contents); await fs.writeFile(filePath, contents); // 5. 记录成功和失败状态 console.log('✅ 成功修改文件'); } catch (error) { console.warn('⚠️ 文件修改失败:', error); } return config; }, ]); }; // 使用正则表达式修改文件内容的辅助函数
config plugin 中可用的路径
config plugin 中可用的不同路径属性:
使用危险 mod 时的注意事项
使用危险 mod 时,请考虑以下几点:
- 幂等性保证有限。 与通常幂等、且在不使用 clean 标志时也能工作的标准 mod 不同,危险 mod 很少能保证幂等。这意味着多次运行同一个危险 mod 可能会产生不同结果或引发问题。
- 具有实验性且容易出问题。 使用
withDangerousMod时要谨慎,因为它未来可能会变更。请在每个 SDK 版本中都对你的危险 mod 进行充分测试,因为当原生模板发生变化时,它们尤其容易出问题。 - 使用标准 mod 插件。Android 和 iOS 都提供了诸如
withAndroidManifest、withPodfile、withPodfileProperties等 mod 插件,用于执行常见的原生文件修改。只有在没有现有 mod 插件可用来处理你的用例时,才使用危险 mod。 - 不要假设文件一定存在。在读写之前,始终检查原生目录以及文件的相对路径。如果你使用 CNG,可以随时运行
npx expo prebuild来创建原生 android 和 ios 目录,并手动验证文件是否存在。 - 危险 mod 会先运行。危险 mod 执行的顺序可能不可靠,因为危险 mod 会在其他修改器之前运行。这会影响构建过程的可预测性,并可能与其他修改发生冲突。