Flutter Secure Storage error Null check operator used on a null value

Issue

I am trying to make a Flutter app that contains a login screen and then home screen (only two screens for now). I am using Flutter Secure Storage and Http libraries too.

Whenever the app launches, I want the app to check if two props, accessKey and accessId, are stored in the Secure storage. If accessId is not found, it is auto-generated and assigned with the Uuid library. Whereas the accessKey is not generated locally and is provided by an API.

App navigates to:
1). HomeScreen, if accessKey is stored in Secure Storage and authentication succeeds.
2). SignInScreen, if accessKey is not found or authentication fails.

My problem is, Secure Storage keeps throwing error "Null check operator used on a null value", everytime I perform a read operation. I have initialized the storage variable, yet this problem keeps happening.

Here is my Secure Storage class code:

import 'package:flutter_secure_storage/flutter_secure_storage.dart';

class FAS {
  static FlutterSecureStorage? _storage;

  static void init() {
    _storage = const FlutterSecureStorage(
      aOptions: AndroidOptions(encryptedSharedPreferences: true),
    );
  }

  static Future<String?> read(String key) async {
    return _storage!.read(key: key);
  }

  static Future<Map<String, String>> readAll() async {
    return _storage!.readAll();
  }

  static Future<void> write(String key, String value) async {
    await _storage!.write(key: key, value: value);
  }

  static Future<void> delete(String key) async {
    await _storage!.delete(key: key);
  }

  static Future<void> deleteAll() async {
    await _storage!.deleteAll();
  }
}

Before, the section of that code was this:

static const FlutterSecureStorage _storage = FlutterSecureStorage(aOptions: AndroidOptions(encryptedSharedPreferences: true));

There was no init method.

Yet I keep getting the same error.

Here is my main.dart:

import 'package:flutter/material.dart';
import 'package:unified_bot_app/pages/home_page.dart';
import 'package:uuid/uuid.dart';

import './models/fas.dart';
import './pages/sign_in_page.dart';
import './request_methods.dart';

Future<void> tryAssignAccessId() async {
  String? accessId = await FAS.read("ACCESS_ID");
  if (accessId == null) {
    await FAS.write("ACCESS_ID", (const Uuid()).v4());
  }
}

void main() {
  FAS.init();
  tryAssignAccessId(); // <- Error  

  runApp(
    MaterialApp(
      home: FutureBuilder<bool>(
        builder: (ctx, a) {
          if (a.connectionState == ConnectionState.done) {
            if (a.data!) return HomePage();
            return const SignInPage();
          }

          return const Center(child: CircularProgressIndicator());
        },
        future: () async {
          try {
            String? accessKey = await FAS.read("ACCESS_KEY");
            if (accessKey == null) {
              return false;
            }

            return await HTTP.authenticate(accessKey);
          } catch (e) {
            return false;
          }
        }(),
      ),
      theme: ThemeData(fontFamily: "Josefin Sans"),
    ),
  );
}  

And here is the output I get when I restart the app:

Restarted application in 531ms. E/flutter (20760):
[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Null
check operator used on a null value E/flutter (20760): #0
MethodChannel.binaryMessenger
package:flutter/…/services/platform_channel.dart:121 E/flutter
(20760): #1 MethodChannel._invokeMethod
package:flutter/…/services/platform_channel.dart:146 E/flutter
(20760): #2 MethodChannel.invokeMethod
package:flutter/…/services/platform_channel.dart:329 E/flutter
(20760): #3 MethodChannelFlutterSecureStorage.read
package:flutter_secure_storage_platform_interface/src/method_channel_flutter_secure_storage.dart:49
E/flutter (20760): #4 FlutterSecureStorage.read
package:flutter_secure_storage/flutter_secure_storage.dart:91
E/flutter (20760): #5 FAS.read
package:unified_bot_app/models/fas.dart:13 E/flutter (20760): #6
tryAssignAccessId package:unified_bot_app/main.dart:10 E/flutter
(20760): #7 main package:unified_bot_app/main.dart:18 E/flutter
(20760): #8 _runMainZoned..
(dart:ui/hooks.dart:145:25) E/flutter (20760): #9 _rootRun
(dart:async/zone.dart:1428:13) E/flutter (20760): #10
_CustomZone.run (dart:async/zone.dart:1328:19) E/flutter (20760): #11 _runZoned (dart:async/zone.dart:1863:10) E/flutter (20760): #12 runZonedGuarded (dart:async/zone.dart:1851:12) E/flutter (20760): #13
_runMainZoned. (dart:ui/hooks.dart:141:5) E/flutter (20760): #14 _delayEntrypointInvocation.
(dart:isolate-patch/isolate_patch.dart:283:19) E/flutter (20760): #15
_RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12) E/flutter (20760):
D/EGL_emulation(20760): app_time_stats: avg=14143.50ms min=14143.50ms
max=14143.50ms count=1

However, the error disappears when I place first two lines in the end (after runApp(..)):

void main() {
  runApp(
    MaterialApp(
      home: FutureBuilder<bool>(
        builder: (ctx, a) {
          if (a.connectionState == ConnectionState.done) {
            if (a.data!) return HomePage();
            return const SignInPage();
          }

          return const Center(child: CircularProgressIndicator());
        },
        future: () async {
          try {
            String? accessKey = await FAS.read("ACCESS_KEY"); // <- Error re-appears here  
            if (accessKey == null) {
              return false;
            }

            return await HTTP.authenticate(accessKey);
          } catch (e) {
            return false;
          }
        }(),
      ),
      theme: ThemeData(fontFamily: "Josefin Sans"),
    ),
  );

  FAS.init();
  tryAssignAccessId();
}  

But doing that, the error then re-appears on the marked line.

I am confused. What’s happening?
Any help is appreciated.

Edit 1:
I tried calling the init() method before I call the second read() method, yet the same error is thrown.

Updated section:

future: () async {
          try {
            FAS.init();
            String? accessKey = await FAS.read("ACCESS_KEY");
            if (accessKey == null) {
              return false;
            }

            return await HTTP.authenticate(accessKey);
          } catch (e) {
            print(e);
            return false;
          }
        }(),  

Console output:

Restarted application in 510ms. I/flutter (20760): Null check operator
used on a null value D/EGL_emulation(20760): app_time_stats:
avg=1899.03ms min=1899.03ms max=1899.03ms count=1

Solution

I solved this by adding

WidgetsFlutterBinding.ensureInitialized();

to the main() method before runApp().

Answered By – Alex Shinkevich

Answer Checked By – Dawn Plyler (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *