You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Expo的app.config.ts中使用异步函数的返回结果?

解决方案

方案1:预获取值并写入环境变量

在启动Expo前通过脚本异步请求ngrok的隧道地址,将结果写入环境变量,再让app.config.ts同步读取该变量。

  1. 编写预启动脚本(比如scripts/fetch-ngrok-url.js):
const fs = require('fs');
const fetch = require('node-fetch');

async function fetchNgrokUrl() {
  try {
    const res = await fetch('http://localhost:4040/api/tunnels');
    const data = await res.json();
    const publicUrl = data.tunnels.find(t => t.proto === 'https')?.public_url;
    
    if (publicUrl) {
      // 将结果写入.env文件
      const envContent = `NGROK_PUBLIC_URL=${publicUrl}\n`;
      fs.writeFileSync('.env', envContent, { flag: 'a' }); // 追加模式避免覆盖其他变量
      console.log('Ngrok URL已写入环境变量');
    } else {
      console.warn('未找到可用的Ngrok HTTPS隧道');
    }
  } catch (err) {
    console.error('获取Ngrok URL失败:', err);
  }
}

fetchNgrokUrl();
  1. 修改package.json中的启动命令,先执行脚本再启动Expo:
{
  "scripts": {
    "start": "node scripts/fetch-ngrok-url.js && expo start",
    "android": "node scripts/fetch-ngrok-url.js && expo start --android",
    "ios": "node scripts/fetch-ngrok-url.js && expo start --ios"
  }
}
  1. 在app.config.ts中读取环境变量:
import { ExpoConfig, ConfigContext } from '@expo/config';

export default ({ config }: ConfigContext): ExpoConfig => {
  return {
    ...config,
    extra: {
      ...config.extra,
      apiUrl: process.env.NGROK_PUBLIC_URL || '默认生产地址',
    },
  };
};

方案2:使用Expo Config Plugin处理异步逻辑

Expo的Config Plugin支持异步操作,可以编写自定义插件在配置阶段获取Ngrok地址并注入到app配置中。

  1. 编写自定义插件(比如plugins/withNgrokUrl.ts):
import { ConfigPlugin } from '@expo/config-plugins';
import fetch from 'node-fetch';

const withNgrokUrl: ConfigPlugin = async (config) => {
  // 仅在开发环境执行
  if (process.env.NODE_ENV !== 'development') {
    return config;
  }

  try {
    const res = await fetch('http://localhost:4040/api/tunnels');
    const data = await res.json();
    const publicUrl = data.tunnels.find(t => t.proto === 'https')?.public_url;

    if (publicUrl) {
      // 将地址注入到extra配置中
      config.extra = {
        ...config.extra,
        apiUrl: publicUrl,
      };
    }
  } catch (err) {
    console.error('插件中获取Ngrok URL失败:', err);
  }

  return config;
};

export default withNgrokUrl;
  1. 在app.config.ts中注册插件:
import { ExpoConfig, ConfigContext } from '@expo/config';
import withNgrokUrl from './plugins/withNgrokUrl';

export default ({ config }: ConfigContext): ExpoConfig => {
  return withNgrokUrl({
    ...config,
    // 其他配置
  });
};

方案3:运行时动态获取(适用于非配置项场景)

如果该地址不需要在app.config.ts中配置,仅在App运行时使用,可以在App初始化时异步获取并全局存储。

示例(使用React Context):

import { createContext, useContext, useEffect, useState } from 'react';
import { View, Text } from 'react-native';

const ApiUrlContext = createContext<string | null>(null);

export const ApiUrlProvider = ({ children }: { children: React.ReactNode }) => {
  const [apiUrl, setApiUrl] = useState<string | null>(null);

  useEffect(() => {
    async function fetchUrl() {
      try {
        const res = await fetch('http://localhost:4040/api/tunnels');
        const data = await res.json();
        const publicUrl = data.tunnels.find(t => t.proto === 'https')?.public_url;
        setApiUrl(publicUrl || '默认地址');
      } catch (err) {
        console.error('获取Ngrok URL失败:', err);
        setApiUrl('默认地址');
      }
    }

    // 仅在开发环境执行
    if (__DEV__) {
      fetchUrl();
    } else {
      setApiUrl('生产环境地址');
    }
  }, []);

  return (
    <ApiUrlContext.Provider value={apiUrl}>
      {children}
    </ApiUrlContext.Provider>
  );
};

// 使用示例
export const useApiUrl = () => useContext(ApiUrlContext);

// 在App入口包裹
export default function App() {
  return (
    <ApiUrlProvider>
      <View>
        <Text>当前API地址: {useApiUrl()}</Text>
      </View>
    </ApiUrlProvider>
  );
}

内容的提问来源于stack exchange,提问作者Christian Merat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 22:41:05