IOSおよびAndroid用のFlutterアプリケーションでshared_preferences
を使用しています。 Webでは、http:Dart
依存関係(window.localStorage
)自体を使用しています。 Flutter for webがFlutterリポジトリに統合されたので、クロスプラットフォームソリューションを作成したいと考えています。
つまり、2つの別個のAPIをインポートする必要があります。これはまだDartでサポートされているようには見えませんが、これは私がやったことです:
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';
私のpreference_utils_stub.Dart
ファイルには、コンパイル時に表示する必要があるすべてのクラス/変数を実装しました。
Window window;
class SharedPreferences {
static Future<SharedPreferences> get getInstance async {}
setString(String key, String value) {}
getString(String key) {}
}
class Window {
Map<String, String> localStorage;
}
これにより、コンパイル前にすべてのエラーが取り除かれます。ここで、アプリケーションがWebを使用しているかどうかをチェックするいくつかのメソッドを実装しました。
static Future<String> getString(String key) async {
if (kIsWeb) {
return window.localStorage[key];
}
SharedPreferences preferences = await SharedPreferences.getInstance;
return preferences.getString(key);
}
ただし、これにより多くのエラーが発生します。
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];
等々。これらのエラーなしで、プラットフォームに応じて異なるメソッド/クラスをどのように使用できますか?この方法では、設定だけでなく、より多くの依存関係を使用していることに注意してください。ありがとう!
これがあなたの問題に対する私のアプローチです。これは here のようにhttp
パッケージの実装に基づいています。
基本的な考え方は次のとおりです。
web
およびAndroid
依存関係に固有の実装を作成します。mobile
およびweb
に固有の条件付きインポートとともにインポートします。次に、そのファクトリコンストラクタで、特定の実装のインスタンスを返します。これは、正しく記述されていれば、条件付きインポートによって自動的に処理されます。ステップ1および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();
}
Step-2.1:Web Key Finder
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();
ステップ-2.2:モバイルキーファインダー
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();
ステップ-3:
import 'key_Finder_interface.Dart';
KeyFinder getKeyFinder() => throw UnsupportedError(
'Cannot create a keyfinder without the packages Dart:html or package:shared_preferences');
次に、main.Dart
KeyFinder
抽象クラスを、その一般的な実装のように使用します。これは、アダプタパターンに似ています。
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;
});
},
)
],
),
),
);
}
}
一部のスクリーンショット