我正在构建一个带有 expo 的应用程序。
使用 Axios 处理请求。
该API具有自签名证书。
请求在 android 7 上失败(它们在 android 9 上工作)
我在网上看到我需要将
network_security_config.xml
添加到 Android 清单中。 链接。
如何在 expo(可能是 app.json)中执行此操作而不弹出?
谢谢你!
我面临着类似的问题(需要使用自签名证书连接到本地 API),经过大量的研究和实验,我终于找到了解决方案。您需要创建一个 config 插件 ,这需要 Expo SDK 版本 41+。请注意,您将失去使用 Expo Go 的能力,但您将保留在托管工作流程中(即无需更改本机代码),并且您可以使用 EAS 构建来构建自定义开发客户端,这基本上是Expo Go 为您的项目量身定制。
将证书添加到您设备的用户证书列表中:
(如果您在下面的网络配置中包含(原始)证书,则可能不需要此步骤,请参阅此链接。) 转到
Settings -> Security -> Advanced -> Encryption & credentials -> Install a certificate
导入证书
确保证书确实是问题所在:
try {
const response = await axios.post(urlPath, payload);
} catch (error) {
console.error(error.request?._response);
}
如果您收到网络错误并且
error.request._response
显示为 java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
,您就会知道您的应用不信任该证书
创建插件:
您现在将创建一个配置插件,它基本上是在 Expo 的
prebuild
阶段运行的 JS 函数,用于在构建本机项目之前修改本机配置,例如 Android 清单。
在项目根目录中,创建一个包含以下两个文件的
plugins
文件夹:
network_security_config.xml
:<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
</network-security-config>
trust-local-certs.js
:const {AndroidConfig, withAndroidManifest } = require('@expo/config-plugins');
const {Paths} = require('@expo/config-plugins/build/android');
const path = require('path');
const fs = require('fs');
const fsPromises = fs.promises;
const { getMainApplicationOrThrow} = AndroidConfig.Manifest
const withTrustLocalCerts = config => {
return withAndroidManifest(config, async config => {
config.modResults = await setCustomConfigAsync(config, config.modResults);
return config;
});
}
async function setCustomConfigAsync(
config,
androidManifest
) {
const src_file_pat = path.join(__dirname, "network_security_config.xml");
const res_file_path = path.join(await Paths.getResourceFolderAsync(config.modRequest.projectRoot),
"xml", "network_security_config.xml");
const res_dir = path.resolve(res_file_path, "..");
if (!fs.existsSync(res_dir)) {
await fsPromises.mkdir(res_dir);
}
try {
await fsPromises.copyFile(src_file_pat, res_file_path);
} catch (e) {
throw e;
}
const mainApplication = getMainApplicationOrThrow(androidManifest);
mainApplication.$["android:networkSecurityConfig"] = "@xml/network_security_config";
return androidManifest;
}
module.exports = withTrustLocalCerts;
运行
expo prebuild
并链接插件
为了使用该插件,您必须在项目根目录中有一个名为
app.json
的文件。我不能 100% 确定我从哪里获取该文件,但我相信它是在我第一次运行时自动创建的 expo prebuild
。注:
prebuild
命令(显然与 eject
相同)现在是完全可逆的(例如,它不会安装大部分附加组件)以前的依赖项)。expo prebuild
并按照提示操作 -> 这应该创建 app.json
文件。android
文件夹(以及 ios
,如果也创建了)。app.json
中,将以下内容添加到 expo
键的末尾:
"plugins": [
"./plugins/trust-local-certs.js"
]
expo prebuild --no-install
并检查 android/app/src/main/AndroidManifest.xml
是否包含对您的网络配置的引用,并且 android/app/src/main/res/xml/network_security_config.xml
是否已从您的 plugins
目录中正确复制。设置并运行 EAS 构建:
如果您还没有这样做,请按照以下步骤设置 EAS 构建项目
这些说明(安装 EAS CLI,运行 eas build:configure
并在
eas.json
中配置开发配置文件)。然后,运行
eas build --profile development --platform android
。这将在云中创建一个自定义开发客户端(在
prebuild
阶段运行插件),您可以将其安装在您的设备上并充当 Expo Go 的替代品。要启动 Metro 服务器,请运行
expo start --dev-client
。然后,您的开发客户端应该能够建立与 Metro 服务器的连接,并且如果您再次运行 axios 请求,它应该会通过:)
https://www.npmjs.com/package/expo-network-security-config 基于 silentsurfer 答案!