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

Expo环境下React Native WebView如何实现图片上传功能

Expo 全WebView架构唤起图片选择器实现方案

不需要eject成裸RN工程,也不需要适配RN CLI文档里的原生修改逻辑,直接用Expo生态官方依赖+WebView双向通信就能实现,全版本Expo SDK通用,Expo Go调试环境直接可用。

依赖安装与基础配置

安装Expo官方维护的无原生link依赖:

npx expo install expo-image-picker react-native-webview

在项目根目录app.json中补充必要权限声明:

{
  "expo": {
    "ios": {
      "infoPlist": {
        "NSPhotoLibraryUsageDescription": "访问相册用于选择需要上传的图片"
      }
    },
    "android": {
      "permissions": ["READ_MEDIA_IMAGES", "READ_EXTERNAL_STORAGE"]
    }
  }
}

RN容器层逻辑实现

核心逻辑是监听WebView发来的唤起选择器指令,调用Expo图片选择器拿到结果后回传给WebView,代码示例:

import { View } from 'react-native';
import { WebView } from 'react-native-webview';
import * as ImagePicker from 'expo-image-picker';
import { useRef } from 'react';

export default function WebViewContainer() {
  const webViewRef = useRef(null);

  const handleWebViewMessage = async (event) => {
    try {
      const message = JSON.parse(event.nativeEvent.data);
      if (message.type !== 'TRIGGER_IMAGE_PICKER') return;

      // 申请相册权限
      const permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync();
      if (!permissionResult.granted) {
        webViewRef.current.postMessage(JSON.stringify({
          type: 'IMAGE_PICKER_RESPONSE',
          success: false,
          msg: '相册权限未开启'
        }));
        return;
      }

      // 唤起图片选择器,可按需配置裁剪、质量、多选等参数
      const pickerResult = await ImagePicker.launchImageLibraryAsync({
        mediaTypes: ImagePicker.MediaTypeOptions.Images,
        allowsEditing: true,
        quality: 0.8,
        base64: true,
      });

      if (pickerResult.canceled) return;
      const selectedAsset = pickerResult.assets[0];
      // 回传选中的图片数据给WebView
      webViewRef.current.postMessage(JSON.stringify({
        type: 'IMAGE_PICKER_RESPONSE',
        success: true,
        data: {
          uri: selectedAsset.uri,
          base64: selectedAsset.base64,
          width: selectedAsset.width,
          height: selectedAsset.height
        }
      }));
    } catch (err) {
      webViewRef.current?.postMessage(JSON.stringify({
        type: 'IMAGE_PICKER_RESPONSE',
        success: false,
        msg: '选择图片失败'
      }));
    }
  };

  return (
    <View style={{ flex: 1 }}>
      <WebView
        ref={webViewRef}
        source={{ uri: '你的Web页面地址' }}
        onMessage={handleWebViewMessage}
        originWhitelist={['*']}
        javaScriptEnabled={true}
      />
    </View>
  );
}

Web页面端适配

网页端无需引入额外依赖,直接通过react-native-webview注入的全局对象通信即可:

<button id="selectImgBtn">选择图片</button>
<div id="imgWrap"></div>

<script>
  // 监听RN层回传的图片选择结果
  window.addEventListener('message', (e) => {
    const res = JSON.parse(e.data);
    if (res.type !== 'IMAGE_PICKER_RESPONSE') return;
    if (!res.success) {
      alert(res.msg);
      return;
    }
    // 渲染选中的图片,可按需替换为上传逻辑
    const img = document.createElement('img');
    img.src = `data:image/jpeg;base64,${res.data.base64}`;
    img.style.maxWidth = '100%';
    document.getElementById('imgWrap').appendChild(img);
  });

  // 按钮点击向RN层发送唤起选择器的指令
  document.getElementById('selectImgBtn').addEventListener('click', () => {
    window.ReactNativeWebView.postMessage(JSON.stringify({
      type: 'TRIGGER_IMAGE_PICKER'
    }));
  });
</script>

避坑说明

  • 不需要按照react-native-webview官方文档修改安卓/iOS原生文件开启文件上传支持,那套逻辑仅适用于裸RN CLI工程,Expo下使用需要额外编写config插件修改原生配置,稳定性远低于双向通信方案,且无法自定义选择器逻辑。
  • 大尺寸图片不建议通过base64传输,容易触发WebView消息体积限制导致通信失败,可将图片本地URI转换为Blob对象后再传入WebView使用。
  • 如果需要支持拍照唤起,替换launchImageLibraryAsync为launchCameraAsync,在app.json中补充相机权限声明即可,逻辑完全一致。
  • Expo SDK 48及以上版本默认已开启WebView的JavaScript执行、跨域通信相关配置,不需要额外设置属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 12:21:34