Flutter / Dart'da platforma özgü bağımlılık nasıl alınır? (Web'i Android / iOS ile birleştirin)


11

shared_preferencesİOS ve Android için Flutter uygulamamda kullanıyorum . Web'de http:dartbağımlılığın ( window.localStorage) kendisini kullanıyorum. Web için Flutter, Flutter deposuna birleştirildiğinden, çapraz platform çözümü oluşturmak istiyorum.

Bu, iki ayrı API içe aktarmam gerektiği anlamına geliyor. Bu henüz Dart'da çok iyi desteklenmiyor gibi görünüyor, ama ben de bunu yaptım:

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';

Benim içinde preference_utils_stub.dartdosyaya, tüm sınıfları derleme sırasında görünür olması gerekir / değişkenler uygulamaya:

Window window;

class SharedPreferences {
  static Future<SharedPreferences> get getInstance async {}
  setString(String key, String value) {}
  getString(String key) {}
}

class Window {
  Map<String, String> localStorage;
}

Bu derleme önce tüm hatalardan kurtulur. Şimdi uygulamanın web kullanıp kullanmadığını kontrol eden bir yöntem uyguladım:

static Future<String> getString(String key) async {
    if (kIsWeb) {
       return window.localStorage[key];
    }
    SharedPreferences preferences = await SharedPreferences.getInstance;
    return preferences.getString(key);
}

Ancak, bu bir sürü hata verir:

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];

Ve bunun gibi. Bu hatalar olmadan platforma bağlı olarak farklı yöntemler / sınıflar nasıl kullanılabilir? Sadece tercihleri ​​değil, bu şekilde daha fazla bağımlılık kullandığımı unutmayın. Teşekkürler!


Sınırlı bilgime göre , aynı yöntem veya sınıfta hem localstorageve shared preferencesbağımlılıklara sahip olmamalısınız . Bu, derleyicinin bu bağımlılıkların her ikisini de sarsamayacağı anlamına gelir. İdeal olarak, içe aktarma bu uygulamaları gizlemelidir. Açık bir uygulama örneği bulmaya çalışacağım.
Abhilash Chandran

Uygulamanın web üzerinde çalışacak şekilde derlenip derlenmediğini söyleyen global boolean kIsWeb'i kullanabilirsiniz. Belgeler: api.flutter.dev/flutter/foundation/kIsWeb-constant.html if (kIsWeb) {// web üzerinde çalışıyor!
başlat

Yanıtlar:


25

İşte benim sorununuza yaklaşımım. Bu, buradahttp olduğu gibi paketteki uygulamalara dayanmaktadır .

Ana fikir aşağıdaki gibidir.

  1. Kullanmanız gereken yöntemleri tanımlamak için soyut bir sınıf oluşturun.
  2. Bu soyut sınıfı genişleten webve androidbağımlılıklara özgü uygulamalar oluşturun .
  3. Bu soyut uygulamanın örneğini döndürmek için bir yöntem ortaya koyan bir saplama oluşturun. Bu sadece dart analiz aracını mutlu etmek içindir.
  4. Soyut sınıfta şartlı ithalatı için spesifik ile birlikte bu saplama dosyasını içe mobileve web. Daha sonra fabrika yapıcısında belirli uygulamanın örneğini döndürün. Doğru yazılırsa bu koşullu içe aktarma ile otomatik olarak ele alınacaktır.

Adım-1 ve 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();
}

Adım-2.1: Web Anahtarı bulucu

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

Adım-2.2: Mobil Anahtar bulucu

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

Aşama 3:

import 'key_finder_interface.dart';

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

Sonra soyut sınıf main.dartkullanmak KeyFindergibi onun genel bir uygulama. Bu bir adaptör modeli gibidir .

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

bazı ekran görüntüleri

resim açıklamasını buraya girin resim açıklamasını buraya girin

seyyar resim açıklamasını buraya girin


2
Bu büyük çaba için teşekkürler! Aferin. Bu arada aynı yoldaydım (http paketine de bakıyorum, komik olan :)). Çok teşekkürler!
Giovanni

1
Umarım bu başkalarına da yardımcı olur. Hepimiz çözerek öğreniriz .. :-)
Abhilash Chandran

Merhaba kod çalıştı çalıştı! Ty. Daha sonra, uygulamanın web üzerinde çalışacak şekilde derlenip derlenmediğini söyleyen global boolean kIsWeb'i öğrendim. Belgeler: api.flutter.dev/flutter/foundation/kIsWeb-constant.html PS- Eğer bir şeyi göz ardı edersem, özür dilemek için önceden özür dilemek için çok daha basit hale gelir
Shamik Chodankar

2
@ShamikChodankar Haklısın. Bu boole bayrağı belirli mantıksal kararlar için yardımcı olacaktır. OP de bu seçeneği denedi. Ancak sorun, dart:html' and aynı işlevde her iki paylaşılan tercihleri de kullanırsak, derleyici hatalar üretecektir, çünkü dart:htmlbir mobil cihaza karşı derlerken bilmeyecek ve aksine sharedpreferencesyazarları olmadıkça web'e karşı derlerken bilmeyecektir. dahili olarak ele alın. Bu bayrağı kullanarak çalışan bir örneğiniz varsa lütfen paylaşın. Ben de çırpınmak için yeniyim :).
Abhilash Chandran
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.