Expo Prebuild 生成多个 CFBundleURLSchemes 原因及解决方法
2025-03-11 03:41:04
Expo Prebuild 生成多个 CFBundleURLSchemes,咋回事?
用 Expo 开发 App,配置 scheme 的时候遇到点小麻烦。按官方文档在 app.json
里设置了 scheme: 'myappname'
,prebuild
之后发现 Info.plist
里面 CFBundleURLSchemes
有重复,心里有点慌,怕以后出问题。
啥原因?
仔细研究了一下,发现这个问题和 Expo 的工作方式,还有咱们配置 app.json
的方式有关。
- Expo 的自动配置: Expo 为了简化开发流程,会自动帮我们配置很多东西,包括 URL Scheme。它会根据
app.json
里面的slug
和name
字段生成一些默认的 Scheme。 - 咱们的自定义 Scheme: 我们在
app.json
里加的scheme
字段,又定义了一个 Scheme。 - iOS 的 Bundle Identifier: iOS 应用的 Bundle Identifier(例如:
fi.myappname.app
) 也会被包含作为可用的scheme.
这几个因素加起来,就导致 Info.plist
里面出现了多个 CFBundleURLSchemes
。
咋解决?
目前来看,多个 Scheme 同时存在一般不会直接导致应用崩溃或功能异常。但为了避免潜在问题,也为了代码更干净,可以尝试以下几种方法:
1. 只用 app.json
里的 scheme
(推荐)
这是最简单直接的方法。如果 app.json
里已经定义了 scheme
,就不用担心 Expo 自动生成的那些。
原理: 明确告诉 Expo 我们要用哪个 Scheme,避免它瞎猜。
操作步骤:
-
确保
app.json
里有scheme
字段:{ "expo": { "scheme": "myappname", "ios": { "bundleIdentifier": "fi.myappname.app" }, ... } }
-
重新运行
npx expo prebuild --clean
。 -
检查
ios/[YourProjectName]/Info.plist
文件,确认CFBundleURLSchemes
里是你想要的。
额外说明 : 这种方式比较稳妥, 只要你确保app.json 中设置了正确的scheme
和bundleIdentifier
。
2. 用 Expo Config Plugin 修改 Info.plist
如果想对 Info.plist
做更细致的修改,可以用 Expo Config Plugin。
原理: Config Plugin 允许我们在 prebuild
过程中,用代码修改原生项目的配置。
操作步骤:
-
安装
@expo/config-plugins
:npm install @expo/config-plugins
-
创建一个新的插件文件(例如
plugins/withCustomScheme.js
):const { withInfoPlist } = require('@expo/config-plugins'); const withCustomScheme = (config) => { return withInfoPlist(config, (config) => { // 假设我们只想保留 app.json 里定义的 scheme const customScheme = config.modRequest.config.scheme; config.modResults.CFBundleURLTypes = [ { CFBundleURLSchemes: [customScheme], }, ]; return config; }); }; module.exports = withCustomScheme;
-
在
app.json
里使用这个插件:{ "expo": { "scheme": "myappname", "ios": { "bundleIdentifier": "fi.myappname.app" }, "plugins": [ "./plugins/withCustomScheme.js" ] } }
-
重新运行
npx expo prebuild --clean
。 -
检查
ios/[YourProjectName]/Info.plist
。
进阶使用:
Config Plugin 的能力很强,不仅能改 Info.plist
,还能改其他原生配置文件。可以根据需要编写更复杂的插件。例如,根据不同环境设置不同的 Scheme。
// plugins/withCustomScheme.js (更复杂的例子)
const { withInfoPlist } = require('@expo/config-plugins');
const withCustomScheme = (config, props) => { // 接受参数
return withInfoPlist(config, (config) => {
const customScheme = config.modRequest.config.scheme;
let schemes = [customScheme];
if (props.includeBundleId) {
schemes.push(config.ios.bundleIdentifier);
}
config.modResults.CFBundleURLTypes = [
{
CFBundleURLSchemes: schemes,
},
];
return config;
});
};
module.exports = withCustomScheme;
{
"expo":{
"plugins": [
[
"./plugins/withCustomScheme.js",
{"includeBundleId": true}
]
]
}
}
安全建议:
- 使用 Config Plugin 修改原生配置时要小心,确保了解自己在做什么。
- 修改前最好备份一下原生项目。
3. 手动修改 Info.plist
(不推荐)
可以直接编辑 ios/[YourProjectName]/Info.plist
文件,删除多余的 CFBundleURLSchemes
。
原理: 直接改最终生成的配置文件。
操作步骤:
- 找到
Info.plist
文件。 - 找到
CFBundleURLTypes
部分。 - 删除不需要的
CFBundleURLSchemes
。
缺点:
- 每次
prebuild
之后都要手动修改,很麻烦。 - 容易出错。
- 不符合 Expo 的开发理念。
强烈不推荐这种方法 。
4. 使用 expo-build-properties
(针对特定情况)
如果问题是由 expo-build-properties
引起的 (例如,你设置了usesNonExemptEncryption: false
), 你可以在 app.json
中进行针对性配置:
原理 : 通过 expo-build-properties
明确地控制某些构建行为。
操作步骤 :
-
在
app.json
中添加相关配置:"expo": { ... "plugins": [ [ "expo-build-properties", { "ios": { "newArchEnabled": false, "useFrameworks": "static" } } ] ] }
上面的配置项要根据实际情况来定, 关键是明确控制
expo-build-properties
影响到的方面。 -
重新
npx expo prebuild --clean
. -
检查
Info.plist
。
进阶使用 :
expo-build-properties
允许很精细地调整构建设置, 但如果配置不当,可能会引入其他问题.所以,要根据错误日志和具体构建报错,逐步排查和调整。
总结:
这几种方法各有优劣。 最推荐的是第一种,直接用 app.json
里的 scheme
。如果需要更精细的控制,可以用 Config Plugin。尽量避免手动修改 Info.plist
。希望这几种方法能帮你解决问题!