如何在不弹出的情况下将 network_security_config.xml 添加到 expo 应用程序中的清单 [英] How to add network_security_config.xml to manifest in expo app without ejecting

查看:26
本文介绍了如何在不弹出的情况下将 network_security_config.xml 添加到 expo 应用程序中的清单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 expo 构建一个应用程序.
使用 Axios 处理请求.
该 API 具有自签名证书.
请求在 android 7 上失败(它们在 android 9 上工作)

I'm building an app with expo.
Using Axios to handle the requests.
The API has a self-signed certificates.
Requests fail on android 7 (they work on android 9)

我在网上看到我需要将 network_security_config.xml 添加到 android 清单中.链接.

I read online that I need to add a network_security_config.xml to the android manifest. Link.

如何在不弹出的情况下在 expo(可能是 app.json)中做到这一点?

How can I do this in expo (probably app.json) without ejecting ?

谢谢!

推荐答案

我遇到了类似的问题(需要使用自签名证书连接到本地 API),经过大量的研究和实验,我终于能够找到解决方案.您需要创建一个 配置插件,这需要Expo SDK 版本 41+.请注意,您将失去使用 Expo Go 的能力,但您将保留在托管工作流程中(即无需更改本机代码),并且您可以使用 EAS 构建来构建 自定义开发客户端,基本上是为您的项目量身定制的 Expo Go 版本.

I was facing a similar problem (needed to connect to a local API with self-signed certificate) and after a ridiculous amount of research and experimentation I was finally able to find a solution. You will need to create a config plugin, which requires Expo SDK version 41+. Note that you will lose the ability to use Expo Go, but you will remain in the managed workflow (i.e. no need to change native code) and you can use EAS builds to build a custom dev client, which is basically a version of Expo Go tailored to your project.

将证书添加到您设备的用户证书列表中:

(如果您在下面的网络配置中包含您的(原始)证书,则此步骤可能是不必要的,请参阅 此链接.) 转到 Settings ->安全 ->高级->加密与凭据->安装证书导入证书

确保证书确实是问题所在:

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,您将知道您的应用不信任证书找不到路径.

You'll know your app doesn't trust the certificate if you get a network error and error.request._response reads java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

创建插件:

您现在将创建一个配置插件,它基本上是在 Expo 的 prebuild 阶段运行的 JS 函数,用于在构建原生项目之前修改原生配置,例如 Android 清单.

You will now create a config plugin, which are basically JS functions which run during Expo's prebuild phase to modify native configuration such as the Android manifest before building the native project.

在您的项目根目录中,创建一个 plugins 文件夹,其中包含以下两个文件:

In your project root, create a plugins folder with the following two files:

  • 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 &链接插件

    Run expo prebuild & link the plugin

    为了使用插件,您必须在项目根目录中有一个名为 app.json 的文件.我不能 100% 确定我从哪里得到文件,但我相信它是在我第一次运行 expo prebuild 时自动创建的.注意:

    In order to use the plugin, you have to a have a file called app.json in the project root. I'm not 100% sure where I got the file from, but I believe it was created automatically when I first ran expo prebuild. Note:

    • 我建议将 Expo SDK 升级到最新版本(当前为 44),因为现在 prebuild 命令(显然与 eject 相同)现在已经完全可逆的(例如,它不会安装以前的大部分附加依赖项).
    • Prebuild 将创建本机文件夹,但您可以在完成插件设置后安全地删除这些文件夹(如果您想保留在托管工作流中,您确实应该删除它们!当您运行 EAS 构建时,EAS如果它看到本机文件夹,它将假定裸工作流,并且可能不会再次运行您的插件).
    • I recommend upgrading the Expo SDK to the most current version (currently 44), because now the prebuild command (which apparently is the same as eject) is now completely reversible (e.g. it doesn't install most of the additional dependencies it used to).
    • Prebuild will create the native folders, but you can safely delete these folders once you are done setting up the plugin (You really should delete them, if you want to remain in the managed workflow! When you run an EAS build, EAS will assume the bare workflow if it sees the native folders, and presumably not run your plugin again).
    1. 运行 expo prebuild 并按照提示操作 ->这应该会创建 app.json 文件.
    2. 删除生成的原生 android 文件夹(以及 ios,如果它也已创建).
    3. app.json 中,将以下内容添加到 expo 键的末尾:
    1. Run expo prebuild and follow the prompts -> This should create the app.json file.
    2. Delete the generated native android folder (and ios, if it got created as well).
    3. In app.json, add the following to the end of the expo key:
    "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 目录正确复制.
  • 如果一切正常,您的插件设置正确,您应该再次删除本机文件夹(参见上面的注释).
  • Run expo prebuild --no-install and check that android/app/src/main/AndroidManifest.xml contains a reference to your network config, and that android/app/src/main/res/xml/network_security_config.xml was correctly copied over from your plugins directory.
  • If all is well, your plugin is set up correctly and you should again delete the native folders (see note above).
  • 设置并运行 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 请求,它应该会通过:)

    If you haven't done so already, set up your project for EAS builds by following these instructions (install EAS CLI, run eas build:configure and configure a dev profile in eas.json). Then, run eas build --profile development --platform android. This will create a custom dev client in the cloud (running the plugin during the prebuild phase), which you can install on your device and acts as a replacement for Expo Go. To start the metro server, run expo start --dev-client. Your dev client should then be able to pick up the connection to the Metro server and if you run the axios request again, it should go through :)

    这篇关于如何在不弹出的情况下将 network_security_config.xml 添加到 expo 应用程序中的清单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