flutter与前端交互,利用in_app_web_view实现下载功能:
首先下载库,终端输入
(相关资料图)
flutter pub add flutter_inappwebview
之后导出
import "package:flutter_inappwebview/flutter_inappwebview.dart";
即可使用。
创建in_app_web_view:
InAppWebView( initialOptions: InAppWebViewGroupOptions( crossPlatform:InAppWebViewOptions( useOnDownloadStart:true, ), android: AndroidInAppWebViewOptions() ), //老版本:initialUrl 新版本:initialUrlRequest initialUrlRequest: URLRequest( url: Uri.parse(widget.url), ))
因为要下载文件,所以请务必手动设置useOnDownloadStart 为 true(否则出发文件下载的监听)。
initialUrlRequest中可填写自己想首先打开的url地址。
可参考例子:flutter_inappwebview_examples/main.dart at main · pichillilorenzo/flutter_inappwebview_examples · GitHub
https://github.com/pichillilorenzo/flutter_inappwebview_examples/blob/main/file_download/lib/main.dart
填写自己需要的回调(例子中的一点错误,没有开启 useOnDownloadStart, 因此不会下载成功,在使用时请设置为true)
正常情况下,配合downloader和android_path_provider,普通https链接即可下载文件。
而遇到blob链接时,还需要进行更多操作来确保文件的下载:
可参考javascript - Flutter WebView blob pdf download - Stack Overflow
https://stackoverflow.com/questions/64865972/flutter-webview-blob-pdf-download/64902313#64902313
因为Android不支持blob链接下载,因此我们嵌套javascript处理下载链接,在in_app_web_view的build中重写onWebViewCreated方法,添加javascriptHandler:
onWebViewCreated: (InAppWebViewController controller) { if (mounted) { setState(() { _inAppWebCtrl = controller; _inAppWebCtrl!.addJavaScriptHandler( handlerName: "blobToBase64Handler", callback: (data) async { if (data.isNotEmpty) { final String receivedFileInBase64 = data[0]; final String receivedMimeType = data[1]; // NOTE: create a method that will handle your extensions final String extension = _mapMimeTypeToExtension(receivedMimeType); String tmpFileName = "tmpfile"; _createFileFromBase64( receivedFileInBase64, tmpFileName, extension); } }, ); }); } },
首先在assets中添加js文件夹,然后创建 base64.js 文件
var xhr = new XMLHttpRequest();var blobUrl = "blobUrlPlaceholder";console.log(blobUrl);xhr.open("GET", blobUrl, true);xhr.responseType = "blob";xhr.onload = function(e) { if (this.status == 200) { var blob = this.response; var reader = new FileReader(); reader.readAsDataURL(blob); reader.onloadend = function() { var base64data = reader.result; var base64ContentArray = base64data.split(","); var mimeType = base64ContentArray[0].match(/[^:\s*]\w+\/[\w-+\d.]+(?=[;| ])/)[0]; var decodedFile = base64ContentArray[1]; console.log(mimeType); window.flutter_inappwebview.callHandler("blobToBase64Handler", decodedFile, mimeType); }; };};xhr.send();
注意js中的callhander的名字参数,对应创建webview时addJavascriptHandler中的name。
另外是文件类型映射函数和文件下载函数:
String _mapMimeTypeToExtension(String mimeType) { String extension = ""; switch(mimeType) { case "image/png": extension = "png"; break; case "application/msword": extension = "doc"; break; case "application/vnd.openxmlformats-officedocument.wordprocessingml.document": extension = "docx"; break; case "image/jpeg": extension = "jpg"; break; case "image/gif": extension = "gif"; break; case "image/svg+xml": extension = "svg"; break; case "image/tiff": extension = "tif"; break; case "text/plain": extension = "txt"; break; case "application/vnd.ms-powerpoint": extension = "ppt"; break; case "application/vnd.openxmlformats-officedocument.presentationml.presentation": extension = "pptx"; break; case "application/vnd.ms-excel": extension = "xls"; break; case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": extension = "xlsx"; break; case "application/zip": extension = "zip"; break; case "application/x-7z-compressed": extension = "7z"; break; case "application/pdf": extension = "pdf"; break; } return extension; } _createFileFromBase64(String base64content, String fileName, String yourExtension) async { var bytes = base64Decode(base64content.replaceAll("\n", "")); final file = File("$_localPath/$fileName.$yourExtension"); await file.writeAsBytes(bytes.buffer.asUint8List()); }
最后重写inappwebview中的下载请求方法:
onDownloadStartRequest: (controller, downloadStartRequest) async { var jsContent = await rootBundle.loadString("assets/js/base64.js");// 运行javascript代码解析blob await controller.evaluateJavascript( source: jsContent.replaceAll("blobUrlPlaceholder", downloadStartRequest.url.toString())); },
总结:因为android本身不能解析blob,我们因此使用javascript作为翻译:运行顺序:
onDownloadStartRequest -> javascript文件 -> webviewController中的handler的callback,最后以流的方式写入文件。
关键词: