Flutter WebView blob pdf download

不打扰是莪最后的温柔 提交于 2021-02-08 09:06:49

问题


I am trying to download a file from a website using flutter, I first used evaluateJavaScript and changed some values before clicking a generate button wich is supposed to download an appropriate pdf file to the phone.

Here is my code :

InAppWebView(
        initialUrl: '...',
        initialOptions: InAppWebViewGroupOptions(
          crossPlatform: InAppWebViewOptions(
              debuggingEnabled: true,
              useOnDownloadStart: true,
              javaScriptEnabled: true,
          ),
        ),
        //javascriptMode: JavascriptMode.unrestricted,
        onWebViewCreated: (InAppWebViewController webViewController) {
          _controller = webViewController;
          },
          onLoadStop: (_controller ,url) async {
          await _loadData();

          _controller.evaluateJavascript(source:
"console.log(document.getElementById('field-lastname').value = '${data[Field.name]}' );"
+"console.log(document.getElementById('generate-btn').click());"

           );
          },

          onDownloadStart:(_controller,url) async{
            print("onDownloadStart $url");
            final taskId = await FlutterDownloader.enqueue(
                url: url,
                savedDir: (await getExternalStorageDirectory()).path,
            showNotification: true, // show download progress in status bar (for Android)
            openFileFromNotification: true,);
          },

      ),

The URL printed is like this one

onDownloadStart blob:https://example.com/a2a5316c-9290-4da7-8a2a-9f899861046a

And here is the console

Can someone help me ?


回答1:


Downloading file with blob url is tricky and not supported out of the box in currently state of webviews in Flutter. There are 3 popular plugins

  • flutter_webview_plugin - (community)
  • Webview_flutter (official)
  • flutter_inappwebview

There is a note at README in community repository

We are working closely with the Flutter Team to integrate all the Community Plugin features in the Official WebView Plugin. We will try our best to resolve PRs and Bugfixes, but our priority right now is to merge our two code-bases. Once the merge is complete we will deprecate the Community Plugin in favor of the Official one

There is a lot of work yet to build fully working and bugfree webview. Currently for more challenging tasks like this mentioned here, the best attempt is to use flutter_inappwebview which is very popular and used by a lot people with success. There is issue associated with blob files. As we can see in your snippet you already used this plugin. To download blob file you can try convert blob:url to base64 like in this case Download Blob file from Website inside Android WebViewClient

Possible workaround

To your webview (_controller) add JavaScriptHandler. I would assume onWebViewCreated might be ok.

        controller.addJavaScriptHandler(
          handlerName: "blobToBase64Handler",
          callback: (data) {
            String receivedEncodedValueFromJs = data[0];
            _createPdfFromBase64(receivedEncodedValueFromJs.substring(28, receivedEncodedValueFromJs.length), "SomeFileName");
          },
        );

Encoded value in base64 will be passed from JavaScript and it starts with "data:application/pdf;base64,". To generate pdf using methods below we remove these characters using substring.

  _createPdfFromBase64(String encodedPdf, String fileName) async {
    var bytes = base64Decode(encodedPdf.replaceAll('\n', ''));
    final output = await getExternalStorageDirectory();
    final file = File("${output.path}/${fileName}.pdf");
    await file.writeAsBytes(bytes.buffer.asUint8List());
    print("${output.path}/${fileName}.pdf");
    await OpenFile.open("${output.path}/${fileName}.pdf");
    setState(() {});
  }

finally where blob url can be handled invoke js

       onDownloadStart: (controller, url) async {
        print("onDownloadStart $url");
        var jsContent = await rootBundle.loadString("assets/js/base64.js");
        await controller.evaluateJavascript(
            source: jsContent.replaceAll("blobUrlPlaceholder", url));
      },

javascript (load as asset base64.js, better than hardcoded in dart code):

var xhr = new XMLHttpRequest();
var blobUrl = "blobUrlPlaceholder";
console.log(blobUrl);
xhr.open('GET', blobUrl, true);
xhr.setRequestHeader('Content-type', 'application/pdf');
xhr.responseType = 'blob';
xhr.onload = function(e) {
    if (this.status == 200) {
        var blobPdf = this.response;
        var reader = new FileReader();
        reader.readAsDataURL(blobPdf);
        reader.onloadend = function() {
            base64data = reader.result;
            console.log(base64data);
            window.flutter_inappwebview.callHandler('blobToBase64Handler', base64data);
        };
    };
};
xhr.send();

source: Download Blob file from Website inside Android WebViewClient

source: How to decode base64 PDF string in Flutter?

It's not clean and looks hacky but could not find better and easier



来源:https://stackoverflow.com/questions/64865972/flutter-webview-blob-pdf-download

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!