J'utilise shared_preferences
dans mon application Flutter pour iOS et Android. Sur le Web, j'utilise le http:Dart
dépendance (window.localStorage
) lui-même. Depuis que Flutter pour le Web a été fusionné dans le référentiel Flutter, je souhaite créer une solution multiplateforme.
Cela signifie que je dois importer deux API distinctes. Cela ne semble pas encore être très bien pris en charge dans Dart, mais c'est ce que j'ai fait:
import 'package:some_project/stub/preference_utils_stub.Dart'
if (Dart.library.html) 'Dart:html'
if (Dart.library.io) 'package:shared_preferences/shared_preferences.Dart';
Dans mon preference_utils_stub.Dart
fichier, j'ai implémenté toutes les classes/variables qui doivent être visibles pendant la compilation:
Window window;
class SharedPreferences {
static Future<SharedPreferences> get getInstance async {}
setString(String key, String value) {}
getString(String key) {}
}
class Window {
Map<String, String> localStorage;
}
Cela supprime toutes les erreurs avant la compilation. Maintenant, j'ai implémenté une méthode qui vérifie si l'application utilise le Web ou non:
static Future<String> getString(String key) async {
if (kIsWeb) {
return window.localStorage[key];
}
SharedPreferences preferences = await SharedPreferences.getInstance;
return preferences.getString(key);
}
Cependant, cela donne beaucoup d'erreurs:
lib/utils/preference_utils.Dart:13:7: Error: Getter not found:
'window'.
window.localStorage[key] = value;
^^^^^^ lib/utils/preference_utils.Dart:15:39: Error: A value of type 'Future<SharedPreferences> Function()' can't be assigned to a
variable of type 'SharedPreferences'.
- 'Future' is from 'Dart:async'.
- 'SharedPreferences' is from 'package:shared_preferences/shared_preferences.Dart'
('../../flutter/.pub-cache/hosted/pub.dartlang.org/shared_preferences-0.5.4+3/lib/shared_preferences.Dart').
SharedPreferences preferences = await SharedPreferences.getInstance;
^ lib/utils/preference_utils.Dart:22:14: Error: Getter not found:
'window'.
return window.localStorage[key];
Etc. Comment peut-on utiliser différentes méthodes/classes selon la plateforme sans ces erreurs? Notez que j'utilise plus de dépendances de cette façon, pas seulement des préférences. Merci!
Voici mon approche de votre problème. Ceci est basé sur les implémentations du package http
comme dans ici .
L'idée centrale est la suivante.
web
et Android
qui étendent cette classe abstraite.mobile
et web
. Ensuite, dans son constructeur d'usine, renvoyez l'instance de l'implémentation spécifique. Cela sera géré automatiquement par importation conditionnelle s'il est écrit correctement.Étape 1 et 4:
import 'key_Finder_stub.Dart'
// ignore: uri_does_not_exist
if (Dart.library.io) 'package:flutter_conditional_dependencies_example/storage/shared_pref_key_Finder.Dart'
// ignore: uri_does_not_exist
if (Dart.library.html) 'package:flutter_conditional_dependencies_example/storage/web_key_Finder.Dart';
abstract class KeyFinder {
// some generic methods to be exposed.
/// returns a value based on the key
String getKeyValue(String key) {
return "I am from the interface";
}
/// stores a key value pair in the respective storage.
void setKeyValue(String key, String value) {}
/// factory constructor to return the correct implementation.
factory KeyFinder() => getKeyFinder();
}
Étape-2.1: Recherche de clé Web
import 'Dart:html';
import 'package:flutter_conditional_dependencies_example/storage/key_Finder_interface.Dart';
Window windowLoc;
class WebKeyFinder implements KeyFinder {
WebKeyFinder() {
windowLoc = window;
print("Widnow is initialized");
// storing something initially just to make sure it works. :)
windowLoc.localStorage["MyKey"] = "I am from web local storage";
}
String getKeyValue(String key) {
return windowLoc.localStorage[key];
}
void setKeyValue(String key, String value) {
windowLoc.localStorage[key] = value;
}
}
KeyFinder getKeyFinder() => WebKeyFinder();
Étape-2.2: Recherche de clé mobile
import 'package:flutter_conditional_dependencies_example/storage/key_Finder_interface.Dart';
import 'package:shared_preferences/shared_preferences.Dart';
class SharedPrefKeyFinder implements KeyFinder {
SharedPreferences _instance;
SharedPrefKeyFinder() {
SharedPreferences.getInstance().then((SharedPreferences instance) {
_instance = instance;
// Just initializing something so that it can be fetched.
_instance.setString("MyKey", "I am from Shared Preference");
});
}
String getKeyValue(String key) {
return _instance?.getString(key) ??
'shared preference is not yet initialized';
}
void setKeyValue(String key, String value) {
_instance?.setString(key, value);
}
}
KeyFinder getKeyFinder() => SharedPrefKeyFinder();
Étape 3:
import 'key_Finder_interface.Dart';
KeyFinder getKeyFinder() => throw UnsupportedError(
'Cannot create a keyfinder without the packages Dart:html or package:shared_preferences');
Puis dans votre main.Dart
utilisez la classe abstraite KeyFinder
comme si c'était une implémentation générique. C'est un peu comme un modèle d'adaptateur .
main.Dart
import 'package:flutter/material.Dart';
import 'package:flutter_conditional_dependencies_example/storage/key_Finder_interface.Dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
KeyFinder keyFinder = KeyFinder();
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SafeArea(
child: KeyValueWidget(
keyFinder: keyFinder,
),
),
);
}
}
class KeyValueWidget extends StatefulWidget {
final KeyFinder keyFinder;
KeyValueWidget({this.keyFinder});
@override
_KeyValueWidgetState createState() => _KeyValueWidgetState();
}
class _KeyValueWidgetState extends State<KeyValueWidget> {
String key = "MyKey";
TextEditingController _keyTextController = TextEditingController();
TextEditingController _valueTextController = TextEditingController();
@override
Widget build(BuildContext context) {
return Material(
child: Container(
width: 200.0,
child: Column(
children: <Widget>[
Expanded(
child: Text(
'$key / ${widget.keyFinder.getKeyValue(key)}',
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
),
),
Expanded(
child: TextFormField(
decoration: InputDecoration(
labelText: "Key",
border: OutlineInputBorder(),
),
controller: _keyTextController,
),
),
Expanded(
child: TextFormField(
decoration: InputDecoration(
labelText: "Value",
border: OutlineInputBorder(),
),
controller: _valueTextController,
),
),
RaisedButton(
child: Text('Save new Key/Value Pair'),
onPressed: () {
widget.keyFinder.setKeyValue(
_keyTextController.text,
_valueTextController.text,
);
setState(() {
key = _keyTextController.text;
});
},
)
],
),
),
);
}
}
quelques captures d'écran