Initialize Dio with persistent cookie at the start of the program

387

OK: Thank you for updating your post.

The error is: Unhandled Exception: Null check operator used on a null value

It's coming from the 3rd party library call getApplicationDocumentsDirectory(), and it's occurring because you're calling a (currently uninitialized) value with null-safety enabled (a Good Thing!).

SUGGESTIONS:

  1. Using a StatefulWidget is a bit more work - but it makes sense here. It also happens to resolve the problem for you, correct?

  2. You might try making docDir nullable (e.g. String? path). This is exactly what the getApplicationDocument page shows:

https://pub.dev/documentation/path_provider/latest/path_provider/getApplicationDocumentsDirectory.html

Future<Directory> getApplicationDocumentsDirectory() async {
  final String? path = await _platform.getApplicationDocumentsPath();
  if (path == null) {
    throw MissingPlatformDirectoryException(
        'Unable to get application documents directory');
  }
  return Directory(path);
}
  1. Finally, check out these links:
Share:
387
splaytreez
Author by

splaytreez

Updated on January 01, 2023

Comments

  • splaytreez
    splaytreez over 1 year

    I'm using Dio in my app and I want it to save cookies. It turns out I have to download three additional packages to do that: cookie_jar, dio_cookie_manager and path_provider.

    I need to:

    1. get application document directory: Directory docDir = await getApplicationDocumentsDirectory();

    2. pass it to PersistCookieJar PersistCookieJar(storage: FileStorage(appDocDir.path + '/.cookies/'));

    3. and add it to interceptors: dio.interceptors.add(CookieManager(_cookieJar));

    My problem is with the first part. For some reason, getApplicationDocumentsDirectory(); throws an error when not used inside a StatefulWidget widget.

    I have two questions:

    1. Why on earth would getting a path require a StatefulWidget?
    2. How can I do what I want? I need to initialize Dio as early as possible so that by the time the UI loads, the user is already (or almost) logged in. Plus, I don't want to put the logic of initiating the client object inside the UI code, that might for example cause it to be initiated multiple times whenever the widget is created.

    What my code looks like right now:

    Future<void> initStuff() async {
      initLocator();
    
      Directory docDir = await getApplicationDocumentsDirectory(); // throws
      print('docDir = ${docDir.path}');
      Client cli = Client(docDir);
      locator.registerSingleton<Client>(cli);
    
      // ...
    }
    
    void main() async {
      await initStuff();
    
      runApp(MyApp());
    }
    

    Client constructor:

      Client(Directory appDocDir) {
        final _cookieJar = PersistCookieJar(storage: FileStorage(appDocDir.path + '/.cookies/'));
    
        dio = Dio()
          ..options.baseUrl = Utils.SERVER_ADDRESS
          ..options.sendTimeout = 5000
          ..options.receiveTimeout = 5000
          ..options.connectTimeout = 5000
          ..interceptors.add(CookieManager(_cookieJar));
      }
    

    The error I'm getting:

    E/flutter (24953): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: Null check operator used on a null value
    E/flutter (24953): #0      MethodChannel.binaryMessenger
    package:flutter/…/services/platform_channel.dart:142
    E/flutter (24953): #1      MethodChannel._invokeMethod
    package:flutter/…/services/platform_channel.dart:148
    E/flutter (24953): #2      MethodChannel.invokeMethod
    package:flutter/…/services/platform_channel.dart:331
    E/flutter (24953): #3      MethodChannelPathProvider.getApplicationDocumentsPath
    package:path_provider_platform_interface/src/method_channel_path_provider.dart:50
    E/flutter (24953): #4      getApplicationDocumentsDirectory
    package:path_provider/path_provider.dart:138
    E/flutter (24953): #5      initStuff
    package:proj/main.dart:20
    E/flutter (24953): #6      main
    package:proj/main.dart:63
    E/flutter (24953): #7      _runMainZoned.<anonymous closure>.<anonymous closure> (dart:ui/hooks.dart:142:25)
    E/flutter (24953): #8      _rootRun (dart:async/zone.dart:1354:13)
    E/flutter (24953): #9      _CustomZone.run (dart:async/zone.dart:1258:19)
    E/flutter (24953): #10     _runZoned (dart:async/zone.dart:1789:10)
    E/flutter (24953): #11     runZonedGuarded (dart:async/zone.dart:1777:12)
    E/flutter (24953): #12     _runMainZoned.<anonymous closure> (dart:ui/hooks.dart:138:5)
    E/flutter (24953): #13     _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:283:19)
    E/flutter (24953): #14     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
    
    
    • paulsm4
      paulsm4 over 2 years
      Q: Why on earth would getting a path require a StatefulWidget? A: Because you're implicitly writing mutable data? Q: I'm curious: could please Edit your post and copy/paste the actual error message? That would be extremely helpful!
    • splaytreez
      splaytreez over 2 years
      @paulsm4 Added the error
    • splaytreez
      splaytreez over 2 years
      @paulsm4 "Because you're implicitly writing mutable data?" - I guess I just consider stuff like that to be more related to business logic. Something you put into your own set of classes/functions that you can then call from the UI. Pluss the need of StatelefullWidget makes the package less versatile
  • splaytreez
    splaytreez over 2 years
    Thanks for the suggestions! Making docDir nullable doesn't solve the problem, so I'm going to try and put this in StatefulWidget. I haven't done this yet; I just learned that in another SO question and was hesitating to do that because I was hoping for a better way (maybe there's a different library?)
  • paulsm4
    paulsm4 over 2 years
    Actually, I don't know if "StatefulWidget" will make any difference for this particular problem. I thought you said that you already tried it, and that it worked for you. If that's not the case ... then by all means, try my other suggestions first. Here's a good article on Flutter "Stateful" vs. "Stateless" widgets: geeksforgeeks.org/flutter-stateful-vs-stateless-widgets. Most of your widgets will probably be "Stateless" ... but it's important to be equally comfortable using both, as needed.
  • splaytreez
    splaytreez over 2 years
    It does work now inside Stateful. I'm currently figuring out why persistent cookie jar doesn't save cookies, but that's unrelated
  • Admin
    Admin almost 2 years
    As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.