Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 546 Vote(s) - 3.55 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How to import platform specific dependency in Flutter/Dart? (Combine Web with Android/iOS)

#1
I am using `shared_preferences` in my Flutter application for iOS and Android. On the web I am using the `http:dart` dependency (`window.localStorage`) itself. Since Flutter for web was merged into the Flutter repo, I want to create a cross platform solution.

This means I need to import two seperate API's. This seems not to be very good supported in Dart yet, but this is what I did:

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

```

In my `preference_utils_stub.dart` file, I implemented all classes/variables which need to be visible during compile time:

```
Window window;

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

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

```

This gets rid of all errors before compilation. Now I implemented some method which checks if the application is using the web or not:

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

However, this gives loads of errors:

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

And so on. How can one use different methods/classes depending on the platform without these errors? Note that I am using more dependencies this way, not just preferences. Thanks!
Reply

#2
Here is my approach to your issue. This is based on the implementations from `http` package as in [here][1].

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:**
```lang-dart
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**
```lang-dart
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**
```lang-dart
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:**
```lang-dart
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`**
```lang-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**
[![enter image description here][2]][2]
[![enter image description here][3]][3]

**mobile**
[![enter image description here][4]][4]


[1]:

[To see links please register here]

[2]:

[3]:

[4]:
Reply

#3
you can just use the package [universal_html][1]


[1]:

[To see links please register here]

Reply

#4
Thanks @AbhilashChandran
I was troubling this kind of problem with the credentials of the http client.

here is my solution copied from @AbhilashChandran without interface

get_client.dart:

import 'package:http/http.dart';

Client getClient() => throw UnsupportedError('[Platform ERROR] Network client');

mobile_client.dart:

import 'package:http/http.dart';

Client getClient() => Client();

web_client.dart:

import 'package:http/browser_client.dart';
import 'package:http/http.dart';

Client getClient() => BrowserClient()..withCredentials = true;

network_client.dart

import 'get_client.dart'
if (dart.library.io) 'mobile_client.dart'
if (dart.library.html) 'web_client.dart';

import 'dart:convert';
import 'package:http/http.dart';
import '../../constants/url_paths.dart';

class NetworkClient {
final client = getClient();

final headers = {
'Content-Type': 'application/json',
};

Future<Response> get(String path) =>
client.get(Uri.http(url, path), headers: headers);

Future<Response> post(String path, dynamic parameter) =>
client.post(Uri.http(url, path),
headers: headers, body: json.encode(parameter));

Future<Response> put(String path, dynamic parameter) => client.put(Uri.http(url, path), headers: headers, body: json.encode(parameter));

Future<Response> delete(String path) =>
client.delete(Uri.http(url, path), headers: headers);
}

Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through