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
相关产品推荐
相关产品推荐

