FlutterDownloader works downloading pdf in android but fails on iOS

1,893

I could to solve this problem. The previous developers committed a bad programming practice, which caused a race condition in ios when trying to force open a task without checking its status.

I had to change the "while" loop and within it, check the status and progress of the download task. Once it reached 100% progress and its status was complete, then we break the loop and finally open the task.

In provider/download/downloadprovider.dart

  bool waitTask = true;
  while(waitTask) {
    String query = "SELECT * FROM task WHERE task_id='" + taskId + "'";
    var _tasks = await FlutterDownloader.loadTasksWithRawQuery(query: query);
    String taskStatus = _tasks[0].status.toString();
    int taskProgress = _tasks[0].progress;
    if(taskStatus == "DownloadTaskStatus(3)" && taskProgress == 100){ 
      waitTask = false;
    }
  }

  await FlutterDownloader.open(taskId: taskId);
Share:
1,893
Angel Pineda
Author by

Angel Pineda

Updated on December 27, 2022

Comments

  • Angel Pineda
    Angel Pineda over 1 year

    I'm new to flutter/iOS.

    I'm using:

    Flutter 1.22.6 • channel stable • https://github.com/flutter/flutter.git Framework • revision 9b2d32b605 • 2021-01-22 14:36:39 -0800 Engine • revision 2f0af37152 Tools • Dart 2.10.5 flutter_downloader: ^1.4.4

    I have to correct an application that I did not code I'm trying to understand it. It downloads a pdf file and open it, but is not working in iOS.

    All the configuration that I read in https://github.com/fluttercommunity/flutter_downloader is correct.

    Flutter doctor is OK.

    Below I show you parts of the code

    main.dart

    final _prefs = SharedPreferences();
    
    void main() async {
      WidgetsFlutterBinding.ensureInitialized(); 
      final prefs = SharedPreferences();
      await prefs.initPrefs();
      SystemChrome.setPreferredOrientations([
        DeviceOrientation.portraitUp,
        DeviceOrientation.portraitDown
      ]);
      WidgetsFlutterBinding.ensureInitialized();
      await FlutterDownloader.initialize(debug: true);
      _prefs.uid = await getId();
      runApp(MyApp());
    }
    

    pages/registry/facture.dart

    List<Widget> _actionsCreateBar(BuildContext context) {
      return <Widget>[
        (document.id != null)
            ? IconButton(
                icon: Icon(EvaIcons.downloadOutline),
                onPressed: () async {
                  _downloadAction(); // This method is executed when user press download icon
                },
                color: primaryColor,
                iconSize: 25,
              )
            : Container(),
      ];
    }
    
    void _downloadAction() async {
      if (await utils.isInternetAvailable()) {
        if (await _validateUrlRideBeforeDownload()) {
          await _pdfBloc.downloadPdf(document.url_ride, Theme.of(context).platform);
          setState(() {});
          return;
        }
        _showDialogOk(
            context, 'Download', 'Wait please');
      } else {
        _showDialogOk(context, 'Info',
            'No conection');
      }
    }
    

    bloc/pdf/pdfbloc.dart

    class PdfBloc {
    
      final _downloadingController    = BehaviorSubject<bool>();
      final _loadingController        = BehaviorSubject<bool>();
      final _progressStringController = BehaviorSubject<String>();
      final _pdfProvider              = DownloadProvider();
      
      
      Stream<String> get progressStringStream => _progressStringController.stream;
      Stream<bool> get loadingStream => _loadingController.stream;
      Stream<bool> get downloadingStream => _downloadingController.stream;
    
      Future<ResponseData> downloadPdf(String url, var platform) async {
        _downloadingController.sink.add(true);
        ResponseData resData = await _pdfProvider.downloadPdf(url, _progressStringController, platform);
        _downloadingController.sink.add(false);
        return resData;
      }
    
      dispose() {
        _downloadingController.close();
        _progressStringController.close();
        _loadingController.close();
      }
    }
    

    provider/download/downloadprovider.dart

    class DownloadProvider {
    
      Future<ResponseData> downloadPdf(String url, dynamic progressString, var platform) async {
      ResponseData resData = ResponseData();
      final _prefs = SharedPreferences();
        try {
          var path = await findLocalPath(platform) + '/';
          FlutterDownloader.cancelAll();
          final String taskId = await FlutterDownloader.enqueue(
            url: url,
            savedDir: path,
            showNotification: true, // show download progress in status bar (for Android)
            openFileFromNotification: true, // click on notification to open downloaded file (for Android)
            headers: {HttpHeaders.authorizationHeader: _prefs.token, 'Content-type': 'application/json'},
          );
    
          // Last developer used this "while" to wait while a dialog is shown
          // Android behaviour: flutter says "only success task can be opened" but then it works
          // iOS behaviour: flutter says "only success task can be opened" infinitely and never 
          // shows the pdf
    
          // In iOS this loop iterates forever
          while(!await FlutterDownloader.open(taskId: taskId,)) {
            // Last developer did this validation, but I don't know why
            if (platform == TargetPlatform.iOS) {
              await FlutterDownloader.open(taskId: taskId);
            }
          }
          _setResponseData(resData, 'Completed', false);
          return resData;
        } catch(e) {
          _setResponseData(resData, 'Error', true);
          return resData;
        }
      }
    
      _setResponseData(ResponseData resData, String message, bool state) {
        resData.setData(message);
        resData.setError(state);
      }
    
    }
    
    Future<String> findLocalPath(var platform) async {
      final directory = platform == TargetPlatform.android
          ? await getExternalStorageDirectory()
          : await getApplicationDocumentsDirectory();
      return directory.path;
    }
    
    

    I have tried several versions of ios and iphone without success.

    Any ideas? Please help me, I'm stuck.

    Thanks.

    • Anoop Thiruonam
      Anoop Thiruonam over 2 years
      Nice clean code!
  • Angel Pineda
    Angel Pineda about 3 years
    All the configuration is fine. I think the problem is in code
  • Fahmi Sawalha
    Fahmi Sawalha over 2 years
    i have a similar issue , any help will be appreciated