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

Flutter WebView中网页图片上传控件调用手机相册问题求助

Flutter WebView 实现网页图片上传功能

在Flutter的WebView组件中,点击网页上的文件上传输入控件(<input type="file">)时,无法唤起手机的图片选择器完成照片上传,以下是相关代码及解决方案:

网页相关代码

<div class="foto-upload">
    <label class="foto-buton">
        <input type="file" name="resim" multiple="multiple" id="fileupload">
        <i class="fa fa-upload"></i>
        <span>FOTOĞRAF EKLE</span>
        <b>YA DA SÜRÜKLE BIRAK</b>
    </label>
    <input type="hidden" name="thumb_id" id="thumb_id" value="">
    <div class="foto-list">
        <div class="foto-count">EKLEDİĞİNİZ FOTOĞRAF ADEDİ: 
            <span id="mediaCount" data-total="0">0/10</span>
            <span id="mediaStatus"></span>
            <span id="filePercent"></span>
        </div>
        <ul>
            <li><i class="fa fa-image"></i></li>
            <li><i class="fa fa-image"></i></li>
            <li><i class="fa fa-image"></i></li>
            <li><i class="fa fa-image"></i></li>
            <li><i class="fa fa-image"></i></li>
            <li><i class="fa fa-image"></i></li>
            <li><i class="fa fa-image"></i></li>
            <li><i class="fa fa-image"></i></li>
            <li><i class="fa fa-image"></i></li>
            <li><i class="fa fa-image"></i></li>
        </ul>
    </div>
    <div class="clear"></div>
</div>

Flutter 现有代码

WebView(
  initialUrl: '***',
  onWebViewCreated: (webViewController) {
     widget._controllerCompleter.future
           .then((value) => widget._controller = value);
     widget._controllerCompleter.complete(webViewController);
  },
  onPageStarted: (url) {
     setState(() {
        loadingPercentage = 0;
     });
  },
  onProgress: (progress) {
     setState(() {
        loadingPercentage = progress;
     });
  },
  onPageFinished: (url) {
     setState(() {
        loadingPercentage = 100;
     });
  },
  javascriptMode: JavascriptMode.unrestricted,
  javascriptChannels: _createJavascriptChannels(context),
),

解决方案

1. 添加平台权限

  • Android端:在AndroidManifest.xml中添加文件访问权限
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
  • iOS端:在Info.plist中添加相册访问说明
    <key>NSPhotoLibraryUsageDescription</key>
    <string>需要访问相册以上传图片</string>
    

2. 基于官方webview_flutter实现文件上传逻辑

修改WebView代码,添加文件选择回调和图片选择逻辑:

import 'package:image_picker/image_picker.dart';
import 'dart:convert';

// ... 其他代码

WebView(
  initialUrl: '***',
  onWebViewCreated: (webViewController) {
     widget._controllerCompleter.future
           .then((value) => widget._controller = value);
     widget._controllerCompleter.complete(webViewController);
  },
  onPageStarted: (url) {
     setState(() {
        loadingPercentage = 0;
     });
  },
  onProgress: (progress) {
     setState(() {
        loadingPercentage = progress;
     });
  },
  onPageFinished: (url) async {
     setState(() {
        loadingPercentage = 100;
     });
     // 注入Base64转Blob的工具函数到网页
     await widget._controller?.runJavascript("""
       function base64ToBlob(base64, mimeType) {
         var byteCharacters = atob(base64);
         var byteNumbers = new Array(byteCharacters.length);
         for (var i = 0; i < byteCharacters.length; i++) {
           byteNumbers[i] = byteCharacters.charCodeAt(i);
         }
         var byteArray = new Uint8Array(byteNumbers);
         return new Blob([byteArray], {type: mimeType});
       }
     """);
  },
  javascriptMode: JavascriptMode.unrestricted,
  javascriptChannels: _createJavascriptChannels(context),
  // 处理文件上传请求
  navigationDelegate: (NavigationRequest request) async {
    if (request.url.contains('filechooser') || request.url.startsWith('file://')) {
      // 调用图片选择器多选图片
      final picker = ImagePicker();
      final images = await picker.pickMultiImage();

      if (images.isNotEmpty) {
        String jsCode = '';
        for (var image in images) {
          final bytes = await image.readAsBytes();
          final base64Image = base64Encode(bytes);
          // 模拟网页文件上传控件的change事件
          jsCode += """
            var file = new File([base64ToBlob('$base64Image', '${image.mimeType}')], '${image.name}', {type: '${image.mimeType}'});
            var event = new Event('change');
            Object.defineProperty(event, 'target', {value: {files: [file]}});
            document.getElementById('fileupload').dispatchEvent(event);
          """;
        }
        // 注入JS代码触发网页上传逻辑
        await widget._controller?.runJavascript(jsCode);
      }
      return NavigationDecision.prevent;
    }
    return NavigationDecision.navigate;
  },
)

3. 更简便的方案:使用flutter_inappwebview插件

该插件内置文件上传处理,无需手动模拟JS事件:

import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:image_picker/image_picker.dart';

// ... 其他代码

InAppWebView(
  initialUrlRequest: URLRequest(url: Uri.parse('***')),
  // Android端文件选择回调
  androidOnShowFileChooser: (controller, params) async {
    final picker = ImagePicker();
    final files = await picker.pickMultiImage();
    if (files.isNotEmpty) {
      return AndroidFileChooserParamsResult(
        uriList: files.map((e) => Uri.parse(e.path)).toList(),
      );
    }
    return AndroidFileChooserParamsResult();
  },
  // iOS端文件选择回调
  iosOnChooseFiles: (controller, params) async {
    final picker = ImagePicker();
    final files = await picker.pickMultiImage();
    return files.map((e) => IOSFile(path: e.path)).toList();
  },
  // 其他配置(加载进度、JS通道等)
)

内容的提问来源于stack exchange,提问作者Doğukan Özgür YILMAZ

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 09:20:30