19

I am using flutter_webview_plugin: ^0.3.8 but I have the same problem with webview_flutter: ^0.3.13.

In webview, I want to make use of a website which triggers a file download on successful completion of a captcha. However, I complete the captcha and nothing happens, no download.

Is there something in Flutter like a webview download listener ("webview.setDownloadListener")? I only need this for Android.

If not, is there a way of downloading files from a webview in Flutter?

3
  • 1
    Check out this answer if you are owner of code at html and js side - stackoverflow.com/questions/56247542/… Commented Feb 20, 2020 at 5:40
  • Here did you find a solution, even I'm facing the same issue. Tried using different packages as well but no use, Need help!
    – Varun
    Commented Aug 4, 2021 at 10:57
  • No, in the end I just had to use webview natively.
    – Code Poet
    Commented Aug 4, 2021 at 20:27

4 Answers 4

8

A similar issue can be found here!

You can use my plugin flutter_inappwebview, which is a Flutter plugin that allows you to add inline WebViews or open an in-app browser window and has a lot of events, methods, and options to control WebViews. It can recognize downloadable files in both Android (using setDownloadListener) and iOS platforms!

I report here the same answer that I gave to the similar issue:

To be able to recognize downloadable files, you need to set the useOnDownloadStart: true option, and then you can listen the onDownloadStart event!

Also, for example, on Android you need to add write permission inside your AndroidManifest.xml file:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Then, you need to ask permission using the permission_handler plugin. Instead, to effectively download your file, you can use the flutter_downloader plugin.

Here is a complete example using http://ovh.net/files/ (in particular, the http://ovh.net/files/1Mio.dat as URL) to test the download:

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_downloader/flutter_downloader.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';

Future main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await FlutterDownloader.initialize(
      debug: true // optional: set false to disable printing logs to console
  );
  await Permission.storage.request();
  runApp(new MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {
  InAppWebViewController webView;

  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('InAppWebView Example'),
        ),
        body: Container(
            child: Column(children: <Widget>[
          Expanded(
              child: InAppWebView(
            initialUrl: "http://ovh.net/files/1Mio.dat",
            initialHeaders: {},
            initialOptions: InAppWebViewGroupOptions(
              crossPlatform: InAppWebViewOptions(
                debuggingEnabled: true,
                useOnDownloadStart: true
              ),
            ),
            onWebViewCreated: (InAppWebViewController controller) {
              webView = controller;
            },
            onLoadStart: (InAppWebViewController controller, String url) {

            },
            onLoadStop: (InAppWebViewController controller, String url) {

            },
            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, // click on notification to open downloaded file (for Android)
              );
            },
          ))
        ])),
      ),
    );
  }
}

Here, as you can see, I'm using also the path_provider plugin to get the folder where I want to save the file.

3
  • Hi @Lorenzo Pichilli, this doesn't save files to the downloads folder. How do I go about doing that?
    – sambam
    Commented Mar 4, 2021 at 12:36
  • 1
    This isn't related to the flutter_inappwebview plugin. What I wrote here was just an example. If you need to specify another directory, check the path_provider plugin documentation! However, it seems that the method getDownloadsDirectory is not supported on Android and iOS (see the official doc) Commented Mar 4, 2021 at 13:42
  • Okay got it! Thanks Lorenzo
    – sambam
    Commented Mar 6, 2021 at 19:10
3

Here is the step-by-step solution to download files in the flutter web view app. Flutter web view does not allow downloading files and images directly same as a browser. Because your web view app should have storage access permission.

You may be using the webview_flutter or flutter_inappwebview plugin solution will be the same for both you will be getting a callback of the download request.

We will be using the following plugins to achieve download functionality in the flutter web view app :

android_path_provider (to access file storage path in android)

flutter_downloader (to listen to the download event and start download)

permission_handler ( for handling permissions)

path_provider ( for accessing storage path /directory)

Now please add the latest versions of the above plugins to your pubspec.yaml file or else run the following command in your terminal :

flutter pub add android_path_provider
flutter pub add flutter_downloader
flutter pub add permission_handler
flutter pub add path_provider

Initialize flutter FlutterDownloader in main.dart file :

    await FlutterDownloader.initialize(
      debug: false, // optional: set to false to disable printing logs to console (default: true)
      ignoreSsl : true // option: set to false to disable working with http links (default: false)
  );

Inside android> app >src > main > AndroidManifest.xml : Add these permissions to the manifest file :

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Inside tag of the manifest file add the following code :

 <provider
       android:name="vn.hunghd.flutterdownloader.DownloadedFileProvider"
       android:authorities="${applicationId}.flutter_downloader.provider"
       android:exported="false"
       android:grantUriPermissions="true">
       <meta-data
           android:name="android.support.FILE_PROVIDER_PATHS"
           android:resource="@xml/provider_paths"/>
   </provider>

