[shared_preferences] allow custom key prefixes - platform changes (#3596)

[shared_preferences] allow custom key prefixes - platform changes
diff --git a/packages/shared_preferences/shared_preferences_android/CHANGELOG.md b/packages/shared_preferences/shared_preferences_android/CHANGELOG.md
index adefa4f..044aedf 100644
--- a/packages/shared_preferences/shared_preferences_android/CHANGELOG.md
+++ b/packages/shared_preferences/shared_preferences_android/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 2.1.0
+
+* Adds `getAllWithPrefix` and `clearWithPrefix` methods.
+
 ## 2.0.17
 
 * Clarifies explanation of endorsement in README.
diff --git a/packages/shared_preferences/shared_preferences_android/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java b/packages/shared_preferences/shared_preferences_android/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java
index cea3f34..7bdc8e7 100644
--- a/packages/shared_preferences/shared_preferences_android/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java
+++ b/packages/shared_preferences/shared_preferences_android/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java
@@ -106,16 +106,18 @@
           // We've been committing the whole time.
           result.success(true);
           break;
-        case "getAll":
-          result.success(getAllPrefs());
+        case "getAllWithPrefix":
+          String prefix = call.argument("prefix");
+          result.success(getAllPrefs(prefix));
           return;
         case "remove":
           commitAsync(preferences.edit().remove(key), result);
           break;
-        case "clear":
-          Set<String> keySet = getAllPrefs().keySet();
+        case "clearWithPrefix":
+          String newPrefix = call.argument("prefix");
+          Set<String> keys = getAllPrefs(newPrefix).keySet();
           SharedPreferences.Editor clearEditor = preferences.edit();
-          for (String keyToDelete : keySet) {
+          for (String keyToDelete : keys) {
             clearEditor.remove(keyToDelete);
           }
           commitAsync(clearEditor, result);
@@ -181,12 +183,12 @@
     }
   }
 
