无法从另一个包调用 Flutter Singleton
Cannot call Flutter Singleton from another package
我正在尝试在 Flutter 中导入一个异步函数来处理安全地存储用户数据。问题是我不断收到以下错误:
packages/authentication_repository/lib/src/authentication_repository.dart:64:15:
Error: Method not found: 'set'. await SecureStorageService.set(
^^^
这是我的代码:
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class SecureStorageService {
static SecureStorageService _intance;
FlutterSecureStorage flutterSecureStorage;
SecureStorageService._internal() {
this.flutterSecureStorage = new FlutterSecureStorage();
}
static Future<SecureStorageService> getInstance() async {
if (_intance == null) {
_intance = SecureStorageService._internal();
}
return _intance;
}
Future<void> set(String key, String value) async {
await this.flutterSecureStorage.write(key: key, value: value);
}
Future<String> get(String key) async {
return await this.flutterSecureStorage.read(key: key);
}
Future<void> clear() async {
await this.flutterSecureStorage.deleteAll();
}
}
然后我导入如下代码:
import 'package:crowdplan_flutter/storage_util.dart';
...
class AuthenticationRepository {
final _controller = StreamController<AuthenticationStatus>();
final secureStorage = SecureStorageService.getInstance();
...
try {
final response = await http.post(
url,
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
'email': email,
'password': password,
'client_id': clientId,
}),
);
if (response.statusCode == 200) {
print(response.body);
print(json.decode(response.body)['access_token']);
print(json.decode(response.body)['refresh_token']);
await secureStorage.set(
key: 'access_token',
value: json.decode(response.body)['access_token']);
await secureStorage.set(
key: 'refresh_token',
value: json.decode(response.body)['refresh_token']);
await secureStorage.set(
key: 'user_id', value: json.decode(response.body)['user_id']);
_controller.add(AuthenticationStatus.authenticated);
}
} catch (error, stacktrace) {
print('Exception occurred: $error stackTrace: $stacktrace');
}
}
我的单例是在我的 main.dart 文件中启动的。
void main() async {
await SecureStorageService.getInstance();
runApp(App(
authenticationRepository: AuthenticationRepository(),
userRepository: UserRepository(),
));
}
我是 Flutter 的新手,所以这可能是一个新的菜鸟错误。
set
方法不是 static
并且无法使用 SecureStorageService.set
访问
Future<void> set(String key, String value) async {
await this.flutterSecureStorage.write(key: key, value: value);
}
我在第二个代码片段中看到您已将单例分配给 secureStorage
。
您是想通过类似的方式访问它吗?:
secureStorage.set()
第 2 部分 - 代码示例
也许单例 class 中的 async getInstance()
给你添麻烦了。它不需要是异步的(也不应该是)。 (在某些情况下,您可能需要异步初始化程序而不是构造函数。有关用例,请参阅 。)
SecureStorageService
(单例)在您的 main()
方法中被实例化,因此在 AuthenticationRepository
内部它将使用相同的实例并准备好使用。
class AuthenticationRepository {
final secureStorage = SecureStorageService.getInstance;
// ↑ will get the same instance created in main()
问题中的代码示例未指定 where/when 正在调用 http.post 方法,但我猜这是 AuthenticationRepository
的初始化/设置,所以我'我们在其中模拟了一个 initStorage()
方法。
此 initStorage()
调用将使用 SecureStorageService
单例,并调用其 secureStorage.set()
方法。
希望此示例可以帮助您发现我们的代码示例之间的差异,从而找出问题所在。
import 'package:flutter/material.dart';
/// Mocking FlutterSecureStorage
/// Note that the actual package FlutterSecureStorage does not have an async
/// constructor nor initializer
class FlutterSecureStorage {
Map<String,String> data = {};
Future<void> write({String key, String value}) async {
data[key] = value;
}
Future<String> read({String key}) async {
print('FSS read - returning value: ${data[key]}');
return data[key];
}
}
class SecureStorageService {
/// for singleton ↓ instance should be final and uses private constructor
static final SecureStorageService _instance = SecureStorageService._internal();
FlutterSecureStorage flutterSecureStorage;
/// Private constructor, not async
SecureStorageService._internal() {
flutterSecureStorage = FlutterSecureStorage();
}
/// This doesn't need to be async. FlutterSecureStorage (FSS) doesn't have an async initializer
/// and constructors are generally never async
/*static Future<SecureStorageService> getInstance() async {
if (_instance == null) {
_instance = SecureStorageService._internal();
}
return _instance;
}*/
/// static singleton instance getter, not async
static SecureStorageService get getInstance => _instance;
/// don't need "this" keyword & could use FSS methods directly, but leaving as is
Future<void> set({String key, String value}) async {
await flutterSecureStorage.write(key: key, value: value);
}
Future<String> get({String key}) async {
return flutterSecureStorage.read(key: key);
}
}
class Response {
int statusCode = 200;
Response() {
print('http post completed');
}
}
class AuthenticationRepository {
final secureStorage = SecureStorageService.getInstance;
String accessToken = '';
/// Encapsulates the slow init of a http.post call. When all ready, returns
/// the AuthenticationRepository in a usable state
Future<AuthenticationRepository> initStorage() async {
try {
// Mock http response
final response = await Future.delayed(Duration(seconds: 2), () => Response());
if (response.statusCode == 200) {
accessToken = 'access_token from http value';
await secureStorage.set(
key: 'access_token',
value: accessToken);
print('access token set');
// snipped other calls for brevity
}
} catch (error, stacktrace) {
print('Exception occurred: $error stackTrace: $stacktrace');
}
return this;
}
}
class SingleStoragePage extends StatefulWidget {
@override
_SingleStoragePageState createState() => _SingleStoragePageState();
}
class _SingleStoragePageState extends State<SingleStoragePage> {
Future<AuthenticationRepository> authRepo;
@override
void initState() {
super.initState();
authRepo = AuthenticationRepository().initStorage();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Singleton Storage'),
),
body: Center(
child: FutureBuilder<AuthenticationRepository>(
future: authRepo,
builder: (context, snapshot) {
print('FutureBuilder re/building');
if (snapshot.hasData) {
return Text('Access token: ${snapshot.data.accessToken}');
}
return Text('loading...');
},
),
),
);
}
}
我正在尝试在 Flutter 中导入一个异步函数来处理安全地存储用户数据。问题是我不断收到以下错误:
packages/authentication_repository/lib/src/authentication_repository.dart:64:15:
Error: Method not found: 'set'. await SecureStorageService.set(
^^^
这是我的代码:
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class SecureStorageService {
static SecureStorageService _intance;
FlutterSecureStorage flutterSecureStorage;
SecureStorageService._internal() {
this.flutterSecureStorage = new FlutterSecureStorage();
}
static Future<SecureStorageService> getInstance() async {
if (_intance == null) {
_intance = SecureStorageService._internal();
}
return _intance;
}
Future<void> set(String key, String value) async {
await this.flutterSecureStorage.write(key: key, value: value);
}
Future<String> get(String key) async {
return await this.flutterSecureStorage.read(key: key);
}
Future<void> clear() async {
await this.flutterSecureStorage.deleteAll();
}
}
然后我导入如下代码:
import 'package:crowdplan_flutter/storage_util.dart';
...
class AuthenticationRepository {
final _controller = StreamController<AuthenticationStatus>();
final secureStorage = SecureStorageService.getInstance();
...
try {
final response = await http.post(
url,
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
'email': email,
'password': password,
'client_id': clientId,
}),
);
if (response.statusCode == 200) {
print(response.body);
print(json.decode(response.body)['access_token']);
print(json.decode(response.body)['refresh_token']);
await secureStorage.set(
key: 'access_token',
value: json.decode(response.body)['access_token']);
await secureStorage.set(
key: 'refresh_token',
value: json.decode(response.body)['refresh_token']);
await secureStorage.set(
key: 'user_id', value: json.decode(response.body)['user_id']);
_controller.add(AuthenticationStatus.authenticated);
}
} catch (error, stacktrace) {
print('Exception occurred: $error stackTrace: $stacktrace');
}
}
我的单例是在我的 main.dart 文件中启动的。
void main() async {
await SecureStorageService.getInstance();
runApp(App(
authenticationRepository: AuthenticationRepository(),
userRepository: UserRepository(),
));
}
我是 Flutter 的新手,所以这可能是一个新的菜鸟错误。
set
方法不是 static
并且无法使用 SecureStorageService.set
Future<void> set(String key, String value) async {
await this.flutterSecureStorage.write(key: key, value: value);
}
我在第二个代码片段中看到您已将单例分配给 secureStorage
。
您是想通过类似的方式访问它吗?:
secureStorage.set()
第 2 部分 - 代码示例
也许单例 class 中的 async getInstance()
给你添麻烦了。它不需要是异步的(也不应该是)。 (在某些情况下,您可能需要异步初始化程序而不是构造函数。有关用例,请参阅
SecureStorageService
(单例)在您的 main()
方法中被实例化,因此在 AuthenticationRepository
内部它将使用相同的实例并准备好使用。
class AuthenticationRepository {
final secureStorage = SecureStorageService.getInstance;
// ↑ will get the same instance created in main()
问题中的代码示例未指定 where/when 正在调用 http.post 方法,但我猜这是 AuthenticationRepository
的初始化/设置,所以我'我们在其中模拟了一个 initStorage()
方法。
此 initStorage()
调用将使用 SecureStorageService
单例,并调用其 secureStorage.set()
方法。
希望此示例可以帮助您发现我们的代码示例之间的差异,从而找出问题所在。
import 'package:flutter/material.dart';
/// Mocking FlutterSecureStorage
/// Note that the actual package FlutterSecureStorage does not have an async
/// constructor nor initializer
class FlutterSecureStorage {
Map<String,String> data = {};
Future<void> write({String key, String value}) async {
data[key] = value;
}
Future<String> read({String key}) async {
print('FSS read - returning value: ${data[key]}');
return data[key];
}
}
class SecureStorageService {
/// for singleton ↓ instance should be final and uses private constructor
static final SecureStorageService _instance = SecureStorageService._internal();
FlutterSecureStorage flutterSecureStorage;
/// Private constructor, not async
SecureStorageService._internal() {
flutterSecureStorage = FlutterSecureStorage();
}
/// This doesn't need to be async. FlutterSecureStorage (FSS) doesn't have an async initializer
/// and constructors are generally never async
/*static Future<SecureStorageService> getInstance() async {
if (_instance == null) {
_instance = SecureStorageService._internal();
}
return _instance;
}*/
/// static singleton instance getter, not async
static SecureStorageService get getInstance => _instance;
/// don't need "this" keyword & could use FSS methods directly, but leaving as is
Future<void> set({String key, String value}) async {
await flutterSecureStorage.write(key: key, value: value);
}
Future<String> get({String key}) async {
return flutterSecureStorage.read(key: key);
}
}
class Response {
int statusCode = 200;
Response() {
print('http post completed');
}
}
class AuthenticationRepository {
final secureStorage = SecureStorageService.getInstance;
String accessToken = '';
/// Encapsulates the slow init of a http.post call. When all ready, returns
/// the AuthenticationRepository in a usable state
Future<AuthenticationRepository> initStorage() async {
try {
// Mock http response
final response = await Future.delayed(Duration(seconds: 2), () => Response());
if (response.statusCode == 200) {
accessToken = 'access_token from http value';
await secureStorage.set(
key: 'access_token',
value: accessToken);
print('access token set');
// snipped other calls for brevity
}
} catch (error, stacktrace) {
print('Exception occurred: $error stackTrace: $stacktrace');
}
return this;
}
}
class SingleStoragePage extends StatefulWidget {
@override
_SingleStoragePageState createState() => _SingleStoragePageState();
}
class _SingleStoragePageState extends State<SingleStoragePage> {
Future<AuthenticationRepository> authRepo;
@override
void initState() {
super.initState();
authRepo = AuthenticationRepository().initStorage();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Singleton Storage'),
),
body: Center(
child: FutureBuilder<AuthenticationRepository>(
future: authRepo,
builder: (context, snapshot) {
print('FutureBuilder re/building');
if (snapshot.hasData) {
return Text('Access token: ${snapshot.data.accessToken}');
}
return Text('loading...');
},
),
),
);
}
}