Learn how to make an Android native call from Flutter

Downloading PDF files in the user download directory on Android is a widespread feature, a lot of apps use PDF viewing and downloading features.

I hoped that flutter plugins could solve my problem but they didn’t. Fortunately, it was working great on iOS but it was not on Android. So I decided to use my old Java code in Flutter using Method Channel.

First I tried two Flutter plugins for permission and one for creating a directory.

flutter pub add path_provider
flutter pub add permission_handler

Request permission was very easy and it worked on both iOS and Android

Future<bool> _requestWritePermission() async {
    await Permission.storage.request();
    var r = await Permission.storage.request();

    return r.isGranted;

Since it was working on iOS, I decided to leave that code and separate platform code by importing ‘dart:io’ show Platform. Use this code on your onTap action.

static const channel = MethodChannel('com.flutterframework/test');

bool hasPermission = await _requestWritePermission();

if (hasPermission) {
  if (Platform.isAndroid) {
    final int downloader = await channel.invokeMethod(
      <String, String>{'title': title, 'pdf': pdf},

  if (Platform.isIOS) {
    var dir = await getApplicationDocumentsDirectory();
    if (dir != null) {
      String saveName = "$title.pdf";
      String savePath = "${dir.path}/$saveName";

      try {
        await Dio().download(pdf, savePath,
            onReceiveProgress: (received, total) {
          if (total != -1) {
            var percentage = (received / total * 100);
            if (percentage >= 100.0) {
                      'Download completed, please open Files app.'));
        print("File is saved to download folder.");
      } on DioError catch (e) {
        ScaffoldMessenger.of(context).showSnackBar("Download error");
} else {

Finally, in the Java code, create a Java class in your main directory.

package your_package;

import android.app.DownloadManager;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;

public class DownloadHelper {
    public static void downloadPDF(Context context, String title, String pdfUrl) {
        try {
            DownloadManager.Request request = new DownloadManager.Request(Uri.parse(pdfUrl));
            // in order for this if to run, you must use the android 3.2 to compile your app
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {

            if (Build.VERSION.SDK_INT <= 17) {
                request.setDestinationInExternalFilesDir(context, "Documents", "MyFolder/" + title + ".pdf");
            } else {
                request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "MyFolder/" + title + ".pdf");

            // get download service and enqueue file
            DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
        } catch (IllegalArgumentException e) {

Call that Java code from MainActivity, my MainActivity in Kotlin

class MainActivity: FlutterActivity() {
    private val CHANNEL = "com.flutterframework/test";
    private lateinit var channel: MethodChannel

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
        channel.setMethodCallHandler { call, result ->
            if (call.method == "download") {
                val pdfTitle = call.argument<String>("title")
                val pdfUrl = call.argument<String>("pdf")
                Log.d("TAG", pdfTitle.toString());
                Log.d("TAG", pdfUrl.toString());

                DownloadHelper.downloadPDF(this, pdfTitle, pdfUrl);


Download the complete project on GitHub

Spread the love

Leave a comment