-  // Filter preferences to only those set by the flutter app.
-  private Map<String, Object> getAllPrefs() throws IOException {
+  // Gets all shared preferences, filtered to only those set with the given prefix.
+  private Map<String, Object> getAllPrefs(String prefix) throws IOException {
     Map<String, ?> allPrefs = preferences.getAll();
     Map<String, Object> filteredPrefs = new HashMap<>();
     for (String key : allPrefs.keySet()) {
-      if (key.startsWith("flutter.")) {
+      if (key.startsWith(prefix)) {
         Object value = allPrefs.get(key);
         if (value instanceof String) {
           String stringValue = (String) value;
diff --git a/packages/shared_preferences/shared_preferences_android/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_android/example/integration_test/shared_preferences_test.dart
index 4d4a85a..46ce5e4 100644
--- a/packages/shared_preferences/shared_preferences_android/example/integration_test/shared_preferences_test.dart
+++ b/packages/shared_preferences/shared_preferences_android/example/integration_test/shared_preferences_test.dart
@@ -11,22 +11,36 @@
   IntegrationTestWidgetsFlutterBinding.ensureInitialized();
 
   group('SharedPreferencesAndroid', () {
-    const Map<String, Object> kTestValues = <String, Object>{
+    const Map<String, Object> flutterTestValues = <String, Object>{
       'flutter.String': 'hello world',
-      'flutter.bool': true,
-      'flutter.int': 42,
-      'flutter.double': 3.14159,
-      'flutter.List': <String>['foo', 'bar'],
+      'flutter.Bool': true,
+      'flutter.Int': 42,
+      'flutter.Double': 3.14159,
+      'flutter.StringList': <String>['foo', 'bar'],
     };
 
-    const Map<String, Object> kTestValues2 = <String, Object>{
-      'flutter.String': 'goodbye world',
-      'flutter.bool': false,
-      'flutter.int': 1337,
-      'flutter.double': 2.71828,
-      'flutter.List': <String>['baz', 'quox'],
+    const Map<String, Object> prefixTestValues = <String, Object>{
+      'prefix.String': 'hello world',
+      'prefix.Bool': true,
+      'prefix.Int': 42,
+      'prefix.Double': 3.14159,
+      'prefix.StringList': <String>['foo', 'bar'],
     };
 
+    const Map<String, Object> nonPrefixTestValues = <String, Object>{
+      'String': 'hello world',
+      'Bool': true,
+      'Int': 42,
+      'Double': 3.14159,
+      'StringList': <String>['foo', 'bar'],
+    };
+
+    final Map<String, Object> allTestValues = <String, Object>{};
+
+    allTestValues.addAll(flutterTestValues);
+    allTestValues.addAll(prefixTestValues);
+    allTestValues.addAll(nonPrefixTestValues);
+
     late SharedPreferencesStorePlatform preferences;
 
     setUp(() async {
@@ -34,95 +48,227 @@
     });
 
     tearDown(() {
-      preferences.clear();
+      preferences.clearWithPrefix('');
     });
 
-    // Normally the app-facing package adds the prefix, but since this test
-    // bypasses the app-facing package it needs to be manually added.
-    String prefixedKey(String key) {
-      return 'flutter.$key';
-    }
-
     testWidgets('reading', (WidgetTester _) async {
-      final Map<String, Object> values = await preferences.getAll();
-      expect(values[prefixedKey('String')], isNull);
-      expect(values[prefixedKey('bool')], isNull);
-      expect(values[prefixedKey('int')], isNull);
-      expect(values[prefixedKey('double')], isNull);
-      expect(values[prefixedKey('List')], isNull);
+      final Map<String, Object> values = await preferences.getAllWithPrefix('');
+      expect(values['String'], isNull);
+      expect(values['Bool'], isNull);
+      expect(values['Int'], isNull);
+      expect(values['Double'], isNull);
+      expect(values['StringList'], isNull);
     });
 
-    testWidgets('writing', (WidgetTester _) async {
+    testWidgets('getAllWithPrefix', (WidgetTester _) async {
       await Future.wait(<Future<bool>>[
         preferences.setValue(
-            'String', prefixedKey('String'), kTestValues2['flutter.String']!),
+            'String', 'prefix.String', allTestValues['prefix.String']!),
         preferences.setValue(
-            'Bool', prefixedKey('bool'), kTestValues2['flutter.bool']!),
+            'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!),
+        preferences.setValue('Int', 'prefix.Int', allTestValues['prefix.Int']!),
         preferences.setValue(
-            'Int', prefixedKey('int'), kTestValues2['flutter.int']!),
+            'Double', 'prefix.Double', allTestValues['prefix.Double']!),
+        preferences.setValue('StringList', 'prefix.StringList',
+            allTestValues['prefix.StringList']!),
         preferences.setValue(
-            'Double', prefixedKey('double'), kTestValues2['flutter.double']!),
+            'String', 'flutter.String', allTestValues['flutter.String']!),
         preferences.setValue(
-            'StringList', prefixedKey('List'), kTestValues2['flutter.List']!)
+            'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
+        preferences.setValue(
+            'Int', 'flutter.Int', allTestValues['flutter.Int']!),
+        preferences.setValue(
+            'Double', 'flutter.Double', allTestValues['flutter.Double']!),
+        preferences.setValue('StringList', 'flutter.StringList',
+            allTestValues['flutter.StringList']!)
       ]);
-      final Map<String, Object> values = await preferences.getAll();
-      expect(values[prefixedKey('String')], kTestValues2['flutter.String']);
-      expect(values[prefixedKey('bool')], kTestValues2['flutter.bool']);
-      expect(values[prefixedKey('int')], kTestValues2['flutter.int']);
-      expect(values[prefixedKey('double')], kTestValues2['flutter.double']);
-      expect(values[prefixedKey('List')], kTestValues2['flutter.List']);
+      final Map<String, Object> values =
+          await preferences.getAllWithPrefix('prefix.');
+      expect(values['prefix.String'], allTestValues['prefix.String']);
+      expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
+      expect(values['prefix.Int'], allTestValues['prefix.Int']);
+      expect(values['prefix.Double'], allTestValues['prefix.Double']);
+      expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
     });
 
-    testWidgets('removing', (WidgetTester _) async {
-      final String key = prefixedKey('testKey');
-      await preferences.setValue('String', key, kTestValues['flutter.String']!);
-      await preferences.setValue('Bool', key, kTestValues['flutter.bool']!);
-      await preferences.setValue('Int', key, kTestValues['flutter.int']!);
-      await preferences.setValue('Double', key, kTestValues['flutter.double']!);
-      await preferences.setValue(
-          'StringList', key, kTestValues['flutter.List']!);
-      await preferences.remove(key);
+    testWidgets('clearWithPrefix', (WidgetTester _) async {
+      await Future.wait(<Future<bool>>[
+        preferences.setValue(
+            'String', 'prefix.String', allTestValues['prefix.String']!),
+        preferences.setValue(
+            'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!),
+        preferences.setValue('Int', 'prefix.Int', allTestValues['prefix.Int']!),
+        preferences.setValue(
+            'Double', 'prefix.Double', allTestValues['prefix.Double']!),
+        preferences.setValue('StringList', 'prefix.StringList',
+            allTestValues['prefix.StringList']!),
+        preferences.setValue(
+            'String', 'flutter.String', allTestValues['flutter.String']!),
+        preferences.setValue(
+            'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
+        preferences.setValue(
+            'Int', 'flutter.Int', allTestValues['flutter.Int']!),
+        preferences.setValue(
+            'Double', 'flutter.Double', allTestValues['flutter.Double']!),
+        preferences.setValue('StringList', 'flutter.StringList',
+            allTestValues['flutter.StringList']!)
+      ]);
+      await preferences.clearWithPrefix('prefix.');
+      Map<String, Object> values =
+          await preferences.getAllWithPrefix('prefix.');
+      expect(values['prefix.String'], null);
+      expect(values['prefix.Bool'], null);
+      expect(values['prefix.Int'], null);
+      expect(values['prefix.Double'], null);
+      expect(values['prefix.StringList'], null);
+      values = await preferences.getAllWithPrefix('flutter.');
+      expect(values['flutter.String'], allTestValues['flutter.String']);
+      expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
+      expect(values['flutter.Int'], allTestValues['flutter.Int']);
+      expect(values['flutter.Double'], allTestValues['flutter.Double']);
+      expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
+    });
+
+    testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
+      await Future.wait(<Future<bool>>[
+        preferences.setValue('String', 'String', allTestValues['String']!),
+        preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
+        preferences.setValue('Int', 'Int', allTestValues['Int']!),
+        preferences.setValue('Double', 'Double', allTestValues['Double']!),
+        preferences.setValue(
+            'StringList', 'StringList', allTestValues['StringList']!),
+        preferences.setValue(
+            'String', 'flutter.String', allTestValues['flutter.String']!),
+        preferences.setValue(
+            'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
+        preferences.setValue(
+            'Int', 'flutter.Int', allTestValues['flutter.Int']!),
+        preferences.setValue(
+            'Double', 'flutter.Double', allTestValues['flutter.Double']!),
+        preferences.setValue('StringList', 'flutter.StringList',
+            allTestValues['flutter.StringList']!)
+      ]);
+      final Map<String, Object> values = await preferences.getAllWithPrefix('');
+      expect(values['String'], allTestValues['String']);
+      expect(values['Bool'], allTestValues['Bool']);
+      expect(values['Int'], allTestValues['Int']);
+      expect(values['Double'], allTestValues['Double']);
+      expect(values['StringList'], allTestValues['StringList']);
+      expect(values['flutter.String'], allTestValues['flutter.String']);
+      expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
+      expect(values['flutter.Int'], allTestValues['flutter.Int']);
+      expect(values['flutter.Double'], allTestValues['flutter.Double']);
+      expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
+    });
+
+    testWidgets('clearWithNoPrefix', (WidgetTester _) async {
+      await Future.wait(<Future<bool>>[
+        preferences.setValue('String', 'String', allTestValues['String']!),
+        preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
+        preferences.setValue('Int', 'Int', allTestValues['Int']!),
+        preferences.setValue('Double', 'Double', allTestValues['Double']!),
+        preferences.setValue(
+            'StringList', 'StringList', allTestValues['StringList']!),
+        preferences.setValue(
+            'String', 'flutter.String', allTestValues['flutter.String']!),
+        preferences.setValue(
+            'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
+        preferences.setValue(
+            'Int', 'flutter.Int', allTestValues['flutter.Int']!),
+        preferences.setValue(
+            'Double', 'flutter.Double', allTestValues['flutter.Double']!),
+        preferences.setValue('StringList', 'flutter.StringList',
+            allTestValues['flutter.StringList']!)
+      ]);
+      await preferences.clearWithPrefix('');
+      final Map<String, Object> values = await preferences.getAllWithPrefix('');
+      expect(values['String'], null);
+      expect(values['Bool'], null);
+      expect(values['Int'], null);
+      expect(values['Double'], null);
+      expect(values['StringList'], null);
+      expect(values['flutter.String'], null);
+      expect(values['flutter.Bool'], null);
+      expect(values['flutter.Int'], null);
+      expect(values['flutter.Double'], null);
+      expect(values['flutter.StringList'], null);
+    });
+
+    testWidgets('getAll', (WidgetTester _) async {
+      await Future.wait(<Future<bool>>[
+        preferences.setValue(
+            'String', 'flutter.String', allTestValues['flutter.String']!),
+        preferences.setValue(
+            'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
+        preferences.setValue(
+            'Int', 'flutter.Int', allTestValues['flutter.Int']!),
+        preferences.setValue(
+            'Double', 'flutter.Double', allTestValues['flutter.Double']!),
+        preferences.setValue('StringList', 'flutter.StringList',
+            allTestValues['flutter.StringList']!)
+      ]);
       final Map<String, Object> values = await preferences.getAll();
+      expect(values['flutter.String'], allTestValues['flutter.String']);
+      expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
+      expect(values['flutter.Int'], allTestValues['flutter.Int']);
+      expect(values['flutter.Double'], allTestValues['flutter.Double']);
+      expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
+    });
+
+    testWidgets('remove', (WidgetTester _) async {
+      const String key = 'testKey';
+      await preferences.setValue(
+          'String', key, allTestValues['flutter.String']!);
+      await preferences.setValue('Bool', key, allTestValues['flutter.Bool']!);
+      await preferences.setValue('Int', key, allTestValues['flutter.Int']!);
+      await preferences.setValue(
+          'Double', key, allTestValues['flutter.Double']!);
+      await preferences.setValue(
+          'StringList', key, allTestValues['flutter.StringList']!);
+      await preferences.remove(key);
+      final Map<String, Object> values = await preferences.getAllWithPrefix('');
       expect(values[key], isNull);
     });
 
-    testWidgets('clearing', (WidgetTester _) async {
+    testWidgets('clear', (WidgetTester _) async {
       await preferences.setValue(
-          'String', 'String', kTestValues['flutter.String']!);
-      await preferences.setValue('Bool', 'bool', kTestValues['flutter.bool']!);
-      await preferences.setValue('Int', 'int', kTestValues['flutter.int']!);
+          'String', 'flutter.String', allTestValues['flutter.String']!);
       await preferences.setValue(
-          'Double', 'double', kTestValues['flutter.double']!);
+          'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!);
       await preferences.setValue(
-          'StringList', 'List', kTestValues['flutter.List']!);
+          'Int', 'flutter.Int', allTestValues['flutter.Int']!);
+      await preferences.setValue(
+          'Double', 'flutter.Double', allTestValues['flutter.Double']!);
+      await preferences.setValue('StringList', 'flutter.StringList',
+          allTestValues['flutter.StringList']!);
       await preferences.clear();
       final Map<String, Object> values = await preferences.getAll();
-      expect(values['String'], null);
-      expect(values['bool'], null);
-      expect(values['int'], null);
-      expect(values['double'], null);
-      expect(values['List'], null);
+      expect(values['flutter.String'], null);
+      expect(values['flutter.Bool'], null);
+      expect(values['flutter.Int'], null);
+      expect(values['flutter.Double'], null);
+      expect(values['flutter.StringList'], null);
     });
 
     testWidgets('simultaneous writes', (WidgetTester _) async {
       final List<Future<bool>> writes = <Future<bool>>[];
       const int writeCount = 100;
       for (int i = 1; i <= writeCount; i++) {
-        writes.add(preferences.setValue('Int', prefixedKey('int'), i));
+        writes.add(preferences.setValue('Int', 'Int', i));
       }
       final List<bool> result = await Future.wait(writes, eagerError: true);
       // All writes should succeed.
       expect(result.where((bool element) => !element), isEmpty);
       // The last write should win.
-      final Map<String, Object> values = await preferences.getAll();
-      expect(values[prefixedKey('int')], writeCount);
+      final Map<String, Object> values = await preferences.getAllWithPrefix('');
+      expect(values['Int'], writeCount);
     });
 
     testWidgets('string clash with lists, big integers and doubles',
         (WidgetTester _) async {
-      final String key = prefixedKey('akey');
+      const String key = 'akey';
       const String value = 'a string value';
-      await preferences.clear();
+      await preferences.clearWithPrefix('');
 
       // Special prefixes used to store datatypes that can't be stored directly
       // in SharedPreferences as strings instead.
@@ -137,7 +283,8 @@
       for (final String prefix in specialPrefixes) {
         expect(preferences.setValue('String', key, prefix + value),
             throwsA(isA<PlatformException>()));
-        final Map<String, Object> values = await preferences.getAll();
+        final Map<String, Object> values =
+            await preferences.getAllWithPrefix('');
         expect(values[key], null);
       }
     });
diff --git a/packages/shared_preferences/shared_preferences_android/lib/shared_preferences_android.dart b/packages/shared_preferences/shared_preferences_android/lib/shared_preferences_android.dart
index da5147d..b77db6c 100644
--- a/packages/shared_preferences/shared_preferences_android/lib/shared_preferences_android.dart
+++ b/packages/shared_preferences/shared_preferences_android/lib/shared_preferences_android.dart
@@ -19,6 +19,8 @@
     SharedPreferencesStorePlatform.instance = SharedPreferencesAndroid();
   }
 
+  static const String _defaultPrefix = 'flutter.';
+
   @override
   Future<bool> remove(String key) async {
     return (await _kChannel.invokeMethod<bool>(
@@ -37,17 +39,28 @@
 
   @override
   Future<bool> clear() async {
-    return (await _kChannel.invokeMethod<bool>('clear'))!;
+    return clearWithPrefix(_defaultPrefix);
+  }
+
+  @override
+  Future<bool> clearWithPrefix(String prefix) async {
+    return (await _kChannel.invokeMethod<bool>(
+      'clearWithPrefix',
+      <String, dynamic>{'prefix': prefix},
+    ))!;
   }
 
   @override
   Future<Map<String, Object>> getAll() async {
-    final Map<String, Object>? preferences =
-        await _kChannel.invokeMapMethod<String, Object>('getAll');
+    return getAllWithPrefix(_defaultPrefix);
+  }
 
-    if (preferences == null) {
-      return <String, Object>{};
-    }
-    return preferences;
+  @override
+  Future<Map<String, Object>> getAllWithPrefix(String prefix) async {
+    return (await _kChannel.invokeMapMethod<String, Object>(
+          'getAllWithPrefix',
+          <String, dynamic>{'prefix': prefix},
+        )) ??
+        <String, Object>{};
   }
 }
diff --git a/packages/shared_preferences/shared_preferences_android/pubspec.yaml b/packages/shared_preferences/shared_preferences_android/pubspec.yaml
index 963ed8b..02dd43a 100644
--- a/packages/shared_preferences/shared_preferences_android/pubspec.yaml
+++ b/packages/shared_preferences/shared_preferences_android/pubspec.yaml
@@ -2,7 +2,7 @@
 description: Android implementation of the shared_preferences plugin
 repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_android
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22
-version: 2.0.17
+version: 2.1.0
 
 environment:
   sdk: ">=2.17.0 <4.0.0"
@@ -20,7 +20,7 @@
 dependencies:
   flutter:
     sdk: flutter
-  shared_preferences_platform_interface: ^2.0.0
+  shared_preferences_platform_interface: ^2.2.0
 
 dev_dependencies:
   flutter_test:
diff --git a/packages/shared_preferences/shared_preferences_android/test/shared_preferences_android_test.dart b/packages/shared_preferences/shared_preferences_android/test/shared_preferences_android_test.dart
index f1043da..9c4ce21 100644
--- a/packages/shared_preferences/shared_preferences_android/test/shared_preferences_android_test.dart
+++ b/packages/shared_preferences/shared_preferences_android/test/shared_preferences_android_test.dart
@@ -16,15 +16,36 @@
       'plugins.flutter.io/shared_preferences_android',
     );
 
-    const Map<String, Object> kTestValues = <String, Object>{
+    const Map<String, Object> flutterTestValues = <String, Object>{
       'flutter.String': 'hello world',
       'flutter.Bool': true,
       'flutter.Int': 42,
       'flutter.Double': 3.14159,
       'flutter.StringList': <String>['foo', 'bar'],
     };
-    // Create a dummy in-memory implementation to back the mocked method channel
-    // API to simplify validation of the expected calls.
+
+    const Map<String, Object> prefixTestValues = <String, Object>{
+      'prefix.String': 'hello world',
+      'prefix.Bool': true,
+      'prefix.Int': 42,
+      'prefix.Double': 3.14159,
+      'prefix.StringList': <String>['foo', 'bar'],
+    };
+
+    const Map<String, Object> nonPrefixTestValues = <String, Object>{
+      'String': 'hello world',
+      'Bool': true,
+      'Int': 42,
+      'Double': 3.14159,
+      'StringList': <String>['foo', 'bar'],
+    };
+
+    final Map<String, Object> allTestValues = <String, Object>{};
+
+    allTestValues.addAll(flutterTestValues);
+    allTestValues.addAll(prefixTestValues);
+    allTestValues.addAll(nonPrefixTestValues);
+
     late InMemorySharedPreferencesStore testData;
 
     final List<MethodCall> log = <MethodCall>[];
@@ -45,6 +66,12 @@
         if (methodCall.method == 'getAll') {
           return testData.getAll();
         }
+        if (methodCall.method == 'getAllWithPrefix') {
+          final Map<String, Object?> arguments =
+              getArgumentDictionary(methodCall);
+          final String prefix = arguments['prefix']! as String;
+          return testData.getAllWithPrefix(prefix);
+        }
         if (methodCall.method == 'remove') {
           final Map<String, Object?> arguments =
               getArgumentDictionary(methodCall);
@@ -54,6 +81,12 @@
         if (methodCall.method == 'clear') {
           return testData.clear();
         }
+        if (methodCall.method == 'clearWithPrefix') {
+          final Map<String, Object?> arguments =
+              getArgumentDictionary(methodCall);
+          final String prefix = arguments['prefix']! as String;
+          return testData.clearWithPrefix(prefix);
+        }
         final RegExp setterRegExp = RegExp(r'set(.*)');
         final Match? match = setterRegExp.matchAsPrefix(methodCall.method);
         if (match?.groupCount == 1) {
@@ -77,14 +110,21 @@
 
     test('getAll', () async {
       store = SharedPreferencesAndroid();
-      testData = InMemorySharedPreferencesStore.withData(kTestValues);
-      expect(await store.getAll(), kTestValues);
-      expect(log.single.method, 'getAll');
+      testData = InMemorySharedPreferencesStore.withData(allTestValues);
+      expect(await store.getAll(), flutterTestValues);
+      expect(log.single.method, 'getAllWithPrefix');
+    });
+
+    test('getAllWithPrefix', () async {
+      store = SharedPreferencesAndroid();
+      testData = InMemorySharedPreferencesStore.withData(allTestValues);
+      expect(await store.getAllWithPrefix('prefix.'), prefixTestValues);
+      expect(log.single.method, 'getAllWithPrefix');
     });
 
     test('remove', () async {
       store = SharedPreferencesAndroid();
-      testData = InMemorySharedPreferencesStore.withData(kTestValues);
+      testData = InMemorySharedPreferencesStore.withData(allTestValues);
       expect(await store.remove('flutter.String'), true);
       expect(await store.remove('flutter.Bool'), true);
       expect(await store.remove('flutter.Int'), true);
@@ -102,13 +142,13 @@
     test('setValue', () async {
       store = SharedPreferencesAndroid();
       expect(await testData.getAll(), isEmpty);
-      for (final String key in kTestValues.keys) {
-        final Object value = kTestValues[key]!;
+      for (final String key in allTestValues.keys) {
+        final Object value = allTestValues[key]!;
         expect(await store.setValue(key.split('.').last, key, value), true);
       }
-      expect(await testData.getAll(), kTestValues);
+      expect(await testData.getAll(), flutterTestValues);
 
-      expect(log, hasLength(5));
+      expect(log, hasLength(15));
       expect(log[0].method, 'setString');
       expect(log[1].method, 'setBool');
       expect(log[2].method, 'setInt');
@@ -118,11 +158,36 @@
 
     test('clear', () async {
       store = SharedPreferencesAndroid();
-      testData = InMemorySharedPreferencesStore.withData(kTestValues);
+      testData = InMemorySharedPreferencesStore.withData(allTestValues);
       expect(await testData.getAll(), isNotEmpty);
       expect(await store.clear(), true);
       expect(await testData.getAll(), isEmpty);
-      expect(log.single.method, 'clear');
+      expect(log.single.method, 'clearWithPrefix');
+    });
+
+    test('clearWithPrefix', () async {
+      store = SharedPreferencesAndroid();
+      testData = InMemorySharedPreferencesStore.withData(allTestValues);
+
+      expect(await testData.getAllWithPrefix('prefix.'), isNotEmpty);
+      expect(await store.clearWithPrefix('prefix.'), true);
+      expect(await testData.getAllWithPrefix('prefix.'), isEmpty);
+    });
+
+    test('getAllWithNoPrefix', () async {
+      store = SharedPreferencesAndroid();
+      testData = InMemorySharedPreferencesStore.withData(allTestValues);
+
+      expect(await testData.getAllWithPrefix(''), hasLength(15));
+    });
+
+    test('clearWithNoPrefix', () async {
+      store = SharedPreferencesAndroid();
+      testData = InMemorySharedPreferencesStore.withData(allTestValues);
+
+      expect(await testData.getAllWithPrefix(''), isNotEmpty);
+      expect(await store.clearWithPrefix(''), true);
+      expect(await testData.getAllWithPrefix(''), isEmpty);
     });
   });
 }
diff --git a/packages/shared_preferences/shared_preferences_foundation/CHANGELOG.md b/packages/shared_preferences/shared_preferences_foundation/CHANGELOG.md
index 06d7f95..d5a6fa2 100644
--- a/packages/shared_preferences/shared_preferences_foundation/CHANGELOG.md
+++ b/packages/shared_preferences/shared_preferences_foundation/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 2.2.0
+
+* Adds `getAllWithPrefix` and `clearWithPrefix` methods.
+
 ## 2.1.5
 
 * Clarifies explanation of endorsement in README.
diff --git a/packages/shared_preferences/shared_preferences_foundation/darwin/Classes/SharedPreferencesPlugin.swift b/packages/shared_preferences/shared_preferences_foundation/darwin/Classes/SharedPreferencesPlugin.swift
index c97698c..b334f68 100644
--- a/packages/shared_preferences/shared_preferences_foundation/darwin/Classes/SharedPreferencesPlugin.swift
+++ b/packages/shared_preferences/shared_preferences_foundation/darwin/Classes/SharedPreferencesPlugin.swift
@@ -22,8 +22,8 @@
     UserDefaultsApiSetup.setUp(binaryMessenger: messenger, api: instance)
   }
 
-  func getAll() -> [String? : Any?] {
-    return getAllPrefs();
+  func getAllWithPrefix(prefix: String) -> [String? : Any?] {
+    return getAllPrefs(prefix: prefix)
   }
 
   func setBool(key: String, value: Bool) {
@@ -42,23 +42,23 @@
     UserDefaults.standard.removeObject(forKey: key)
   }
 
-  func clear() {
+  func clearWithPrefix(prefix: String) {
     let defaults = UserDefaults.standard
-    for (key, _) in getAllPrefs() {
+    for (key, _) in getAllPrefs(prefix: prefix) {
       defaults.removeObject(forKey: key)
     }
   }
-}
 
-/// Returns all preferences stored by this plugin.
-private func getAllPrefs() -> [String: Any] {
-  var filteredPrefs: [String: Any] = [:]
-  if let appDomain = Bundle.main.bundleIdentifier,
-    let prefs = UserDefaults.standard.persistentDomain(forName: appDomain)
-  {
-    for (key, value) in prefs where key.hasPrefix("flutter.") {
-      filteredPrefs[key] = value
+  /// Returns all preferences stored with specified prefix.
+  func getAllPrefs(prefix: String) -> [String: Any] {
+    var filteredPrefs: [String: Any] = [:]
+    if let appDomain = Bundle.main.bundleIdentifier,
+      let prefs = UserDefaults.standard.persistentDomain(forName: appDomain)
+    {
+      for (key, value) in prefs where key.hasPrefix(prefix) {
+        filteredPrefs[key] = value
+      }
     }
+    return filteredPrefs
   }
-  return filteredPrefs
 }
diff --git a/packages/shared_preferences/shared_preferences_foundation/darwin/Classes/messages.g.swift b/packages/shared_preferences/shared_preferences_foundation/darwin/Classes/messages.g.swift
index 933217b..57a08e8 100644
--- a/packages/shared_preferences/shared_preferences_foundation/darwin/Classes/messages.g.swift
+++ b/packages/shared_preferences/shared_preferences_foundation/darwin/Classes/messages.g.swift
@@ -1,7 +1,7 @@
 // Copyright 2013 The Flutter Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-// Autogenerated from Pigeon (v5.0.0), do not edit directly.
+// Autogenerated from Pigeon (v9.1.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 import Foundation
@@ -14,15 +14,33 @@
 #endif
 
 
-/// Generated class from Pigeon.
+
+private func wrapResult(_ result: Any?) -> [Any?] {
+  return [result]
+}
+
+private func wrapError(_ error: Any) -> [Any?] {
+  if let flutterError = error as? FlutterError {
+    return [
+      flutterError.code,
+      flutterError.message,
+      flutterError.details
+    ]
+  }
+  return [
+    "\(error)",
+    "\(type(of: error))",
+    "Stacktrace: \(Thread.callStackSymbols)"
+  ]
+}
 /// Generated protocol from Pigeon that represents a handler of messages from Flutter.
 protocol UserDefaultsApi {
-  func remove(key: String)
-  func setBool(key: String, value: Bool)
-  func setDouble(key: String, value: Double)
-  func setValue(key: String, value: Any)
-  func getAll() -> [String?: Any?]
-  func clear()
+  func remove(key: String) throws
+  func setBool(key: String, value: Bool) throws
+  func setDouble(key: String, value: Double) throws
+  func setValue(key: String, value: Any) throws
+  func getAllWithPrefix(prefix: String) throws -> [String?: Any?]
+  func clearWithPrefix(prefix: String) throws
 }
 
 /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
@@ -33,10 +51,14 @@
     let removeChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.remove", binaryMessenger: binaryMessenger)
     if let api = api {
       removeChannel.setMessageHandler { message, reply in
-        let args = message as! [Any?]
+        let args = message as! [Any]
         let keyArg = args[0] as! String
-        api.remove(key: keyArg)
-        reply(wrapResult(nil))
+        do {
+          try api.remove(key: keyArg)
+          reply(wrapResult(nil))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       removeChannel.setMessageHandler(nil)
@@ -44,11 +66,15 @@
     let setBoolChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.setBool", binaryMessenger: binaryMessenger)
     if let api = api {
       setBoolChannel.setMessageHandler { message, reply in
-        let args = message as! [Any?]
+        let args = message as! [Any]
         let keyArg = args[0] as! String
         let valueArg = args[1] as! Bool
-        api.setBool(key: keyArg, value: valueArg)
-        reply(wrapResult(nil))
+        do {
+          try api.setBool(key: keyArg, value: valueArg)
+          reply(wrapResult(nil))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       setBoolChannel.setMessageHandler(nil)
@@ -56,11 +82,15 @@
     let setDoubleChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.setDouble", binaryMessenger: binaryMessenger)
     if let api = api {
       setDoubleChannel.setMessageHandler { message, reply in
-        let args = message as! [Any?]
+        let args = message as! [Any]
         let keyArg = args[0] as! String
         let valueArg = args[1] as! Double
-        api.setDouble(key: keyArg, value: valueArg)
-        reply(wrapResult(nil))
+        do {
+          try api.setDouble(key: keyArg, value: valueArg)
+          reply(wrapResult(nil))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       setDoubleChannel.setMessageHandler(nil)
@@ -68,44 +98,48 @@
     let setValueChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.setValue", binaryMessenger: binaryMessenger)
     if let api = api {
       setValueChannel.setMessageHandler { message, reply in
-        let args = message as! [Any?]
+        let args = message as! [Any]
         let keyArg = args[0] as! String
-        let valueArg = args[1]!
-        api.setValue(key: keyArg, value: valueArg)
-        reply(wrapResult(nil))
+        let valueArg = args[1]
+        do {
+          try api.setValue(key: keyArg, value: valueArg)
+          reply(wrapResult(nil))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       setValueChannel.setMessageHandler(nil)
     }
-    let getAllChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.getAll", binaryMessenger: binaryMessenger)
+    let getAllWithPrefixChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.getAllWithPrefix", binaryMessenger: binaryMessenger)
     if let api = api {
-      getAllChannel.setMessageHandler { _, reply in
-        let result = api.getAll()
-        reply(wrapResult(result))
+      getAllWithPrefixChannel.setMessageHandler { message, reply in
+        let args = message as! [Any]
+        let prefixArg = args[0] as! String
+        do {
+          let result = try api.getAllWithPrefix(prefix: prefixArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
-      getAllChannel.setMessageHandler(nil)
+      getAllWithPrefixChannel.setMessageHandler(nil)
     }
-    let clearChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.clear", binaryMessenger: binaryMessenger)
+    let clearWithPrefixChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.clearWithPrefix", binaryMessenger: binaryMessenger)
     if let api = api {
-      clearChannel.setMessageHandler { _, reply in
-        api.clear()
-        reply(wrapResult(nil))
+      clearWithPrefixChannel.setMessageHandler { message, reply in
+        let args = message as! [Any]
+        let prefixArg = args[0] as! String
+        do {
+          try api.clearWithPrefix(prefix: prefixArg)
+          reply(wrapResult(nil))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
-      clearChannel.setMessageHandler(nil)
+      clearWithPrefixChannel.setMessageHandler(nil)
     }
   }
 }
-
-private func wrapResult(_ result: Any?) -> [Any?] {
-  return [result]
-}
-
-private func wrapError(_ error: FlutterError) -> [Any?] {
-  return [
-    error.code,
-    error.message,
-    error.details
-  ]
-}
diff --git a/packages/shared_preferences/shared_preferences_foundation/darwin/Tests/RunnerTests.swift b/packages/shared_preferences/shared_preferences_foundation/darwin/Tests/RunnerTests.swift
index a4dd4b5..c33b990 100644
--- a/packages/shared_preferences/shared_preferences_foundation/darwin/Tests/RunnerTests.swift
+++ b/packages/shared_preferences/shared_preferences_foundation/darwin/Tests/RunnerTests.swift
@@ -13,52 +13,61 @@
 @testable import shared_preferences_foundation
 
 class RunnerTests: XCTestCase {
+  let prefixes: [String] = ["aPrefix", ""]
+
   func testSetAndGet() throws {
-    let plugin = SharedPreferencesPlugin()
+    for aPrefix in prefixes {
+      let plugin = SharedPreferencesPlugin()
 
-    plugin.setBool(key: "flutter.aBool", value: true)
-    plugin.setDouble(key: "flutter.aDouble", value: 3.14)
-    plugin.setValue(key: "flutter.anInt", value: 42)
-    plugin.setValue(key: "flutter.aString", value: "hello world")
-    plugin.setValue(key: "flutter.aStringList", value: ["hello", "world"])
+      plugin.setBool(key: "\(aPrefix)aBool", value: true)
+      plugin.setDouble(key: "\(aPrefix)aDouble", value: 3.14)
+      plugin.setValue(key: "\(aPrefix)anInt", value: 42)
+      plugin.setValue(key: "\(aPrefix)aString", value: "hello world")
+      plugin.setValue(key: "\(aPrefix)aStringList", value: ["hello", "world"])
 
-    let storedValues = plugin.getAll()
-    XCTAssertEqual(storedValues["flutter.aBool"] as? Bool, true)
-    XCTAssertEqual(storedValues["flutter.aDouble"] as! Double, 3.14, accuracy: 0.0001)
-    XCTAssertEqual(storedValues["flutter.anInt"] as? Int, 42)
-    XCTAssertEqual(storedValues["flutter.aString"] as? String, "hello world")
-    XCTAssertEqual(storedValues["flutter.aStringList"] as? Array<String>, ["hello", "world"])
+      let storedValues = plugin.getAllWithPrefix(prefix: aPrefix)
+      XCTAssertEqual(storedValues["\(aPrefix)aBool"] as? Bool, true)
+      XCTAssertEqual(storedValues["\(aPrefix)aDouble"] as! Double, 3.14, accuracy: 0.0001)
+      XCTAssertEqual(storedValues["\(aPrefix)anInt"] as? Int, 42)
+      XCTAssertEqual(storedValues["\(aPrefix)aString"] as? String, "hello world")
+      XCTAssertEqual(storedValues["\(aPrefix)aStringList"] as? Array<String>, ["hello", "world"])
+    }
   }
 
   func testRemove() throws {
-    let plugin = SharedPreferencesPlugin()
-    let testKey = "flutter.foo"
-    plugin.setValue(key: testKey, value: 42)
+    for aPrefix in prefixes {
+      let plugin = SharedPreferencesPlugin()
+      let testKey = "\(aPrefix)foo"
+      plugin.setValue(key: testKey, value: 42)
 
-    // Make sure there is something to remove, so the test can't pass due to a set failure.
-    let preRemovalValues = plugin.getAll()
-    XCTAssertEqual(preRemovalValues[testKey] as? Int, 42)
+      // Make sure there is something to remove, so the test can't pass due to a set failure.
+      let preRemovalValues = plugin.getAllWithPrefix(prefix: aPrefix)
+      XCTAssertEqual(preRemovalValues[testKey] as? Int, 42)
 
-    // Then verify that removing it works.
-    plugin.remove(key: testKey)
+      // Then verify that removing it works.
+      plugin.remove(key: testKey)
 
-    let finalValues = plugin.getAll()
-    XCTAssertNil(finalValues[testKey] as Any?)
+      let finalValues = plugin.getAllWithPrefix(prefix: aPrefix)
+      XCTAssertNil(finalValues[testKey] as Any?)
+    }
   }
 
   func testClear() throws {
-    let plugin = SharedPreferencesPlugin()
-    let testKey = "flutter.foo"
-    plugin.setValue(key: testKey, value: 42)
+    for aPrefix in prefixes {
+      let plugin = SharedPreferencesPlugin()
+      let testKey = "\(aPrefix)foo"
+      plugin.setValue(key: testKey, value: 42)
 
-    // Make sure there is something to clear, so the test can't pass due to a set failure.
-    let preRemovalValues = plugin.getAll()
-    XCTAssertEqual(preRemovalValues[testKey] as? Int, 42)
+      // Make sure there is something to clear, so the test can't pass due to a set failure.
+      let preRemovalValues = plugin.getAllWithPrefix(prefix: aPrefix)
+      XCTAssertEqual(preRemovalValues[testKey] as? Int, 42)
 
-    // Then verify that clearing works.
-    plugin.clear()
+      // Then verify that clearing works.
+      plugin.clearWithPrefix(prefix: aPrefix)
 
-    let finalValues = plugin.getAll()
-    XCTAssertNil(finalValues[testKey] as Any?)
+      let finalValues = plugin.getAllWithPrefix(prefix: aPrefix)
+      XCTAssertNil(finalValues[testKey] as Any?)
+    }
   }
+  
 }
diff --git a/packages/shared_preferences/shared_preferences_foundation/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_foundation/example/integration_test/shared_preferences_test.dart
index b3c1973..7a8fb4a 100644
--- a/packages/shared_preferences/shared_preferences_foundation/example/integration_test/shared_preferences_test.dart
+++ b/packages/shared_preferences/shared_preferences_foundation/example/integration_test/shared_preferences_test.dart
@@ -10,22 +10,36 @@
   IntegrationTestWidgetsFlutterBinding.ensureInitialized();
 
   group('SharedPreferencesFoundation', () {
-    const Map<String, Object> kTestValues = <String, Object>{
+    const Map<String, Object> flutterTestValues = <String, Object>{
       'flutter.String': 'hello world',
-      'flutter.bool': true,
-      'flutter.int': 42,
-      'flutter.double': 3.14159,
-      'flutter.List': <String>['foo', 'bar'],
+      'flutter.Bool': true,
+      'flutter.Int': 42,
+      'flutter.Double': 3.14159,
+      'flutter.StringList': <String>['foo', 'bar'],
     };
 
-    const Map<String, Object> kTestValues2 = <String, Object>{
-      'flutter.String': 'goodbye world',
-      'flutter.bool': false,
-      'flutter.int': 1337,
-      'flutter.double': 2.71828,
-      'flutter.List': <String>['baz', 'quox'],
+    const Map<String, Object> prefixTestValues = <String, Object>{
+      'prefix.String': 'hello world',
+      'prefix.Bool': true,
+      'prefix.Int': 42,
+      'prefix.Double': 3.14159,
+      'prefix.StringList': <String>['foo', 'bar'],
     };
 
+    const Map<String, Object> nonPrefixTestValues = <String, Object>{
+      'String': 'hello world',
+      'Bool': true,
+      'Int': 42,
+      'Double': 3.14159,
+      'StringList': <String>['foo', 'bar'],
+    };
+
+    final Map<String, Object> allTestValues = <String, Object>{};
+
+    allTestValues.addAll(flutterTestValues);
+    allTestValues.addAll(prefixTestValues);
+    allTestValues.addAll(nonPrefixTestValues);
+
     late SharedPreferencesStorePlatform preferences;
 
     setUp(() async {
@@ -33,74 +47,220 @@
     });
 
     tearDown(() {
-      preferences.clear();
+      preferences.clearWithPrefix('');
     });
 
-    // Normally the app-facing package adds the prefix, but since this test
-    // bypasses the app-facing package it needs to be manually added.
-    String prefixedKey(String key) {
-      return 'flutter.$key';
-    }
-
     testWidgets('reading', (WidgetTester _) async {
-      final Map<String, Object> values = await preferences.getAll();
-      expect(values[prefixedKey('String')], isNull);
-      expect(values[prefixedKey('bool')], isNull);
-      expect(values[prefixedKey('int')], isNull);
-      expect(values[prefixedKey('double')], isNull);
-      expect(values[prefixedKey('List')], isNull);
+      final Map<String, Object> values = await preferences.getAllWithPrefix('');
+      expect(values['String'], isNull);
+      expect(values['Bool'], isNull);
+      expect(values['Int'], isNull);
+      expect(values['Double'], isNull);
+      expect(values['StringList'], isNull);
     });
 
-    testWidgets('writing', (WidgetTester _) async {
+    testWidgets('getAllWithPrefix', (WidgetTester _) async {
       await Future.wait(<Future<bool>>[
         preferences.setValue(
-            'String', prefixedKey('String'), kTestValues2['flutter.String']!),
+            'String', 'prefix.String', allTestValues['prefix.String']!),
         preferences.setValue(
-            'Bool', prefixedKey('bool'), kTestValues2['flutter.bool']!),
+            'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!),
+        preferences.setValue('Int', 'prefix.Int', allTestValues['prefix.Int']!),
         preferences.setValue(
-            'Int', prefixedKey('int'), kTestValues2['flutter.int']!),
+            'Double', 'prefix.Double', allTestValues['prefix.Double']!),
+        preferences.setValue('StringList', 'prefix.StringList',
+            allTestValues['prefix.StringList']!),
         preferences.setValue(
-            'Double', prefixedKey('double'), kTestValues2['flutter.double']!),
+            'String', 'flutter.String', allTestValues['flutter.String']!),
         preferences.setValue(
-            'StringList', prefixedKey('List'), kTestValues2['flutter.List']!)
+            'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
+        preferences.setValue(
+            'Int', 'flutter.Int', allTestValues['flutter.Int']!),
+        preferences.setValue(
+            'Double', 'flutter.Double', allTestValues['flutter.Double']!),
+        preferences.setValue('StringList', 'flutter.StringList',
+            allTestValues['flutter.StringList']!)
       ]);
-      final Map<String, Object> values = await preferences.getAll();
-      expect(values[prefixedKey('String')], kTestValues2['flutter.String']);
-      expect(values[prefixedKey('bool')], kTestValues2['flutter.bool']);
-      expect(values[prefixedKey('int')], kTestValues2['flutter.int']);
-      expect(values[prefixedKey('double')], kTestValues2['flutter.double']);
-      expect(values[prefixedKey('List')], kTestValues2['flutter.List']);
+      final Map<String, Object> values =
+          await preferences.getAllWithPrefix('prefix.');
+      expect(values['prefix.String'], allTestValues['prefix.String']);
+      expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
+      expect(values['prefix.Int'], allTestValues['prefix.Int']);
+      expect(values['prefix.Double'], allTestValues['prefix.Double']);
+      expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
     });
 
-    testWidgets('removing', (WidgetTester _) async {
-      final String key = prefixedKey('testKey');
-      await preferences.setValue('String', key, kTestValues['flutter.String']!);
-      await preferences.setValue('Bool', key, kTestValues['flutter.bool']!);
-      await preferences.setValue('Int', key, kTestValues['flutter.int']!);
-      await preferences.setValue('Double', key, kTestValues['flutter.double']!);
-      await preferences.setValue(
-          'StringList', key, kTestValues['flutter.List']!);
-      await preferences.remove(key);
+    testWidgets('clearWithPrefix', (WidgetTester _) async {
+      await Future.wait(<Future<bool>>[
+        preferences.setValue(
+            'String', 'prefix.String', allTestValues['prefix.String']!),
+        preferences.setValue(
+            'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!),
+        preferences.setValue('Int', 'prefix.Int', allTestValues['prefix.Int']!),
+        preferences.setValue(
+            'Double', 'prefix.Double', allTestValues['prefix.Double']!),
+        preferences.setValue('StringList', 'prefix.StringList',
+            allTestValues['prefix.StringList']!),
+        preferences.setValue(
+            'String', 'flutter.String', allTestValues['flutter.String']!),
+        preferences.setValue(
+            'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
+        preferences.setValue(
+            'Int', 'flutter.Int', allTestValues['flutter.Int']!),
+        preferences.setValue(
+            'Double', 'flutter.Double', allTestValues['flutter.Double']!),
+        preferences.setValue('StringList', 'flutter.StringList',
+            allTestValues['flutter.StringList']!)
+      ]);
+      await preferences.clearWithPrefix('prefix.');
+      Map<String, Object> values =
+          await preferences.getAllWithPrefix('prefix.');
+      expect(values['prefix.String'], null);
+      expect(values['prefix.Bool'], null);
+      expect(values['prefix.Int'], null);
+      expect(values['prefix.Double'], null);
+      expect(values['prefix.StringList'], null);
+      values = await preferences.getAllWithPrefix('flutter.');
+      expect(values['flutter.String'], allTestValues['flutter.String']);
+      expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
+      expect(values['flutter.Int'], allTestValues['flutter.Int']);
+      expect(values['flutter.Double'], allTestValues['flutter.Double']);
+      expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
+    });
+
+    testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
+      await Future.wait(<Future<bool>>[
+        preferences.setValue('String', 'String', allTestValues['String']!),
+        preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
+        preferences.setValue('Int', 'Int', allTestValues['Int']!),
+        preferences.setValue('Double', 'Double', allTestValues['Double']!),
+        preferences.setValue(
+            'StringList', 'StringList', allTestValues['StringList']!),
+        preferences.setValue(
+            'String', 'flutter.String', allTestValues['flutter.String']!),
+        preferences.setValue(
+            'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
+        preferences.setValue(
+            'Int', 'flutter.Int', allTestValues['flutter.Int']!),
+        preferences.setValue(
+            'Double', 'flutter.Double', allTestValues['flutter.Double']!),
+        preferences.setValue('StringList', 'flutter.StringList',
+            allTestValues['flutter.StringList']!)
+      ]);
+      final Map<String, Object> values = await preferences.getAllWithPrefix('');
+      expect(values['String'], allTestValues['String']);
+      expect(values['Bool'], allTestValues['Bool']);
+      expect(values['Int'], allTestValues['Int']);
+      expect(values['Double'], allTestValues['Double']);
+      expect(values['StringList'], allTestValues['StringList']);
+      expect(values['flutter.String'], allTestValues['flutter.String']);
+      expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
+      expect(values['flutter.Int'], allTestValues['flutter.Int']);
+      expect(values['flutter.Double'], allTestValues['flutter.Double']);
+      expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
+    });
+
+    testWidgets('clearWithNoPrefix', (WidgetTester _) async {
+      await Future.wait(<Future<bool>>[
+        preferences.setValue('String', 'String', allTestValues['String']!),
+        preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
+        preferences.setValue('Int', 'Int', allTestValues['Int']!),
+        preferences.setValue('Double', 'Double', allTestValues['Double']!),
+        preferences.setValue(
+            'StringList', 'StringList', allTestValues['StringList']!),
+        preferences.setValue(
+            'String', 'flutter.String', allTestValues['flutter.String']!),
+        preferences.setValue(
+            'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
+        preferences.setValue(
+            'Int', 'flutter.Int', allTestValues['flutter.Int']!),
+        preferences.setValue(
+            'Double', 'flutter.Double', allTestValues['flutter.Double']!),
+        preferences.setValue('StringList', 'flutter.StringList',
+            allTestValues['flutter.StringList']!)
+      ]);
+      await preferences.clearWithPrefix('');
+      final Map<String, Object> values = await preferences.getAllWithPrefix('');
+      expect(values['String'], null);
+      expect(values['Bool'], null);
+      expect(values['Int'], null);
+      expect(values['Double'], null);
+      expect(values['StringList'], null);
+      expect(values['flutter.String'], null);
+      expect(values['flutter.Bool'], null);
+      expect(values['flutter.Int'], null);
+      expect(values['flutter.Double'], null);
+      expect(values['flutter.StringList'], null);
+    });
+
+    testWidgets('getAll', (WidgetTester _) async {
+      await Future.wait(<Future<bool>>[
+        preferences.setValue(
+            'String', 'flutter.String', allTestValues['flutter.String']!),
+        preferences.setValue(
+            'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
+        preferences.setValue(
+            'Int', 'flutter.Int', allTestValues['flutter.Int']!),
+        preferences.setValue(
+            'Double', 'flutter.Double', allTestValues['flutter.Double']!),
+        preferences.setValue('StringList', 'flutter.StringList',
+            allTestValues['flutter.StringList']!)
+      ]);
       final Map<String, Object> values = await preferences.getAll();
+      expect(values['flutter.String'], allTestValues['flutter.String']);
+      expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
+      expect(values['flutter.Int'], allTestValues['flutter.Int']);
+      expect(values['flutter.Double'], allTestValues['flutter.Double']);
+      expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
+    });
+
+    testWidgets('remove', (WidgetTester _) async {
+      const String key = 'testKey';
+      await preferences.setValue(
+          'String', key, allTestValues['flutter.String']!);
+      await preferences.setValue('Bool', key, allTestValues['flutter.Bool']!);
+      await preferences.setValue('Int', key, allTestValues['flutter.Int']!);
+      await preferences.setValue(
+          'Double', key, allTestValues['flutter.Double']!);
+      await preferences.setValue(
+          'StringList', key, allTestValues['flutter.StringList']!);
+      await preferences.remove(key);
+      final Map<String, Object> values = await preferences.getAllWithPrefix('');
       expect(values[key], isNull);
     });
 
-    testWidgets('clearing', (WidgetTester _) async {
+    testWidgets('clear', (WidgetTester _) async {
       await preferences.setValue(
-          'String', 'String', kTestValues['flutter.String']!);
-      await preferences.setValue('Bool', 'bool', kTestValues['flutter.bool']!);
-      await preferences.setValue('Int', 'int', kTestValues['flutter.int']!);
+          'String', 'flutter.String', allTestValues['flutter.String']!);
       await preferences.setValue(
-          'Double', 'double', kTestValues['flutter.double']!);
+          'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!);
       await preferences.setValue(
-          'StringList', 'List', kTestValues['flutter.List']!);
+          'Int', 'flutter.Int', allTestValues['flutter.Int']!);
+      await preferences.setValue(
+          'Double', 'flutter.Double', allTestValues['flutter.Double']!);
+      await preferences.setValue('StringList', 'flutter.StringList',
+          allTestValues['flutter.StringList']!);
       await preferences.clear();
       final Map<String, Object> values = await preferences.getAll();
-      expect(values['String'], null);
-      expect(values['bool'], null);
-      expect(values['int'], null);
-      expect(values['double'], null);
-      expect(values['List'], null);
+      expect(values['flutter.String'], null);
+      expect(values['flutter.Bool'], null);
+      expect(values['flutter.Int'], null);
+      expect(values['flutter.Double'], null);
+      expect(values['flutter.StringList'], null);
+    });
+
+    testWidgets('simultaneous writes', (WidgetTester _) async {
+      final List<Future<bool>> writes = <Future<bool>>[];
+      const int writeCount = 100;
+      for (int i = 1; i <= writeCount; i++) {
+        writes.add(preferences.setValue('Int', 'Int', i));
+      }
+      final List<bool> result = await Future.wait(writes, eagerError: true);
+      // All writes should succeed.
+      expect(result.where((bool element) => !element), isEmpty);
+      // The last write should win.
+      final Map<String, Object> values = await preferences.getAllWithPrefix('');
+      expect(values['Int'], writeCount);
     });
   });
 }
diff --git a/packages/shared_preferences/shared_preferences_foundation/lib/messages.g.dart b/packages/shared_preferences/shared_preferences_foundation/lib/messages.g.dart
index f7c6c21..a74c34d 100644
--- a/packages/shared_preferences/shared_preferences_foundation/lib/messages.g.dart
+++ b/packages/shared_preferences/shared_preferences_foundation/lib/messages.g.dart
@@ -1,9 +1,10 @@
 // Copyright 2013 The Flutter Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-// Autogenerated from Pigeon (v5.0.0), do not edit directly.
+// Autogenerated from Pigeon (v9.1.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
+
 import 'dart:async';
 import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
 
@@ -108,11 +109,12 @@
     }
   }
 
-  Future<Map<String?, Object?>> getAll() async {
+  Future<Map<String?, Object?>> getAllWithPrefix(String arg_prefix) async {
     final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
-        'dev.flutter.pigeon.UserDefaultsApi.getAll', codec,
+        'dev.flutter.pigeon.UserDefaultsApi.getAllWithPrefix', codec,
         binaryMessenger: _binaryMessenger);
-    final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
+    final List<Object?>? replyList =
+        await channel.send(<Object?>[arg_prefix]) as List<Object?>?;
     if (replyList == null) {
       throw PlatformException(
         code: 'channel-error',
@@ -134,11 +136,12 @@
     }
   }
 
-  Future<void> clear() async {
+  Future<void> clearWithPrefix(String arg_prefix) async {
     final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
-        'dev.flutter.pigeon.UserDefaultsApi.clear', codec,
+        'dev.flutter.pigeon.UserDefaultsApi.clearWithPrefix', codec,
         binaryMessenger: _binaryMessenger);
-    final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
+    final List<Object?>? replyList =
+        await channel.send(<Object?>[arg_prefix]) as List<Object?>?;
     if (replyList == null) {
       throw PlatformException(
         code: 'channel-error',
diff --git a/packages/shared_preferences/shared_preferences_foundation/lib/shared_preferences_foundation.dart b/packages/shared_preferences/shared_preferences_foundation/lib/shared_preferences_foundation.dart
index 46b0ec4..f535ab9 100644
--- a/packages/shared_preferences/shared_preferences_foundation/lib/shared_preferences_foundation.dart
+++ b/packages/shared_preferences/shared_preferences_foundation/lib/shared_preferences_foundation.dart
@@ -11,6 +11,9 @@
 /// iOS and macOS implementation of shared_preferences.
 class SharedPreferencesFoundation extends SharedPreferencesStorePlatform {
   final UserDefaultsApi _api = UserDefaultsApi();
+
+  static const String _defautPrefix = 'flutter.';
+
   late final Map<String, _Setter> _setters = <String, _Setter>{
     'Bool': (String key, Object value) {
       return _api.setBool(key, value as bool);
@@ -37,13 +40,23 @@
 
   @override
   Future<bool> clear() async {
-    await _api.clear();
+    return clearWithPrefix(_defautPrefix);
+  }
+
+  @override
+  Future<bool> clearWithPrefix(String prefix) async {
+    await _api.clearWithPrefix(prefix);
     return true;
   }
 
   @override
   Future<Map<String, Object>> getAll() async {
-    final Map<String?, Object?> result = await _api.getAll();
+    return getAllWithPrefix(_defautPrefix);
+  }
+
+  @override
+  Future<Map<String, Object>> getAllWithPrefix(String prefix) async {
+    final Map<String?, Object?> result = await _api.getAllWithPrefix(prefix);
     return result.cast<String, Object>();
   }
 
diff --git a/packages/shared_preferences/shared_preferences_foundation/pigeons/messages.dart b/packages/shared_preferences/shared_preferences_foundation/pigeons/messages.dart
index 81848ed..e651546 100644
--- a/packages/shared_preferences/shared_preferences_foundation/pigeons/messages.dart
+++ b/packages/shared_preferences/shared_preferences_foundation/pigeons/messages.dart
@@ -20,6 +20,6 @@
   void setValue(String key, Object value);
   // TODO(stuartmorgan): Make these non-nullable once
   // https://github.com/flutter/flutter/issues/97848 is fixed.
-  Map<String?, Object?> getAll();
-  void clear();
+  Map<String?, Object?> getAllWithPrefix(String prefix);
+  void clearWithPrefix(String prefix);
 }
diff --git a/packages/shared_preferences/shared_preferences_foundation/pubspec.yaml b/packages/shared_preferences/shared_preferences_foundation/pubspec.yaml
index 74d7cfc..b6b91cc 100644
--- a/packages/shared_preferences/shared_preferences_foundation/pubspec.yaml
+++ b/packages/shared_preferences/shared_preferences_foundation/pubspec.yaml
@@ -2,7 +2,7 @@
 description: iOS and macOS implementation of the shared_preferences plugin.
 repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_foundation
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22
-version: 2.1.5
+version: 2.2.0
 
 environment:
   sdk: ">=2.17.0 <4.0.0"
@@ -24,9 +24,9 @@
 dependencies:
   flutter:
     sdk: flutter
-  shared_preferences_platform_interface: ^2.0.0
+  shared_preferences_platform_interface: ^2.2.0
 
 dev_dependencies:
   flutter_test:
     sdk: flutter
-  pigeon: ^5.0.0
+  pigeon: ^9.0.0
diff --git a/packages/shared_preferences/shared_preferences_foundation/test/shared_preferences_foundation_test.dart b/packages/shared_preferences/shared_preferences_foundation/test/shared_preferences_foundation_test.dart
index 6c0635a..5859aad 100644
--- a/packages/shared_preferences/shared_preferences_foundation/test/shared_preferences_foundation_test.dart
+++ b/packages/shared_preferences/shared_preferences_foundation/test/shared_preferences_foundation_test.dart
@@ -13,8 +13,11 @@
   final Map<String, Object> items = <String, Object>{};
 
   @override
-  Map<String?, Object?> getAll() {
-    return items;
+  Map<String?, Object?> getAllWithPrefix(String prefix) {
+    return <String?, Object?>{
+      for (final String key in items.keys)
+        if (key.startsWith(prefix)) key: items[key]
+    };
   }
 
   @override
@@ -38,8 +41,12 @@
   }
 
   @override
-  void clear() {
-    items.clear();
+  void clearWithPrefix(String prefix) {
+    items.keys.toList().forEach((String key) {
+      if (key.startsWith(prefix)) {
+        items.remove(key);
+      }
+    });
   }
 }
 
@@ -47,6 +54,36 @@
   TestWidgetsFlutterBinding.ensureInitialized();
   late _MockSharedPreferencesApi api;
 
+  const Map<String, Object> flutterTestValues = <String, Object>{
+    'flutter.String': 'hello world',
+    'flutter.Bool': true,
+    'flutter.Int': 42,
+    'flutter.Double': 3.14159,
+    'flutter.StringList': <String>['foo', 'bar'],
+  };
+
+  const Map<String, Object> prefixTestValues = <String, Object>{
+    'prefix.String': 'hello world',
+    'prefix.Bool': true,
+    'prefix.Int': 42,
+    'prefix.Double': 3.14159,
+    'prefix.StringList': <String>['foo', 'bar'],
+  };
+
+  const Map<String, Object> nonPrefixTestValues = <String, Object>{
+    'String': 'hello world',
+    'Bool': true,
+    'Int': 42,
+    'Double': 3.14159,
+    'StringList': <String>['foo', 'bar'],
+  };
+
+  final Map<String, Object> allTestValues = <String, Object>{};
+
+  allTestValues.addAll(flutterTestValues);
+  allTestValues.addAll(prefixTestValues);
+  allTestValues.addAll(nonPrefixTestValues);
+
   setUp(() {
     api = _MockSharedPreferencesApi();
     TestUserDefaultsApi.setup(api);
@@ -72,21 +109,39 @@
     expect(api.items.containsKey('flutter.hi'), isFalse);
   });
 
+  test('clearWithPrefix', () async {
+    final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
+    for (final String key in allTestValues.keys) {
+      api.items[key] = allTestValues[key]!;
+    }
+
+    Map<String?, Object?> all = await plugin.getAllWithPrefix('prefix.');
+    expect(all.length, 5);
+    await plugin.clearWithPrefix('prefix.');
+    all = await plugin.getAll();
+    expect(all.length, 5);
+    all = await plugin.getAllWithPrefix('prefix.');
+    expect(all.length, 0);
+  });
+
   test('getAll', () async {
     final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
-    api.items['flutter.aBool'] = true;
-    api.items['flutter.aDouble'] = 3.14;
-    api.items['flutter.anInt'] = 42;
-    api.items['flutter.aString'] = 'hello world';
-    api.items['flutter.aStringList'] = <String>['hello', 'world'];
+    for (final String key in flutterTestValues.keys) {
+      api.items[key] = flutterTestValues[key]!;
+    }
     final Map<String?, Object?> all = await plugin.getAll();
     expect(all.length, 5);
-    expect(all['flutter.aBool'], api.items['flutter.aBool']);
-    expect(all['flutter.aDouble'],
-        closeTo(api.items['flutter.aDouble']! as num, 0.0001));
-    expect(all['flutter.anInt'], api.items['flutter.anInt']);
-    expect(all['flutter.aString'], api.items['flutter.aString']);
-    expect(all['flutter.aStringList'], api.items['flutter.aStringList']);
+    expect(all, flutterTestValues);
+  });
+
+  test('getAllWithPrefix', () async {
+    final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
+    for (final String key in allTestValues.keys) {
+      api.items[key] = allTestValues[key]!;
+    }
+    final Map<String?, Object?> all = await plugin.getAllWithPrefix('prefix.');
+    expect(all.length, 5);
+    expect(all, prefixTestValues);
   });
 
   test('setValue', () async {
@@ -112,4 +167,27 @@
       await plugin.setValue('Map', 'flutter.key', <String, String>{});
     }, throwsA(isA<PlatformException>()));
   });
+
+  test('getAllWithNoPrefix', () async {
+    final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
+    for (final String key in allTestValues.keys) {
+      api.items[key] = allTestValues[key]!;
+    }
+    final Map<String?, Object?> all = await plugin.getAllWithPrefix('');
+    expect(all.length, 15);
+    expect(all, allTestValues);
+  });
+
+  test('clearWithNoPrefix', () async {
+    final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
+    for (final String key in allTestValues.keys) {
+      api.items[key] = allTestValues[key]!;
+    }
+
+    Map<String?, Object?> all = await plugin.getAllWithPrefix('');
+    expect(all.length, 15);
+    await plugin.clearWithPrefix('');
+    all = await plugin.getAllWithPrefix('');
+    expect(all.length, 0);
+  });
 }
diff --git a/packages/shared_preferences/shared_preferences_foundation/test/test_api.g.dart b/packages/shared_preferences/shared_preferences_foundation/test/test_api.g.dart
index 12f97bd..bbc0d2a 100644
--- a/packages/shared_preferences/shared_preferences_foundation/test/test_api.g.dart
+++ b/packages/shared_preferences/shared_preferences_foundation/test/test_api.g.dart
@@ -1,7 +1,7 @@
 // Copyright 2013 The Flutter Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-// Autogenerated from Pigeon (v5.0.0), do not edit directly.
+// Autogenerated from Pigeon (v9.1.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import
 // ignore_for_file: avoid_relative_lib_imports
@@ -24,9 +24,9 @@
 
   void setValue(String key, Object value);
 
-  Map<String?, Object?> getAll();
+  Map<String?, Object?> getAllWithPrefix(String prefix);
 
-  void clear();
+  void clearWithPrefix(String prefix);
 
   static void setup(TestUserDefaultsApi? api,
       {BinaryMessenger? binaryMessenger}) {
@@ -117,28 +117,39 @@
     }
     {
       final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
-          'dev.flutter.pigeon.UserDefaultsApi.getAll', codec,
+          'dev.flutter.pigeon.UserDefaultsApi.getAllWithPrefix', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
         channel.setMockMessageHandler(null);
       } else {
         channel.setMockMessageHandler((Object? message) async {
-          // ignore message
-          final Map<String?, Object?> output = api.getAll();
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.UserDefaultsApi.getAllWithPrefix was null.');
+          final List<Object?> args = (message as List<Object?>?)!;
+          final String? arg_prefix = (args[0] as String?);
+          assert(arg_prefix != null,
+              'Argument for dev.flutter.pigeon.UserDefaultsApi.getAllWithPrefix was null, expected non-null String.');
+          final Map<String?, Object?> output =
+              api.getAllWithPrefix(arg_prefix!);
           return <Object?>[output];
         });
       }
     }
     {
       final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
-          'dev.flutter.pigeon.UserDefaultsApi.clear', codec,
+          'dev.flutter.pigeon.UserDefaultsApi.clearWithPrefix', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
         channel.setMockMessageHandler(null);
       } else {
         channel.setMockMessageHandler((Object? message) async {
-          // ignore message
-          api.clear();
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.UserDefaultsApi.clearWithPrefix was null.');
+          final List<Object?> args = (message as List<Object?>?)!;
+          final String? arg_prefix = (args[0] as String?);
+          assert(arg_prefix != null,
+              'Argument for dev.flutter.pigeon.UserDefaultsApi.clearWithPrefix was null, expected non-null String.');
+          api.clearWithPrefix(arg_prefix!);
           return <Object?>[];
         });
       }
diff --git a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md
index d3736fa..4ba0cec 100644
--- a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md
+++ b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 2.2.0
+
+* Adds `getAllWithPrefix` and `clearWithPrefix` methods.
+
 ## 2.1.5
 
 * Clarifies explanation of endorsement in README.
diff --git a/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart
index 664048a..8939d0a 100644
--- a/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart
+++ b/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart
@@ -38,34 +38,36 @@
 
     testWidgets('reading', (WidgetTester _) async {
       final Map<String, Object> all = await preferences.getAll();
-      expect(all['String'], isNull);
-      expect(all['bool'], isNull);
-      expect(all['int'], isNull);
-      expect(all['double'], isNull);
-      expect(all['List'], isNull);
+      expect(all['flutter.String'], isNull);
+      expect(all['flutter.bool'], isNull);
+      expect(all['flutter.int'], isNull);
+      expect(all['flutter.double'], isNull);
+      expect(all['flutter.List'], isNull);
     });
 
     testWidgets('writing', (WidgetTester _) async {
       await Future.wait(<Future<bool>>[
         preferences.setValue(
-            'String', 'String', kTestValues2['flutter.String']!),
-        preferences.setValue('Bool', 'bool', kTestValues2['flutter.bool']!),
-        preferences.setValue('Int', 'int', kTestValues2['flutter.int']!),
+            'String', 'flutter.String', kTestValues2['flutter.String']!),
         preferences.setValue(
-            'Double', 'double', kTestValues2['flutter.double']!),
+            'Bool', 'flutter.bool', kTestValues2['flutter.bool']!),
         preferences.setValue(
-            'StringList', 'List', kTestValues2['flutter.List']!)
+            'Int', 'flutter.int', kTestValues2['flutter.int']!),
+        preferences.setValue(
+            'Double', 'flutter.double', kTestValues2['flutter.double']!),
+        preferences.setValue(
+            'StringList', 'flutter.List', kTestValues2['flutter.List']!)
       ]);
       final Map<String, Object> all = await preferences.getAll();
-      expect(all['String'], kTestValues2['flutter.String']);
-      expect(all['bool'], kTestValues2['flutter.bool']);
-      expect(all['int'], kTestValues2['flutter.int']);
-      expect(all['double'], kTestValues2['flutter.double']);
-      expect(all['List'], kTestValues2['flutter.List']);
+      expect(all['flutter.String'], kTestValues2['flutter.String']);
+      expect(all['flutter.bool'], kTestValues2['flutter.bool']);
+      expect(all['flutter.int'], kTestValues2['flutter.int']);
+      expect(all['flutter.double'], kTestValues2['flutter.double']);
+      expect(all['flutter.List'], kTestValues2['flutter.List']);
     });
 
     testWidgets('removing', (WidgetTester _) async {
-      const String key = 'testKey';
+      const String key = 'flutter.testKey';
 
       await Future.wait(<Future<bool>>[
         preferences.setValue('String', key, kTestValues['flutter.String']!),
@@ -76,26 +78,28 @@
       ]);
       await preferences.remove(key);
       final Map<String, Object> all = await preferences.getAll();
-      expect(all['testKey'], isNull);
+      expect(all[key], isNull);
     });
 
     testWidgets('clearing', (WidgetTester _) async {
       await Future.wait(<Future<bool>>[
         preferences.setValue(
-            'String', 'String', kTestValues['flutter.String']!),
-        preferences.setValue('Bool', 'bool', kTestValues['flutter.bool']!),
-        preferences.setValue('Int', 'int', kTestValues['flutter.int']!),
+            'String', 'flutter.String', kTestValues['flutter.String']!),
         preferences.setValue(
-            'Double', 'double', kTestValues['flutter.double']!),
-        preferences.setValue('StringList', 'List', kTestValues['flutter.List']!)
+            'Bool', 'flutter.bool', kTestValues['flutter.bool']!),
+        preferences.setValue('Int', 'flutter.int', kTestValues['flutter.int']!),
+        preferences.setValue(
+            'Double', 'flutter.double', kTestValues['flutter.double']!),
+        preferences.setValue(
+            'StringList', 'flutter.List', kTestValues['flutter.List']!)
       ]);
       await preferences.clear();
       final Map<String, Object> all = await preferences.getAll();
-      expect(all['String'], null);
-      expect(all['bool'], null);
-      expect(all['int'], null);
-      expect(all['double'], null);
-      expect(all['List'], null);
+      expect(all['flutter.String'], null);
+      expect(all['flutter.bool'], null);
+      expect(all['flutter.int'], null);
+      expect(all['flutter.double'], null);
+      expect(all['flutter.List'], null);
     });
   });
 }
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
index 1cc1c41..738ccdc 100644
--- a/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart
+++ b/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart
@@ -21,6 +21,8 @@
   @Deprecated('Use `SharedPreferencesStorePlatform.instance` instead.')
   static SharedPreferencesLinux instance = SharedPreferencesLinux();
 
+  static const String _defaultPrefix = 'flutter.';
+
   /// Registers the Linux implementation.
   static void registerWith() {
     SharedPreferencesStorePlatform.instance = SharedPreferencesLinux();
@@ -46,13 +48,8 @@
     return fs.file(path.join(directory, 'shared_preferences.json'));
   }
 
-  /// 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!;
-    }
-
+  /// Gets the preferences from the stored file and saves them in cache.
+  Future<Map<String, Object>> _reload() async {
     Map<String, Object> preferences = <String, Object>{};
     final File? localDataFile = await _getLocalDataFile();
     if (localDataFile != null && localDataFile.existsSync()) {
@@ -68,6 +65,12 @@
     return preferences;
   }
 
+  /// Checks for cached preferences and returns them or loads preferences from
+  /// file and returns and caches them.
+  Future<Map<String, Object>> _readPreferences() async {
+    return _cachedPreferences ?? await _reload();
+  }
+
   /// Writes the cached preferences to disk. Returns [true] if the operation
   /// succeeded.
   Future<bool> _writePreferences(Map<String, Object> preferences) async {
@@ -91,14 +94,27 @@
 
   @override
   Future<bool> clear() async {
+    return clearWithPrefix(_defaultPrefix);
+  }
+
+  @override
+  Future<bool> clearWithPrefix(String prefix) async {
     final Map<String, Object> preferences = await _readPreferences();
-    preferences.clear();
+    preferences.removeWhere((String key, _) => key.startsWith(prefix));
     return _writePreferences(preferences);
   }
 
   @override
   Future<Map<String, Object>> getAll() async {
-    return _readPreferences();
+    return getAllWithPrefix(_defaultPrefix);
+  }
+
+  @override
+  Future<Map<String, Object>> getAllWithPrefix(String prefix) async {
+    final Map<String, Object> withPrefix =
+        Map<String, Object>.from(await _readPreferences());
+    withPrefix.removeWhere((String key, _) => !key.startsWith(prefix));
+    return withPrefix;
   }
 
   @override
diff --git a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml
index 08fc024..ff3f6d2 100644
--- a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml
+++ b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml
@@ -2,7 +2,7 @@
 description: Linux implementation of the shared_preferences plugin
 repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_linux
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22
-version: 2.1.5
+version: 2.2.0
 
 environment:
   sdk: ">=2.17.0 <4.0.0"
@@ -22,7 +22,7 @@
   path: ^1.8.0
   path_provider_linux: ^2.0.0
   path_provider_platform_interface: ^2.0.0
-  shared_preferences_platform_interface: ^2.0.0
+  shared_preferences_platform_interface: ^2.2.0
 
 dev_dependencies:
   flutter_test:
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
index 176d1d9..a4f2854 100644
--- 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
@@ -1,6 +1,8 @@
 // Copyright 2013 The Flutter 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:convert';
+
 import 'package:file/memory.dart';
 import 'package:flutter_test/flutter_test.dart';
 import 'package:path/path.dart' as path;
@@ -15,6 +17,36 @@
 
   SharedPreferencesLinux.registerWith();
 
+  const Map<String, Object> flutterTestValues = <String, Object>{
+    'flutter.String': 'hello world',
+    'flutter.Bool': true,
+    'flutter.Int': 42,
+    'flutter.Double': 3.14159,
+    'flutter.StringList': <String>['foo', 'bar'],
+  };
+
+  const Map<String, Object> prefixTestValues = <String, Object>{
+    'prefix.String': 'hello world',
+    'prefix.Bool': true,
+    'prefix.Int': 42,
+    'prefix.Double': 3.14159,
+    'prefix.StringList': <String>['foo', 'bar'],
+  };
+
+  const Map<String, Object> nonPrefixTestValues = <String, Object>{
+    'String': 'hello world',
+    'Bool': true,
+    'Int': 42,
+    'Double': 3.14159,
+    'StringList': <String>['foo', 'bar'],
+  };
+
+  final Map<String, Object> allTestValues = <String, Object>{};
+
+  allTestValues.addAll(flutterTestValues);
+  allTestValues.addAll(prefixTestValues);
+  allTestValues.addAll(nonPrefixTestValues);
+
   setUp(() {
     fs = MemoryFileSystem.test();
     pathProvider = FakePathProviderLinux();
@@ -49,13 +81,21 @@
   });
 
   test('getAll', () async {
-    await writeTestFile('{"key1": "one", "key2": 2}');
+    await writeTestFile(json.encode(allTestValues));
     final SharedPreferencesLinux prefs = getPreferences();
 
     final Map<String, Object> values = await prefs.getAll();
-    expect(values, hasLength(2));
-    expect(values['key1'], 'one');
-    expect(values['key2'], 2);
+    expect(values, hasLength(5));
+    expect(values, flutterTestValues);
+  });
+
+  test('getAllWithPrefix', () async {
+    await writeTestFile(json.encode(allTestValues));
+    final SharedPreferencesLinux prefs = getPreferences();
+
+    final Map<String, Object> values = await prefs.getAllWithPrefix('prefix.');
+    expect(values, hasLength(5));
+    expect(values, prefixTestValues);
   });
 
   test('remove', () async {
@@ -78,12 +118,43 @@
   });
 
   test('clear', () async {
-    await writeTestFile('{"key1":"one","key2":2}');
+    await writeTestFile(json.encode(flutterTestValues));
     final SharedPreferencesLinux prefs = getPreferences();
 
+    expect(await readTestFile(), json.encode(flutterTestValues));
     await prefs.clear();
     expect(await readTestFile(), '{}');
   });
+
+  test('clearWithPrefix', () async {
+    await writeTestFile(json.encode(flutterTestValues));
+    final SharedPreferencesLinux prefs = getPreferences();
+    await prefs.clearWithPrefix('prefix.');
+    final Map<String, Object> noValues =
+        await prefs.getAllWithPrefix('prefix.');
+    expect(noValues, hasLength(0));
+
+    final Map<String, Object> values = await prefs.getAll();
+    expect(values, hasLength(5));
+    expect(values, flutterTestValues);
+  });
+
+  test('getAllWithNoPrefix', () async {
+    await writeTestFile(json.encode(allTestValues));
+    final SharedPreferencesLinux prefs = getPreferences();
+
+    final Map<String, Object> values = await prefs.getAllWithPrefix('');
+    expect(values, hasLength(15));
+    expect(values, allTestValues);
+  });
+
+  test('clearWithNoPrefix', () async {
+    await writeTestFile(json.encode(flutterTestValues));
+    final SharedPreferencesLinux prefs = getPreferences();
+    await prefs.clearWithPrefix('');
+    final Map<String, Object> noValues = await prefs.getAllWithPrefix('');
+    expect(noValues, hasLength(0));
+  });
 }
 
 /// Fake implementation of PathProviderLinux that returns hard-coded paths,
diff --git a/packages/shared_preferences/shared_preferences_web/CHANGELOG.md b/packages/shared_preferences/shared_preferences_web/CHANGELOG.md
index 1f1d2dc..b5efabc 100644
--- a/packages/shared_preferences/shared_preferences_web/CHANGELOG.md
+++ b/packages/shared_preferences/shared_preferences_web/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 2.1.0
+
+* Adds `getAllWithPrefix` and `clearWithPrefix` methods.
+
 ## 2.0.6
 
 * Clarifies explanation of endorsement in README.
diff --git a/packages/shared_preferences/shared_preferences_web/example/integration_test/shared_preferences_web_test.dart b/packages/shared_preferences/shared_preferences_web/example/integration_test/shared_preferences_web_test.dart
index d3bfa49..ccc01df 100644
--- a/packages/shared_preferences/shared_preferences_web/example/integration_test/shared_preferences_web_test.dart
+++ b/packages/shared_preferences/shared_preferences_web/example/integration_test/shared_preferences_web_test.dart
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:convert' show json;
 import 'dart:html' as html;
 
 import 'package:flutter_test/flutter_test.dart';
@@ -37,57 +36,257 @@
           isA<SharedPreferencesPlugin>());
     });
 
-    testWidgets('getAll', (WidgetTester tester) async {
-      final SharedPreferencesPlugin store = SharedPreferencesPlugin();
-      expect(await store.getAll(), isEmpty);
+    const Map<String, Object> flutterTestValues = <String, Object>{
+      'flutter.String': 'hello world',
+      'flutter.Bool': true,
+      'flutter.Int': 42,
+      'flutter.Double': 3.14159,
+      'flutter.StringList': <String>['foo', 'bar'],
+    };
 
-      html.window.localStorage['flutter.testKey'] = '"test value"';
-      html.window.localStorage['unprefixed_key'] = 'not a flutter value';
-      final Map<String, Object> allData = await store.getAll();
-      expect(allData, hasLength(1));
-      expect(allData['flutter.testKey'], 'test value');
+    const Map<String, Object> prefixTestValues = <String, Object>{
+      'prefix.String': 'hello world',
+      'prefix.Bool': true,
+      'prefix.Int': 42,
+      'prefix.Double': 3.14159,
+      'prefix.StringList': <String>['foo', 'bar'],
+    };
+
+    const Map<String, Object> nonPrefixTestValues = <String, Object>{
+      'String': 'hello world',
+      'Bool': true,
+      'Int': 42,
+      'Double': 3.14159,
+      'StringList': <String>['foo', 'bar'],
+    };
+
+    final Map<String, Object> allTestValues = <String, Object>{};
+
+    allTestValues.addAll(flutterTestValues);
+    allTestValues.addAll(prefixTestValues);
+    allTestValues.addAll(nonPrefixTestValues);
+
+    late SharedPreferencesStorePlatform preferences;
+
+    setUp(() async {
+      preferences = SharedPreferencesStorePlatform.instance;
     });
 
-    testWidgets('remove', (WidgetTester tester) async {
-      final SharedPreferencesPlugin store = SharedPreferencesPlugin();
-      html.window.localStorage['flutter.testKey'] = '"test value"';
-      expect(html.window.localStorage['flutter.testKey'], isNotNull);
-      expect(await store.remove('flutter.testKey'), isTrue);
-      expect(html.window.localStorage['flutter.testKey'], isNull);
-      expect(
-        () => store.remove('unprefixed'),
-        throwsA(isA<FormatException>()),
-      );
+    tearDown(() {
+      preferences.clearWithPrefix('');
     });
 
-    testWidgets('setValue', (WidgetTester tester) async {
-      final SharedPreferencesPlugin store = SharedPreferencesPlugin();
-      for (final String key in kTestValues.keys) {
-        final dynamic value = kTestValues[key];
-        expect(await store.setValue(key.split('.').last, key, value), true);
+    testWidgets('reading', (WidgetTester _) async {
+      final Map<String, Object> values = await preferences.getAllWithPrefix('');
+      expect(values['String'], isNull);
+      expect(values['Bool'], isNull);
+      expect(values['Int'], isNull);
+      expect(values['Double'], isNull);
+      expect(values['StringList'], isNull);
+    });
+
+    testWidgets('getAllWithPrefix', (WidgetTester _) async {
+      await Future.wait(<Future<bool>>[
+        preferences.setValue(
+            'String', 'prefix.String', allTestValues['prefix.String']!),
+        preferences.setValue(
+            'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!),
+        preferences.setValue('Int', 'prefix.Int', allTestValues['prefix.Int']!),
+        preferences.setValue(
+            'Double', 'prefix.Double', allTestValues['prefix.Double']!),
+        preferences.setValue('StringList', 'prefix.StringList',
+            allTestValues['prefix.StringList']!),
+        preferences.setValue(
+            'String', 'flutter.String', allTestValues['flutter.String']!),
+        preferences.setValue(
+            'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
+        preferences.setValue(
+            'Int', 'flutter.Int', allTestValues['flutter.Int']!),
+        preferences.setValue(
+            'Double', 'flutter.Double', allTestValues['flutter.Double']!),
+        preferences.setValue('StringList', 'flutter.StringList',
+            allTestValues['flutter.StringList']!)
+      ]);
+      final Map<String, Object> values =
+          await preferences.getAllWithPrefix('prefix.');
+      expect(values['prefix.String'], allTestValues['prefix.String']);
+      expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
+      expect(values['prefix.Int'], allTestValues['prefix.Int']);
+      expect(values['prefix.Double'], allTestValues['prefix.Double']);
+      expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
+    });
+
+    testWidgets('clearWithPrefix', (WidgetTester _) async {
+      await Future.wait(<Future<bool>>[
+        preferences.setValue(
+            'String', 'prefix.String', allTestValues['prefix.String']!),
+        preferences.setValue(
+            'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!),
+        preferences.setValue('Int', 'prefix.Int', allTestValues['prefix.Int']!),
+        preferences.setValue(
+            'Double', 'prefix.Double', allTestValues['prefix.Double']!),
+        preferences.setValue('StringList', 'prefix.StringList',
+            allTestValues['prefix.StringList']!),
+        preferences.setValue(
+            'String', 'flutter.String', allTestValues['flutter.String']!),
+        preferences.setValue(
+            'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
+        preferences.setValue(
+            'Int', 'flutter.Int', allTestValues['flutter.Int']!),
+        preferences.setValue(
+            'Double', 'flutter.Double', allTestValues['flutter.Double']!),
+        preferences.setValue('StringList', 'flutter.StringList',
+            allTestValues['flutter.StringList']!)
+      ]);
+      await preferences.clearWithPrefix('prefix.');
+      Map<String, Object> values =
+          await preferences.getAllWithPrefix('prefix.');
+      expect(values['prefix.String'], null);
+      expect(values['prefix.Bool'], null);
+      expect(values['prefix.Int'], null);
+      expect(values['prefix.Double'], null);
+      expect(values['prefix.StringList'], null);
+      values = await preferences.getAllWithPrefix('flutter.');
+      expect(values['flutter.String'], allTestValues['flutter.String']);
+      expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
+      expect(values['flutter.Int'], allTestValues['flutter.Int']);
+      expect(values['flutter.Double'], allTestValues['flutter.Double']);
+      expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
+    });
+
+    testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
+      await Future.wait(<Future<bool>>[
+        preferences.setValue('String', 'String', allTestValues['String']!),
+        preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
+        preferences.setValue('Int', 'Int', allTestValues['Int']!),
+        preferences.setValue('Double', 'Double', allTestValues['Double']!),
+        preferences.setValue(
+            'StringList', 'StringList', allTestValues['StringList']!),
+        preferences.setValue(
+            'String', 'flutter.String', allTestValues['flutter.String']!),
+        preferences.setValue(
+            'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
+        preferences.setValue(
+            'Int', 'flutter.Int', allTestValues['flutter.Int']!),
+        preferences.setValue(
+            'Double', 'flutter.Double', allTestValues['flutter.Double']!),
+        preferences.setValue('StringList', 'flutter.StringList',
+            allTestValues['flutter.StringList']!)
+      ]);
+      final Map<String, Object> values = await preferences.getAllWithPrefix('');
+      expect(values['String'], allTestValues['String']);
+      expect(values['Bool'], allTestValues['Bool']);
+      expect(values['Int'], allTestValues['Int']);
+      expect(values['Double'], allTestValues['Double']);
+      expect(values['StringList'], allTestValues['StringList']);
+      expect(values['flutter.String'], allTestValues['flutter.String']);
+      expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
+      expect(values['flutter.Int'], allTestValues['flutter.Int']);
+      expect(values['flutter.Double'], allTestValues['flutter.Double']);
+      expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
+    });
+
+    testWidgets('clearWithNoPrefix', (WidgetTester _) async {
+      await Future.wait(<Future<bool>>[
+        preferences.setValue('String', 'String', allTestValues['String']!),
+        preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
+        preferences.setValue('Int', 'Int', allTestValues['Int']!),
+        preferences.setValue('Double', 'Double', allTestValues['Double']!),
+        preferences.setValue(
+            'StringList', 'StringList', allTestValues['StringList']!),
+        preferences.setValue(
+            'String', 'flutter.String', allTestValues['flutter.String']!),
+        preferences.setValue(
+            'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
+        preferences.setValue(
+            'Int', 'flutter.Int', allTestValues['flutter.Int']!),
+        preferences.setValue(
+            'Double', 'flutter.Double', allTestValues['flutter.Double']!),
+        preferences.setValue('StringList', 'flutter.StringList',
+            allTestValues['flutter.StringList']!)
+      ]);
+      await preferences.clearWithPrefix('');
+      final Map<String, Object> values = await preferences.getAllWithPrefix('');
+      expect(values['String'], null);
+      expect(values['Bool'], null);
+      expect(values['Int'], null);
+      expect(values['Double'], null);
+      expect(values['StringList'], null);
+      expect(values['flutter.String'], null);
+      expect(values['flutter.Bool'], null);
+      expect(values['flutter.Int'], null);
+      expect(values['flutter.Double'], null);
+      expect(values['flutter.StringList'], null);
+    });
+
+    testWidgets('getAll', (WidgetTester _) async {
+      await Future.wait(<Future<bool>>[
+        preferences.setValue(
+            'String', 'flutter.String', allTestValues['flutter.String']!),
+        preferences.setValue(
+            'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
+        preferences.setValue(
+            'Int', 'flutter.Int', allTestValues['flutter.Int']!),
+        preferences.setValue(
+            'Double', 'flutter.Double', allTestValues['flutter.Double']!),
+        preferences.setValue('StringList', 'flutter.StringList',
+            allTestValues['flutter.StringList']!)
+      ]);
+      final Map<String, Object> values = await preferences.getAll();
+      expect(values['flutter.String'], allTestValues['flutter.String']);
+      expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
+      expect(values['flutter.Int'], allTestValues['flutter.Int']);
+      expect(values['flutter.Double'], allTestValues['flutter.Double']);
+      expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
+    });
+
+    testWidgets('remove', (WidgetTester _) async {
+      const String key = 'testKey';
+      await preferences.setValue(
+          'String', key, allTestValues['flutter.String']!);
+      await preferences.setValue('Bool', key, allTestValues['flutter.Bool']!);
+      await preferences.setValue('Int', key, allTestValues['flutter.Int']!);
+      await preferences.setValue(
+          'Double', key, allTestValues['flutter.Double']!);
+      await preferences.setValue(
+          'StringList', key, allTestValues['flutter.StringList']!);
+      await preferences.remove(key);
+      final Map<String, Object> values = await preferences.getAllWithPrefix('');
+      expect(values[key], isNull);
+    });
+
+    testWidgets('clear', (WidgetTester _) async {
+      await preferences.setValue(
+          'String', 'flutter.String', allTestValues['flutter.String']!);
+      await preferences.setValue(
+          'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!);
+      await preferences.setValue(
+          'Int', 'flutter.Int', allTestValues['flutter.Int']!);
+      await preferences.setValue(
+          'Double', 'flutter.Double', allTestValues['flutter.Double']!);
+      await preferences.setValue('StringList', 'flutter.StringList',
+          allTestValues['flutter.StringList']!);
+      await preferences.clear();
+      final Map<String, Object> values = await preferences.getAll();
+      expect(values['flutter.String'], null);
+      expect(values['flutter.Bool'], null);
+      expect(values['flutter.Int'], null);
+      expect(values['flutter.Double'], null);
+      expect(values['flutter.StringList'], null);
+    });
+
+    testWidgets('simultaneous writes', (WidgetTester _) async {
+      final List<Future<bool>> writes = <Future<bool>>[];
+      const int writeCount = 100;
+      for (int i = 1; i <= writeCount; i++) {
+        writes.add(preferences.setValue('Int', 'Int', i));
       }
-      expect(html.window.localStorage.keys, hasLength(kTestValues.length));
-      for (final String key in html.window.localStorage.keys) {
-        expect(html.window.localStorage[key], json.encode(kTestValues[key]));
-      }
-
-      // Check that generics are preserved.
-      expect((await store.getAll())['flutter.StringList'], isA<List<String>>());
-
-      // Invalid key format.
-      expect(
-        () => store.setValue('String', 'unprefixed', 'hello'),
-        throwsA(isA<FormatException>()),
-      );
-    });
-
-    testWidgets('clear', (WidgetTester tester) async {
-      final SharedPreferencesPlugin store = SharedPreferencesPlugin();
-      html.window.localStorage['flutter.testKey1'] = '"test value"';
-      html.window.localStorage['flutter.testKey2'] = '42';
-      html.window.localStorage['unprefixed_key'] = 'not a flutter value';
-      expect(await store.clear(), isTrue);
-      expect(html.window.localStorage.keys.single, 'unprefixed_key');
+      final List<bool> result = await Future.wait(writes, eagerError: true);
+      // All writes should succeed.
+      expect(result.where((bool element) => !element), isEmpty);
+      // The last write should win.
+      final Map<String, Object> values = await preferences.getAllWithPrefix('');
+      expect(values['Int'], writeCount);
     });
   });
 }
diff --git a/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart b/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart
index d9d6234..6ee692e 100644
--- a/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart
+++ b/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart
@@ -18,19 +18,31 @@
     SharedPreferencesStorePlatform.instance = SharedPreferencesPlugin();
   }
 
+  static const String _defaultPrefix = 'flutter.';
+
   @override
   Future<bool> clear() async {
+    return clearWithPrefix(_defaultPrefix);
+  }
+
+  @override
+  Future<bool> clearWithPrefix(String prefix) async {
     // IMPORTANT: Do not use html.window.localStorage.clear() as that will
     //            remove _all_ local data, not just the keys prefixed with
-    //            "flutter."
-    _storedFlutterKeys.forEach(html.window.localStorage.remove);
+    //            _prefix
+    _getStoredFlutterKeys(prefix).forEach(html.window.localStorage.remove);
     return true;
   }
 
   @override
   Future<Map<String, Object>> getAll() async {
+    return getAllWithPrefix(_defaultPrefix);
+  }
+
+  @override
+  Future<Map<String, Object>> getAllWithPrefix(String prefix) async {
     final Map<String, Object> allData = <String, Object>{};
-    for (final String key in _storedFlutterKeys) {
+    for (final String key in _getStoredFlutterKeys(prefix)) {
       allData[key] = _decodeValue(html.window.localStorage[key]!);
     }
     return allData;
@@ -38,31 +50,19 @@
 
   @override
   Future<bool> remove(String key) async {
-    _checkPrefix(key);
     html.window.localStorage.remove(key);
     return true;
   }
 
   @override
   Future<bool> setValue(String valueType, String key, Object? value) async {
-    _checkPrefix(key);
     html.window.localStorage[key] = _encodeValue(value);
     return true;
   }
 
-  void _checkPrefix(String key) {
-    if (!key.startsWith('flutter.')) {
-      throw FormatException(
-        'Shared preferences keys must start with prefix "flutter.".',
-        key,
-        0,
-      );
-    }
-  }
-
-  Iterable<String> get _storedFlutterKeys {
+  Iterable<String> _getStoredFlutterKeys(String prefix) {
     return html.window.localStorage.keys
-        .where((String key) => key.startsWith('flutter.'));
+        .where((String key) => key.startsWith(prefix));
   }
 
   String _encodeValue(Object? value) {
diff --git a/packages/shared_preferences/shared_preferences_web/pubspec.yaml b/packages/shared_preferences/shared_preferences_web/pubspec.yaml
index 3598348..5c88356 100644
--- a/packages/shared_preferences/shared_preferences_web/pubspec.yaml
+++ b/packages/shared_preferences/shared_preferences_web/pubspec.yaml
@@ -2,7 +2,7 @@
 description: Web platform implementation of shared_preferences
 repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_web
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22
-version: 2.0.6
+version: 2.1.0
 
 environment:
   sdk: ">=2.17.0 <4.0.0"
@@ -21,7 +21,7 @@
     sdk: flutter
   flutter_web_plugins:
     sdk: flutter
-  shared_preferences_platform_interface: ^2.0.0
+  shared_preferences_platform_interface: ^2.2.0
 
 dev_dependencies:
   flutter_test:
diff --git a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md
index cbde97a..caeabe4 100644
--- a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md
+++ b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 2.2.0
+
+* Adds `getAllWithPrefix` and `clearWithPrefix` methods.
+
 ## 2.1.5
 
 * Clarifies explanation of endorsement in README.
diff --git a/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart
index 92a34fc..0025200 100644
--- a/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart
+++ b/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart
@@ -41,25 +41,27 @@
       final SharedPreferencesWindows preferences = SharedPreferencesWindows();
       preferences.clear();
       await preferences.setValue(
-          'String', 'String', kTestValues2['flutter.String']!);
-      await preferences.setValue('Bool', 'bool', kTestValues2['flutter.bool']!);
-      await preferences.setValue('Int', 'int', kTestValues2['flutter.int']!);
+          'String', 'flutter.String', kTestValues2['flutter.String']!);
       await preferences.setValue(
-          'Double', 'double', kTestValues2['flutter.double']!);
+          'Bool', 'flutter.bool', kTestValues2['flutter.bool']!);
       await preferences.setValue(
-          'StringList', 'List', kTestValues2['flutter.List']!);
+          'Int', 'flutter.int', kTestValues2['flutter.int']!);
+      await preferences.setValue(
+          'Double', 'flutter.double', kTestValues2['flutter.double']!);
+      await preferences.setValue(
+          'StringList', 'flutter.List', kTestValues2['flutter.List']!);
       final Map<String, Object> values = await preferences.getAll();
-      expect(values['String'], kTestValues2['flutter.String']);
-      expect(values['bool'], kTestValues2['flutter.bool']);
-      expect(values['int'], kTestValues2['flutter.int']);
-      expect(values['double'], kTestValues2['flutter.double']);
-      expect(values['List'], kTestValues2['flutter.List']);
+      expect(values['flutter.String'], kTestValues2['flutter.String']);
+      expect(values['flutter.bool'], kTestValues2['flutter.bool']);
+      expect(values['flutter.int'], kTestValues2['flutter.int']);
+      expect(values['flutter.double'], kTestValues2['flutter.double']);
+      expect(values['flutter.List'], kTestValues2['flutter.List']);
     });
 
     testWidgets('removing', (WidgetTester _) async {
       final SharedPreferencesWindows preferences = SharedPreferencesWindows();
       preferences.clear();
-      const String key = 'testKey';
+      const String key = 'flutter.testKey';
       await preferences.setValue('String', key, kTestValues['flutter.String']!);
       await preferences.setValue('Bool', key, kTestValues['flutter.bool']!);
       await preferences.setValue('Int', key, kTestValues['flutter.int']!);
@@ -75,20 +77,22 @@
       final SharedPreferencesWindows preferences = SharedPreferencesWindows();
       preferences.clear();
       await preferences.setValue(
-          'String', 'String', kTestValues['flutter.String']!);
-      await preferences.setValue('Bool', 'bool', kTestValues['flutter.bool']!);
-      await preferences.setValue('Int', 'int', kTestValues['flutter.int']!);
+          'String', 'flutter.String', kTestValues['flutter.String']!);
       await preferences.setValue(
-          'Double', 'double', kTestValues['flutter.double']!);
+          'Bool', 'flutter.bool', kTestValues['flutter.bool']!);
       await preferences.setValue(
-          'StringList', 'List', kTestValues['flutter.List']!);
+          'Int', 'flutter.int', kTestValues['flutter.int']!);
+      await preferences.setValue(
+          'Double', 'flutter.double', kTestValues['flutter.double']!);
+      await preferences.setValue(
+          'StringList', 'flutter.List', kTestValues['flutter.List']!);
       await preferences.clear();
       final Map<String, Object> values = await preferences.getAll();
-      expect(values['String'], null);
-      expect(values['bool'], null);
-      expect(values['int'], null);
-      expect(values['double'], null);
-      expect(values['List'], null);
+      expect(values['flutter.String'], null);
+      expect(values['flutter.bool'], null);
+      expect(values['flutter.int'], null);
+      expect(values['flutter.double'], null);
+      expect(values['flutter.List'], null);
     });
   });
 }
diff --git a/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart b/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart
index 5cdb30c..6343759 100644
--- a/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart
+++ b/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart
@@ -26,6 +26,8 @@
     SharedPreferencesStorePlatform.instance = SharedPreferencesWindows();
   }
 
+  static const String _defaultPrefix = 'flutter.';
+
   /// File system used to store to disk. Exposed for testing only.
   @visibleForTesting
   FileSystem fs = const LocalFileSystem();
@@ -55,10 +57,7 @@
 
   /// 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!;
-    }
+  Future<Map<String, Object>> _reload() async {
     Map<String, Object> preferences = <String, Object>{};
     final File? localDataFile = await _getLocalDataFile();
     if (localDataFile != null && localDataFile.existsSync()) {
@@ -74,6 +73,10 @@
     return preferences;
   }
 
+  Future<Map<String, Object>> _readPreferences() async {
+    return _cachedPreferences ?? await _reload();
+  }
+
   /// Writes the cached preferences to disk. Returns [true] if the operation
   /// succeeded.
   Future<bool> _writePreferences(Map<String, Object> preferences) async {
@@ -97,14 +100,27 @@
 
   @override
   Future<bool> clear() async {
+    return clearWithPrefix(_defaultPrefix);
+  }
+
+  @override
+  Future<bool> clearWithPrefix(String prefix) async {
     final Map<String, Object> preferences = await _readPreferences();
-    preferences.clear();
+    preferences.removeWhere((String key, _) => key.startsWith(prefix));
     return _writePreferences(preferences);
   }
 
   @override
   Future<Map<String, Object>> getAll() async {
-    return _readPreferences();
+    return getAllWithPrefix(_defaultPrefix);
+  }
+
+  @override
+  Future<Map<String, Object>> getAllWithPrefix(String prefix) async {
+    final Map<String, Object> withPrefix =
+        Map<String, Object>.from(await _readPreferences());
+    withPrefix.removeWhere((String key, _) => !key.startsWith(prefix));
+    return withPrefix;
   }
 
   @override
diff --git a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml
index da7db58..ae2246b 100644
--- a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml
+++ b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml
@@ -2,7 +2,7 @@
 description: Windows implementation of shared_preferences
 repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_windows
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22
-version: 2.1.5
+version: 2.2.0
 
 environment:
   sdk: ">=2.17.0 <4.0.0"
@@ -22,7 +22,7 @@
   path: ^1.8.0
   path_provider_platform_interface: ^2.0.0
   path_provider_windows: ^2.0.0
-  shared_preferences_platform_interface: ^2.0.0
+  shared_preferences_platform_interface: ^2.2.0
 
 dev_dependencies:
   flutter_test:
diff --git a/packages/shared_preferences/shared_preferences_windows/test/shared_preferences_windows_test.dart b/packages/shared_preferences/shared_preferences_windows/test/shared_preferences_windows_test.dart
index 04fa335..c23ac46 100644
--- a/packages/shared_preferences/shared_preferences_windows/test/shared_preferences_windows_test.dart
+++ b/packages/shared_preferences/shared_preferences_windows/test/shared_preferences_windows_test.dart
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'dart:convert';
+
 import 'package:file/memory.dart';
 import 'package:flutter_test/flutter_test.dart';
 import 'package:path/path.dart' as path;
@@ -11,11 +13,43 @@
 import 'package:shared_preferences_windows/shared_preferences_windows.dart';
 
 void main() {
-  late MemoryFileSystem fileSystem;
+  late MemoryFileSystem fs;
   late PathProviderWindows pathProvider;
 
+  SharedPreferencesWindows.registerWith();
+
+  const Map<String, Object> flutterTestValues = <String, Object>{
+    'flutter.String': 'hello world',
+    'flutter.Bool': true,
+    'flutter.Int': 42,
+    'flutter.Double': 3.14159,
+    'flutter.StringList': <String>['foo', 'bar'],
+  };
+
+  const Map<String, Object> prefixTestValues = <String, Object>{
+    'prefix.String': 'hello world',
+    'prefix.Bool': true,
+    'prefix.Int': 42,
+    'prefix.Double': 3.14159,
+    'prefix.StringList': <String>['foo', 'bar'],
+  };
+
+  const Map<String, Object> nonPrefixTestValues = <String, Object>{
+    'String': 'hello world',
+    'Bool': true,
+    'Int': 42,
+    'Double': 3.14159,
+    'StringList': <String>['foo', 'bar'],
+  };
+
+  final Map<String, Object> allTestValues = <String, Object>{};
+
+  allTestValues.addAll(flutterTestValues);
+  allTestValues.addAll(prefixTestValues);
+  allTestValues.addAll(nonPrefixTestValues);
+
   setUp(() {
-    fileSystem = MemoryFileSystem.test();
+    fs = MemoryFileSystem.test();
     pathProvider = FakePathProviderWindows();
   });
 
@@ -25,18 +59,18 @@
   }
 
   Future<void> writeTestFile(String value) async {
-    fileSystem.file(await getFilePath())
+    fs.file(await getFilePath())
       ..createSync(recursive: true)
       ..writeAsStringSync(value);
   }
 
   Future<String> readTestFile() async {
-    return fileSystem.file(await getFilePath()).readAsStringSync();
+    return fs.file(await getFilePath()).readAsStringSync();
   }
 
   SharedPreferencesWindows getPreferences() {
     final SharedPreferencesWindows prefs = SharedPreferencesWindows();
-    prefs.fs = fileSystem;
+    prefs.fs = fs;
     prefs.pathProvider = pathProvider;
     return prefs;
   }
@@ -48,13 +82,21 @@
   });
 
   test('getAll', () async {
-    await writeTestFile('{"key1": "one", "key2": 2}');
+    await writeTestFile(json.encode(allTestValues));
     final SharedPreferencesWindows prefs = getPreferences();
 
     final Map<String, Object> values = await prefs.getAll();
-    expect(values, hasLength(2));
-    expect(values['key1'], 'one');
-    expect(values['key2'], 2);
+    expect(values, hasLength(5));
+    expect(values, flutterTestValues);
+  });
+
+  test('getAllWithPrefix', () async {
+    await writeTestFile(json.encode(allTestValues));
+    final SharedPreferencesWindows prefs = getPreferences();
+
+    final Map<String, Object> values = await prefs.getAllWithPrefix('prefix.');
+    expect(values, hasLength(5));
+    expect(values, prefixTestValues);
   });
 
   test('remove', () async {
@@ -77,12 +119,43 @@
   });
 
   test('clear', () async {
-    await writeTestFile('{"key1":"one","key2":2}');
+    await writeTestFile(json.encode(flutterTestValues));
     final SharedPreferencesWindows prefs = getPreferences();
 
+    expect(await readTestFile(), json.encode(flutterTestValues));
     await prefs.clear();
     expect(await readTestFile(), '{}');
   });
+
+  test('clearWithPrefix', () async {
+    await writeTestFile(json.encode(flutterTestValues));
+    final SharedPreferencesWindows prefs = getPreferences();
+    await prefs.clearWithPrefix('prefix.');
+    final Map<String, Object> noValues =
+        await prefs.getAllWithPrefix('prefix.');
+    expect(noValues, hasLength(0));
+
+    final Map<String, Object> values = await prefs.getAll();
+    expect(values, hasLength(5));
+    expect(values, flutterTestValues);
+  });
+
+  test('getAllWithNoPrefix', () async {
+    await writeTestFile(json.encode(allTestValues));
+    final SharedPreferencesWindows prefs = getPreferences();
+
+    final Map<String, Object> values = await prefs.getAllWithPrefix('');
+    expect(values, hasLength(15));
+    expect(values, allTestValues);
+  });
+
+  test('clearWithNoPrefix', () async {
+    await writeTestFile(json.encode(flutterTestValues));
+    final SharedPreferencesWindows prefs = getPreferences();
+    await prefs.clearWithPrefix('');
+    final Map<String, Object> noValues = await prefs.getAllWithPrefix('');
+    expect(noValues, hasLength(0));
+  });
 }
 
 /// Fake implementation of PathProviderWindows that returns hard-coded paths,