now create a download_helper_functions.dart file and create these functions in that file :

late String localPath;

Future<void> prepareSaveDir() async {
  localPath = (await findLocalPath())!;
  final savedDir = Directory(localPath);
  bool hasExisted = await savedDir.exists();
  if (!hasExisted) {
    savedDir.create();
  }
  return ;
}

Future<String?> findLocalPath() async {
  var externalStorageDirPath;
  if (Platform.isAndroid) {
    try {
      externalStorageDirPath = await AndroidPathProvider.documentsPath;
    } catch (e) {
      final directory = await getExternalStorageDirectory();
      externalStorageDirPath = directory?.path;
    }
  } else if (Platform.isIOS) {
    externalStorageDirPath =
        (await getApplicationDocumentsDirectory()).absolute.path;
  }
  return externalStorageDirPath;
}

now inside you webview widget declaration or InAppWebView widget we have a callback onDownloadStart or onDownloadStartRequest so add this code to the download callback :

 onDownloadStartRequest: (controller, DownloadStartRequest request) async {
            //todo download catelog here
            FlutterDownloader.registerCallback(downloadCallback);
            final platform = Theme.of(context).platform;
            bool value = await _checkPermission(platform);
            if(value){
              await prepareSaveDir();
              {
                final taskId = await FlutterDownloader.enqueue(
                  url: request.url.toString(),
                  savedDir: localPath,
                  showNotification: true,
                  saveInPublicStorage: true,// show download progress in status bar (for Android)
                  openFileFromNotification: true, // click on notification to open downloaded file (for Android)
                );
              }
            }
          },

and now inside your dart where you have declared webview create these two functions :

  Future<bool> _checkPermission(platform) async {
if (Platform.isIOS) return true;
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
if (platform == TargetPlatform.android &&
    androidInfo.version.sdkInt! <= 28) {
  final status = await Permission.storage.status;
  // final status2 = await Permission.manageExternalStorage.status;
  if (status != PermissionStatus.granted) {
    final result = await Permission.storage.request();
    // final result2 = await Permission.manageExternalStorage.request();
    if (result == PermissionStatus.granted) {
      return true;
    }
  } else {
    return true;
  }
} else {
  return true;
}
return false;

}

static void downloadCallback( String id, DownloadTaskStatus status, int progress) { final SendPort send = IsolateNameServer.lookupPortByName('downloader_send_port')!; send.send([id, status, progress]); }

Now rebuild your app and test. download files will work now.

Hope this will help.

Feel free to ask doubt (if any in the comment section).

It takes a lot of time and effort to write solutions please upvote if this helps.

3
  • I haven't tried this yet, but was wondering if there are changes that needs to be done on ios for capabilities or permissions same as android?
    – rashidotm
    Commented Jun 6, 2023 at 8:03
  • I do not have onDownloadStart inside my WebView widget, and I am using "webview_flutter: ^3.0.4"
    – Maciek
    Commented Jan 10, 2024 at 16:10
  • Tive mudar para InAppWebView. Commented Jan 15, 2024 at 19:05
2

just add this code to your AndroidManifest.xml

   <provider
            android:name="vn.hunghd.flutterdownloader.DownloadedFileProvider"
            android:authorities="${applicationId}.flutter_downloader.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
    </provider>

and add this code to your AndroidManifest.xml

it works to me

2
  • 1
    what is in your xml/provider_paths? Are you using any other plugins except the one for webview?
    – Aleksandar
    Commented Mar 29, 2022 at 16:36
  • You can create xml file under res folder and then add this code in it. <?xml version="1.0" encoding="utf-8"?> <paths> <files-path name="share" path="external_files"/> </paths> Commented Sep 11, 2022 at 16:25
0

it works for me

require plugin https://pub.dev/packages/url_launcher

add this code to your project to download file from flutter webview

onDownloadStart: (controller, url,) async {
                    // print("onDownloadStart $url");
                    final String _url_files = "$url";
                    void _launchURL_files() async =>
                        await canLaunch(_url_files) ? await launch(_url_files) : throw 'Could not launch $_url_files';
                    _launchURL_files();
                  },
1
  • 5
    where do you add this code? flutter webview does have this api call. I only see: onPageStarted: (String url) {}, onPageFinished: (String url) {}, onWebResourceError: (WebResourceError error) {}, onNavigationRequest: Commented Feb 23, 2023 at 1:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.