How to import platform specific dependency in Flutter/Dart? (Combine Web with Android/iOS)

前端 未结 1 1103
耶瑟儿~
耶瑟儿~ 2020-11-30 09:05

I am using shared_preferences in my Flutter application for iOS and Android. On the web I am using the http:dart dependency (window.localStor

相关标签:
1条回答
  • 2020-11-30 09:16

    Here is my approach to your issue. This is based on the implementations from http package as in here.

    The core idea is as follows.

    1. Create an abstract class to define the methods you will need to use.
    2. Create implementations specific to web and android dependencies which extends this abstract class.
    3. Create a stub which exposes a method to return the instance of this abstract implementation. This is only to keep the dart analysis tool happy.
    4. In the abstract class import this stub file along with the conditional imports specific for mobile and web. Then in its factory constructor return the instance of the specific implementation. This will be handled automatically by conditional import if written correctly.

    Step-1 and 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();
    

    Step-2.2: Mobile Key finder

    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();
    

    Step-3:

    import 'key_finder_interface.dart';
    
    KeyFinder getKeyFinder() => throw UnsupportedError(
        'Cannot create a keyfinder without the packages dart:html or package:shared_preferences');
    

    Then in your main.dart use the KeyFinder abstract class as if its a generic implementation. This is somewhat like an adapter pattern.

    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;
                    });
                  },
                )
              ],
            ),
          ),
        );
      }
    }
    
    

    some screen shots

    Web

    mobile

    0 讨论(0)
提交回复
热议问题