Flutter 如何在flatter/Dart中导入特定于平台的依赖项?(将Web与Android/iOS结合使用)

Flutter 如何在flatter/Dart中导入特定于平台的依赖项?(将Web与Android/iOS结合使用),flutter,dart,flutter-web,Flutter,Dart,Flutter Web,我在iOS和Android的Flitter应用程序中使用了共享_首选项。在web上,我使用的是http:dart依赖项(window.localStorage)本身。由于Flatter for web被合并到Flatter repo中,我想创建一个跨平台的解决方案 这意味着我需要导入两个独立的API。这在Dart中似乎还没有得到很好的支持,但我就是这么做的: import 'package:some_project/stub/preference_utils_stub.dart' if

我在iOS和Android的Flitter应用程序中使用了
共享_首选项。在web上,我使用的是
http:dart
依赖项(
window.localStorage
)本身。由于Flatter for web被合并到Flatter repo中,我想创建一个跨平台的解决方案

这意味着我需要导入两个独立的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\u utils\u 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;
}

窗口;
类共享引用{
静态未来获取getInstance异步{}
setString(字符串键,字符串值){}
getString(字符串键){}
}
类窗口{
地图本地存储;
}
这将在编译之前消除所有错误。现在,我实现了一些方法来检查应用程序是否正在使用web:

static Future<String> getString(String key) async {
    if (kIsWeb) {
       return window.localStorage[key];
    }
    SharedPreferences preferences = await SharedPreferences.getInstance;
    return preferences.getString(key);
}
static Future getString(字符串键)异步{
如果(kIsWeb){
返回窗口。localStorage[key];
}
SharedReferences首选项=等待SharedReferences.getInstance;
返回preferences.getString(键);
}
但是,这会产生大量错误:

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];
lib/utils/preference\u utils.dart:13:7:错误:找不到Getter:
“窗口”。
window.localStorage[key]=值;
^^^^^^lib/utils/preference_utils.dart:15:39:错误:无法将“Future Function()”类型的值分配给
类型为“SharedReferences”的变量。
-“Future”来自“dart:async”。
-“SharedPreferences”来自“package:shared_preferences/shared_preferences.dart”
(“../../flatter/.pub cache/hosted/pub.dartlang.org/shared_preferences-0.5.4+3/lib/shared_preferences.dart”)。
SharedReferences首选项=等待SharedReferences.getInstance;
^lib/utils/preference_utils.dart:22:14:错误:找不到Getter:
“窗口”。
返回窗口。localStorage[key];

等等。如何根据平台使用不同的方法/类而不出现这些错误?请注意,我以这种方式使用了更多的依赖项,而不仅仅是首选项。谢谢

以下是我对你的问题的看法。这是基于
http
包中的实现,如中所示

其核心思想如下

  • 创建一个抽象类来定义需要使用的方法
  • 创建特定于扩展此抽象类的
    web
    android
    依赖项的实现
  • 创建一个存根,该存根公开一个方法来返回此抽象实现的实例。这只是为了让dart分析工具满意
  • 在抽象类中,将此存根文件与特定于
    mobile
    web
    的条件导入一起导入。然后在其工厂构造函数中返回特定实现的实例。如果写入正确,这将由条件导入自动处理
  • 第1步和第4步:

    import'key\u finder\u stub.dart'
    //忽略:uri不存在
    if(dart.library.io)'package:flatter\u conditional\u dependencies\u example/storage/shared\u pref\u key\u finder.dart'
    //忽略:uri不存在
    if(dart.library.html)'package:flatter\u conditional\u dependencies\u example/storage/web\u key\u finder.dart';
    抽象类密钥查找器{
    //要公开的一些通用方法。
    ///返回基于键的值
    字符串getKeyValue(字符串键){
    返回“我来自接口”;
    }
    ///将键值对存储在相应的存储器中。
    void setKeyValue(字符串键,字符串值){}
    ///工厂构造函数返回正确的实现。
    factory KeyFinder()=>getKeyFinder();
    }
    
    步骤2.1:Web密钥查找器

    导入'dart:html';
    导入“package:flatter\u conditional\u dependencies\u example/storage/key\u finder\u interface.dart”;
    窗口位置;
    类WebKeyFinder实现KeyFinder{
    WebKeyFinder(){
    windowLoc=窗口;
    打印(“Widnow已初始化”);
    //最初存储某些内容只是为了确保其正常工作。:)
    windowLoc.localStorage[“MyKey”]=“我来自web本地存储”;
    }
    字符串getKeyValue(字符串键){
    返回windowLoc.localStorage[key];
    }
    void setKeyValue(字符串键,字符串值){
    windowLoc.localStorage[key]=值;
    }  
    }
    KeyFinder getKeyFinder()=>WebKeyFinder();
    
    步骤2.2:移动密钥查找器

    import'package:flatter\u conditional\u dependencies\u example/storage/key\u finder\u interface.dart';
    导入“package:shared_preferences/shared_preferences.dart”;
    类SharedPrefKeyFinder实现KeyFinder{
    SharedReferences\u实例;
    SharedPrefKeyFinder(){
    SharedReferences.getInstance()。然后((SharedReferences实例){
    _实例=实例;
    //只是初始化一些东西以便可以获取它。
    _setString(“MyKey”,“我来自共享偏好”);
    });
    }
    字符串getKeyValue(字符串键){
    返回_实例?.getString(键)??
    '共享首选项尚未初始化';
    }
    void setKeyValue(字符串键,字符串值){
    _实例?.setString(键、值);
    }
    }
    KeyFinder getKeyFinder()=>SharedPrefKeyFinder();
    
    第三步:

    导入“key\u finder\u interface.dart”;
    KeyFinder getKeyFinder()=>抛出不支持错误(
    '如果没有包dart:html或包:shared_首选项',则无法创建keyfinder';
    
    然后在
    main.dart
    中使用
    KeyFinder
    抽象类,就好像它是一个通用实现一样。这有点像适配器模式

    main.dart

    导入“包装:颤振/材料.省道”;
    导入“package:flatter\u conditional\u dependencies\u example/storage/key\u finder\u interface.dart”;
    void main()=>runApp(MyApp());
    类MyApp扩展了无状态小部件{
    //这个wi