Flutter: how do I write a file to local directory with path_provider?

339

Here's an example of the data uri method mentioned in the comments:

import 'dart:html' as html;

  final bytes = utf8.encode('hello!');
  final dataUri = 'data:text/plain;base64,${base64.encode(bytes)}';
  html.document.createElement('a') as html.AnchorElement
    ..href = dataUri
    ..download = 'my_file.txt'
    ..dispatchEvent(html.Event.eventType('MouseEvent', 'click'));

Make sure that's in a dart file that's only imported when html is available, or preferably, use package:universal_html.

Share:
339
Emile Haas
Author by

Emile Haas

Updated on January 04, 2023

Comments

  • Emile Haas
    Emile Haas over 1 year

    I'm working on a Flutter app and need to write files to the local system (iOS, Android but also Web). I have logically followed the documentation on Read and Write Files, and used path_provider to make a small example to test functionality:

    import 'package:path_provider/path_provider.dart';
    
    ...
    
      void _testPathProvider() async {
          // Directory appDocDir = await getTemporaryDirectory(); // Using a different dir. not working either
          // String appDocPath = appDocDir.path;
    
          Directory appDocDir = await getApplicationDocumentsDirectory();
          String appDocPath = appDocDir.path;
          debugPrint('$appDocPath/my_file.txt');
    
          // Save in local file system
          var file = await File('$appDocPath/my_file.txt').writeAsString('hello!');
      }
    

    This test function is simply called by a button, nothing crazy there. But when I run flutter in browser & press button, I get following error:

    Error: MissingPluginException(No implementation found for method getApplicationDocumentsDirectory on channel plugins.flutter.io/path_provider)
        at Object.throw_ [as throw] (http://localhost:42561/dart_sdk.js:5067:11)
    at MethodChannel._invokeMethod (http://localhost:42561/packages/flutter/src/services/restoration.dart.lib.js:1560:21)
        at _invokeMethod.next (<anonymous>)
        at http://localhost:42561/dart_sdk.js:40571:33
        at _RootZone.runUnary (http://localhost:42561/dart_sdk.js:40441:59)
        at _FutureListener.thenAwait.handleValue (http://localhost:42561/dart_sdk.js:35363:29)
        at handleValueCallback (http://localhost:42561/dart_sdk.js:35931:49)
        at Function._propagateToListeners (http://localhost:42561/dart_sdk.js:35969:17)
        at _Future.new.[_completeWithValue] (http://localhost:42561/dart_sdk.js:35817:23)
        at async._AsyncCallbackEntry.new.callback (http://localhost:42561/dart_sdk.js:35838:35)
        at Object._microtaskLoop (http://localhost:42561/dart_sdk.js:40708:13)
        at _startMicrotaskLoop (http://localhost:42561/dart_sdk.js:40714:13)
        at http://localhost:42561/dart_sdk.js:36191:9
    

    Seems like the issue is well-know, have followed advice both here and here, including :

    • running flutter clean and re-getting packages
    • closing app completely and re-running
    • upgrading Flutter to latest stable
    • re-adding path_provider to my pubspec.yaml

    I'm using latest version of the dependency (path_provider: ^2.0.9).

    Any help much appreciated.

    • Richard Heap
      Richard Heap about 2 years
      Web applications run in browsers, and browsers can't write to arbitrary locations on disk, so path_provider isn't supported on Flutter web.
    • Richard Heap
      Richard Heap about 2 years
      One solution is to create a data uri with the contents, behind an anchor tag and then programmatically click it - browser will then offer to 'download' the contents.
    • Emile Haas
      Emile Haas about 2 years
      Thanks a lot for the interest. I was confused about it as the package doc says getApplicationDocumentsDirectory is supported on Linux, but I guess they meant Linux app. If you have an example of usign the URI strategy on Flutter, highly appreciated. Also, would this strategy work for iOS and Android too (to download file on phone storage?).
    • Richard Heap
      Richard Heap about 2 years
      No, won't work on iOS etc. Use the 'normal' way for that.