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
I fixed this issue by adding a new Blank page containing all the methods.
Blank page file:
import 'package:flutter/material.dart';
import 'package:uuid/uuid.dart';
import '../models/fas.dart';
import '../request_methods.dart';
import './home_page.dart';
import './sign_in_page.dart';
class BlankPage extends StatelessWidget {
Future<void> _tryAssignAccessId() async {
String? accessId = await FAS.read("ACCESS_ID");
if (accessId == null) {
await FAS.write("ACCESS_ID", (const Uuid()).v4());
}
}
Future<bool> _checkAuth() async {
try {
String? accessKey = await FAS.read("ACCESS_KEY");
if (accessKey == null) {
return false;
}
return await HTTP.authenticate(accessKey);
} catch (e) {
return false;
}
}
@override
Widget build(BuildContext context) {
FAS.init();
_tryAssignAccessId();
_checkAuth().then((result) {
if (result) {
Navigator.of(context)
.pushReplacement(MaterialPageRoute(builder: (ctx) => HomePage()));
} else {
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (ctx) => const SignInPage()));
}
});
return Scaffold();
}
}
Updated main.dart (for ref.):
import 'package:flutter/material.dart';
import './pages/blank.dart';
void main() {
runApp(
MaterialApp(
home: BlankPage(),
theme: ThemeData(fontFamily: "Josefin Sans"),
),
);
}
I solved this by adding
WidgetsFlutterBinding.ensureInitialized();
to the main() method before runApp().
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.