[shared_preferences_linux] Add support for Linux (#2836)
Adds shared_preferences support for Linux.
Part of flutter/flutter#41720
diff --git a/packages/shared_preferences/shared_preferences_linux/.gitignore b/packages/shared_preferences/shared_preferences_linux/.gitignore
new file mode 100644
index 0000000..e9dc58d
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_linux/.gitignore
@@ -0,0 +1,7 @@
+.DS_Store
+.dart_tool/
+
+.packages
+.pub/
+
+build/
diff --git a/packages/shared_preferences/shared_preferences_linux/.metadata b/packages/shared_preferences/shared_preferences_linux/.metadata
new file mode 100644
index 0000000..9615744
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_linux/.metadata
@@ -0,0 +1,10 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: e491544588e8d34fdf31d5f840b4649850ef167a
+ channel: master
+
+project_type: plugin
diff --git a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md
new file mode 100644
index 0000000..1169480
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md
@@ -0,0 +1,2 @@
+## 0.0.1
+* Initial release to support shared_preferences on Linux.
diff --git a/packages/shared_preferences/shared_preferences_linux/LICENSE b/packages/shared_preferences/shared_preferences_linux/LICENSE
new file mode 100644
index 0000000..0c91662
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_linux/LICENSE
@@ -0,0 +1,27 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/packages/shared_preferences/shared_preferences_linux/README.md b/packages/shared_preferences/shared_preferences_linux/README.md
new file mode 100644
index 0000000..1894f50
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_linux/README.md
@@ -0,0 +1,22 @@
+# shared_preferences_linux
+
+The Linux implementation of [`shared_preferences`][1].
+
+## Usage
+
+### Import the package
+
+This package is an unendorsed Linux implementation of `shared_preferences`.
+
+In order to use this now, you'll need to depend on `shared_preferences_linux`.
+When this package is endorsed it will be automatically used by the `shared_preferences` package and you can switch to that API.
+
+```yaml
+...
+dependencies:
+ ...
+ shared_preferences_linux: ^0.0.1
+ ...
+```
+
+[1]: ../
diff --git a/packages/shared_preferences/shared_preferences_linux/example/.gitignore b/packages/shared_preferences/shared_preferences_linux/example/.gitignore
new file mode 100644
index 0000000..1ba9c33
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_linux/example/.gitignore
@@ -0,0 +1,43 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.packages
+.pub-cache/
+.pub/
+/build/
+
+# Web related
+lib/generated_plugin_registrant.dart
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
+
+# Exceptions to above rules.
+!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
diff --git a/packages/shared_preferences/shared_preferences_linux/example/.metadata b/packages/shared_preferences/shared_preferences_linux/example/.metadata
new file mode 100644
index 0000000..c0bc9a9
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_linux/example/.metadata
@@ -0,0 +1,10 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: e491544588e8d34fdf31d5f840b4649850ef167a
+ channel: master
+
+project_type: app
diff --git a/packages/shared_preferences/shared_preferences_linux/example/README.md b/packages/shared_preferences/shared_preferences_linux/example/README.md
new file mode 100644
index 0000000..9d3bf1f
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_linux/example/README.md
@@ -0,0 +1,8 @@
+# shared_preferences_example
+
+Demonstrates how to use the shared_preferences plugin.
+
+## Getting Started
+
+For help getting started with Flutter, view our online
+[documentation](http://flutter.io/).
diff --git a/packages/shared_preferences/shared_preferences_linux/example/lib/main.dart b/packages/shared_preferences/shared_preferences_linux/example/lib/main.dart
new file mode 100644
index 0000000..ceacf2f
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_linux/example/lib/main.dart
@@ -0,0 +1,87 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ignore_for_file: public_member_api_docs
+
+import 'dart:async';
+
+import 'package:flutter/material.dart';
+import 'package:shared_preferences_linux/shared_preferences_linux.dart';
+
+void main() {
+ runApp(MyApp());
+}
+
+class MyApp extends StatelessWidget {
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp(
+ title: 'SharedPreferences Demo',
+ home: SharedPreferencesDemo(),
+ );
+ }
+}
+
+class SharedPreferencesDemo extends StatefulWidget {
+ SharedPreferencesDemo({Key key}) : super(key: key);
+
+ @override
+ SharedPreferencesDemoState createState() => SharedPreferencesDemoState();
+}
+
+class SharedPreferencesDemoState extends State<SharedPreferencesDemo> {
+ final prefs = SharedPreferencesLinux.instance;
+ Future<int> _counter;
+
+ Future<void> _incrementCounter() async {
+ final values = await prefs.getAll();
+ final int counter = (values['counter'] as int ?? 0) + 1;
+
+ setState(() {
+ _counter = prefs.setValue(null, "counter", counter).then((bool success) {
+ return counter;
+ });
+ });
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ _counter = prefs.getAll().then((Map<String, Object> values) {
+ return (values['counter'] ?? 0);
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: const Text("SharedPreferences Demo"),
+ ),
+ body: Center(
+ child: FutureBuilder<int>(
+ future: _counter,
+ builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
+ switch (snapshot.connectionState) {
+ case ConnectionState.waiting:
+ return const CircularProgressIndicator();
+ default:
+ if (snapshot.hasError) {
+ return Text('Error: ${snapshot.error}');
+ } else {
+ return Text(
+ 'Button tapped ${snapshot.data} time${snapshot.data == 1 ? '' : 's'}.\n\n'
+ 'This should persist across restarts.',
+ );
+ }
+ }
+ })),
+ floatingActionButton: FloatingActionButton(
+ onPressed: _incrementCounter,
+ tooltip: 'Increment',
+ child: const Icon(Icons.add),
+ ),
+ );
+ }
+}
diff --git a/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml
new file mode 100644
index 0000000..1c06240
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml
@@ -0,0 +1,15 @@
+name: shared_preferences_linux_example
+description: Demonstrates how to use the shared_preferences_linux plugin.
+
+dependencies:
+ flutter:
+ sdk: flutter
+ shared_preferences_linux: ^0.1.0
+
+dependency_overrides:
+ shared_preferences_linux:
+ path: ../
+
+flutter:
+ uses-material-design: true
+
diff --git a/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart b/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart
new file mode 100644
index 0000000..dc93100
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart
@@ -0,0 +1,96 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert' show json;
+import 'package:file/file.dart';
+import 'package:file/local.dart';
+import 'package:meta/meta.dart';
+import 'package:path/path.dart' as path;
+import 'package:path_provider/path_provider.dart';
+import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
+
+/// The Linux implementation of [SharedPreferencesStorePlatform].
+///
+/// This class implements the `package:shared_preferences` functionality for Linux.
+class SharedPreferencesLinux extends SharedPreferencesStorePlatform {
+ /// The default instance of [SharedPreferencesLinux] to use.
+ static SharedPreferencesLinux instance = SharedPreferencesLinux();
+
+ /// Local copy of preferences
+ Map<String, Object> _cachedPreferences;
+
+ /// File system used to store to disk. Exposed for testing only.
+ @visibleForTesting
+ FileSystem fs = LocalFileSystem();
+
+ /// Gets the file where the preferences are stored.
+ Future<File> _getLocalDataFile() async {
+ var directory = await getApplicationSupportDirectory();
+ var filePath = path.join(directory.path, 'shared_preferences.json');
+ return fs.file(filePath);
+ }
+
+ /// Gets the preferences from the stored file. Once read, the preferences are
+ /// maintained in memory.
+ Future<Map<String, Object>> _readPreferences() async {
+ if (_cachedPreferences != null) {
+ return _cachedPreferences;
+ }
+
+ _cachedPreferences = {};
+ var localDataFile = await _getLocalDataFile();
+ if (localDataFile.existsSync()) {
+ String stringMap = localDataFile.readAsStringSync();
+ if (stringMap.isNotEmpty) {
+ _cachedPreferences = json.decode(stringMap) as Map<String, Object>;
+ }
+ }
+
+ return _cachedPreferences;
+ }
+
+ /// Writes the cached preferences to disk. Returns [true] if the operation
+ /// succeeded.
+ Future<bool> _writePreferences(Map<String, Object> preferences) async {
+ try {
+ var localDataFile = await _getLocalDataFile();
+ if (!localDataFile.existsSync()) {
+ localDataFile.createSync(recursive: true);
+ }
+ var stringMap = json.encode(preferences);
+ localDataFile.writeAsStringSync(stringMap);
+ } catch (e) {
+ print("Error saving preferences to disk: $e");
+ return false;
+ }
+ return true;
+ }
+
+ @override
+ Future<bool> clear() async {
+ var preferences = await _readPreferences();
+ preferences.clear();
+ return _writePreferences(preferences);
+ }
+
+ @override
+ Future<Map<String, Object>> getAll() async {
+ return _readPreferences();
+ }
+
+ @override
+ Future<bool> remove(String key) async {
+ var preferences = await _readPreferences();
+ preferences.remove(key);
+ return _writePreferences(preferences);
+ }
+
+ @override
+ Future<bool> setValue(String valueType, String key, Object value) async {
+ var preferences = await _readPreferences();
+ preferences[key] = value;
+ return _writePreferences(preferences);
+ }
+}
diff --git a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml
new file mode 100644
index 0000000..2539b93
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml
@@ -0,0 +1,29 @@
+name: shared_preferences_linux
+description: Linux implementation of the shared_preferences plugin
+version: 0.0.1
+homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_linux
+
+flutter:
+ plugin:
+ platforms:
+ linux:
+ dartPluginClass: SharedPreferencesLinux
+ pluginClass: none
+
+environment:
+ sdk: ">=2.1.0 <3.0.0"
+ flutter: ">=1.12.8 <2.0.0"
+
+dependencies:
+ file: ^5.1.0
+ flutter:
+ sdk: flutter
+ meta: ^1.0.4
+ path: ^1.6.4
+ path_provider: ^1.6.11
+ shared_preferences_platform_interface: ^1.0.0
+
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+ pedantic: ^1.8.0
diff --git a/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart b/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart
new file mode 100644
index 0000000..8a794b1
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart
@@ -0,0 +1,74 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+import 'package:file/memory.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:path/path.dart' as path;
+import 'package:path_provider/path_provider.dart';
+import 'package:shared_preferences_linux/shared_preferences_linux.dart';
+
+MemoryFileSystem fs = MemoryFileSystem.test();
+
+void main() {
+ setUp(() {});
+
+ tearDown(() {});
+
+ Future<String> _getFilePath() async {
+ var directory = await getApplicationSupportDirectory();
+ return path.join(directory.path, 'shared_preferences.json');
+ }
+
+ _writeTestFile(String value) async {
+ fs.file(await _getFilePath())
+ ..createSync(recursive: true)
+ ..writeAsStringSync(value);
+ }
+
+ Future<String> _readTestFile() async {
+ return fs.file(await _getFilePath()).readAsStringSync();
+ }
+
+ SharedPreferencesLinux _getPreferences() {
+ var prefs = SharedPreferencesLinux();
+ prefs.fs = fs;
+ return prefs;
+ }
+
+ test('getAll', () async {
+ await _writeTestFile('{"key1": "one", "key2": 2}');
+ var prefs = _getPreferences();
+
+ var values = await prefs.getAll();
+ expect(values, hasLength(2));
+ expect(values['key1'], 'one');
+ expect(values['key2'], 2);
+ });
+
+ test('remove', () async {
+ await _writeTestFile('{"key1":"one","key2":2}');
+ var prefs = _getPreferences();
+
+ await prefs.remove('key2');
+
+ expect(await _readTestFile(), '{"key1":"one"}');
+ });
+
+ test('setValue', () async {
+ await _writeTestFile('{}');
+ var prefs = _getPreferences();
+
+ await prefs.setValue('', 'key1', 'one');
+ await prefs.setValue('', 'key2', 2);
+
+ expect(await _readTestFile(), '{"key1":"one","key2":2}');
+ });
+
+ test('clear', () async {
+ await _writeTestFile('{"key1":"one","key2":2}');
+ var prefs = _getPreferences();
+
+ await prefs.clear();
+ expect(await _readTestFile(), '{}');
+ });
+}
diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh
index 2c0a906..262c4ed 100755
--- a/script/build_all_plugins_app.sh
+++ b/script/build_all_plugins_app.sh
@@ -26,6 +26,7 @@
"path_provider_platform_interface"
"path_provider_web"
"plugin_platform_interface"
+ "shared_preferences_linux"
"shared_preferences_macos"
"shared_preferences_platform_interface"
"shared_preferences_web"