[shared_preferences] upgraded ios to using pigeon (#4732)

diff --git a/packages/shared_preferences/shared_preferences_ios/CHANGELOG.md b/packages/shared_preferences/shared_preferences_ios/CHANGELOG.md
index b2a9f14..a5cc1d3 100644
--- a/packages/shared_preferences/shared_preferences_ios/CHANGELOG.md
+++ b/packages/shared_preferences/shared_preferences_ios/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 2.1.0
+
+* Upgrades to using Pigeon.
+
 ## 2.0.10
 
 * Switches to an in-package method channel implementation.
diff --git a/packages/shared_preferences/shared_preferences_ios/ios/Classes/FLTSharedPreferencesPlugin.m b/packages/shared_preferences/shared_preferences_ios/ios/Classes/FLTSharedPreferencesPlugin.m
index 4d49e3b..bb11da2 100644
--- a/packages/shared_preferences/shared_preferences_ios/ios/Classes/FLTSharedPreferencesPlugin.m
+++ b/packages/shared_preferences/shared_preferences_ios/ios/Classes/FLTSharedPreferencesPlugin.m
@@ -3,68 +3,7 @@
 // found in the LICENSE file.
 
 #import "FLTSharedPreferencesPlugin.h"
-
-static NSString *const CHANNEL_NAME = @"plugins.flutter.io/shared_preferences_ios";
-
-@implementation FLTSharedPreferencesPlugin
-
-+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
-  FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:CHANNEL_NAME
-                                                              binaryMessenger:registrar.messenger];
-  [channel setMethodCallHandler:^(FlutterMethodCall *call, FlutterResult result) {
-    NSString *method = [call method];
-    NSDictionary *arguments = [call arguments];
-
-    if ([method isEqualToString:@"getAll"]) {
-      result(getAllPrefs());
-    } else if ([method isEqualToString:@"setBool"]) {
-      NSString *key = arguments[@"key"];
-      NSNumber *value = arguments[@"value"];
-      [[NSUserDefaults standardUserDefaults] setBool:value.boolValue forKey:key];
-      result(@YES);
-    } else if ([method isEqualToString:@"setInt"]) {
-      NSString *key = arguments[@"key"];
-      NSNumber *value = arguments[@"value"];
-      // int type in Dart can come to native side in a variety of forms
-      // It is best to store it as is and send it back when needed.
-      // Platform channel will handle the conversion.
-      [[NSUserDefaults standardUserDefaults] setValue:value forKey:key];
-      result(@YES);
-    } else if ([method isEqualToString:@"setDouble"]) {
-      NSString *key = arguments[@"key"];
-      NSNumber *value = arguments[@"value"];
-      [[NSUserDefaults standardUserDefaults] setDouble:value.doubleValue forKey:key];
-      result(@YES);
-    } else if ([method isEqualToString:@"setString"]) {
-      NSString *key = arguments[@"key"];
-      NSString *value = arguments[@"value"];
-      [[NSUserDefaults standardUserDefaults] setValue:value forKey:key];
-      result(@YES);
-    } else if ([method isEqualToString:@"setStringList"]) {
-      NSString *key = arguments[@"key"];
-      NSArray *value = arguments[@"value"];
-      [[NSUserDefaults standardUserDefaults] setValue:value forKey:key];
-      result(@YES);
-    } else if ([method isEqualToString:@"commit"]) {
-      // synchronize is deprecated.
-      // "this method is unnecessary and shouldn't be used."
-      result(@YES);
-    } else if ([method isEqualToString:@"remove"]) {
-      [[NSUserDefaults standardUserDefaults] removeObjectForKey:arguments[@"key"]];
-      result(@YES);
-    } else if ([method isEqualToString:@"clear"]) {
-      NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
-      for (NSString *key in getAllPrefs()) {
-        [defaults removeObjectForKey:key];
-      }
-      result(@YES);
-    } else {
-      result(FlutterMethodNotImplemented);
-    }
-  }];
-}
-
-#pragma mark - Private
+#import "messages.g.h"
 
 static NSMutableDictionary *getAllPrefs() {
   NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
@@ -80,4 +19,50 @@
   return filteredPrefs;
 }
 
+@interface FLTSharedPreferencesPlugin () <UserDefaultsApi>
+@end
+
+@implementation FLTSharedPreferencesPlugin
+
++ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
+  FLTSharedPreferencesPlugin *plugin = [[FLTSharedPreferencesPlugin alloc] init];
+  UserDefaultsApiSetup(registrar.messenger, plugin);
+}
+
+// Must not return nil unless "error" is set.
+- (nullable NSDictionary<NSString *, id> *)getAllWithError:
+    (FlutterError *_Nullable __autoreleasing *_Nonnull)error {
+  return getAllPrefs();
+}
+
+- (void)clearWithError:(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
+  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+  for (NSString *key in getAllPrefs()) {
+    [defaults removeObjectForKey:key];
+  }
+}
+
+- (void)removeKey:(nonnull NSString *)key
+            error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
+  [[NSUserDefaults standardUserDefaults] removeObjectForKey:key];
+}
+
+- (void)setBoolKey:(nonnull NSString *)key
+             value:(nonnull NSNumber *)value
+             error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
+  [[NSUserDefaults standardUserDefaults] setBool:value.boolValue forKey:key];
+}
+
+- (void)setDoubleKey:(nonnull NSString *)key
+               value:(nonnull NSNumber *)value
+               error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
+  [[NSUserDefaults standardUserDefaults] setDouble:value.doubleValue forKey:key];
+}
+
+- (void)setValueKey:(nonnull NSString *)key
+              value:(nonnull NSString *)value
+              error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
+  [[NSUserDefaults standardUserDefaults] setValue:value forKey:key];
+}
+
 @end
diff --git a/packages/shared_preferences/shared_preferences_ios/ios/Classes/messages.g.h b/packages/shared_preferences/shared_preferences_ios/ios/Classes/messages.g.h
new file mode 100644
index 0000000..5924023
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_ios/ios/Classes/messages.g.h
@@ -0,0 +1,33 @@
+// 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 (v1.0.16), do not edit directly.
+// See also: https://pub.dev/packages/pigeon
+#import <Foundation/Foundation.h>
+@protocol FlutterBinaryMessenger;
+@protocol FlutterMessageCodec;
+@class FlutterError;
+@class FlutterStandardTypedData;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// The codec used by UserDefaultsApi.
+NSObject<FlutterMessageCodec> *UserDefaultsApiGetCodec(void);
+
+@protocol UserDefaultsApi
+- (void)removeKey:(NSString *)key error:(FlutterError *_Nullable *_Nonnull)error;
+- (void)setBoolKey:(NSString *)key
+             value:(NSNumber *)value
+             error:(FlutterError *_Nullable *_Nonnull)error;
+- (void)setDoubleKey:(NSString *)key
+               value:(NSNumber *)value
+               error:(FlutterError *_Nullable *_Nonnull)error;
+- (void)setValueKey:(NSString *)key value:(id)value error:(FlutterError *_Nullable *_Nonnull)error;
+- (nullable NSDictionary<NSString *, id> *)getAllWithError:(FlutterError *_Nullable *_Nonnull)error;
+- (void)clearWithError:(FlutterError *_Nullable *_Nonnull)error;
+@end
+
+extern void UserDefaultsApiSetup(id<FlutterBinaryMessenger> binaryMessenger,
+                                 NSObject<UserDefaultsApi> *_Nullable api);
+
+NS_ASSUME_NONNULL_END
diff --git a/packages/shared_preferences/shared_preferences_ios/ios/Classes/messages.g.m b/packages/shared_preferences/shared_preferences_ios/ios/Classes/messages.g.m
new file mode 100644
index 0000000..ea8c45c
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_ios/ios/Classes/messages.g.m
@@ -0,0 +1,178 @@
+// 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 (v1.0.16), do not edit directly.
+// See also: https://pub.dev/packages/pigeon
+#import "messages.g.h"
+#import <Flutter/Flutter.h>
+
+#if !__has_feature(objc_arc)
+#error File requires ARC to be enabled.
+#endif
+
+static NSDictionary<NSString *, id> *wrapResult(id result, FlutterError *error) {
+  NSDictionary *errorDict = (NSDictionary *)[NSNull null];
+  if (error) {
+    errorDict = @{
+      @"code" : (error.code ? error.code : [NSNull null]),
+      @"message" : (error.message ? error.message : [NSNull null]),
+      @"details" : (error.details ? error.details : [NSNull null]),
+    };
+  }
+  return @{
+    @"result" : (result ? result : [NSNull null]),
+    @"error" : errorDict,
+  };
+}
+
+@interface UserDefaultsApiCodecReader : FlutterStandardReader
+@end
+@implementation UserDefaultsApiCodecReader
+@end
+
+@interface UserDefaultsApiCodecWriter : FlutterStandardWriter
+@end
+@implementation UserDefaultsApiCodecWriter
+@end
+
+@interface UserDefaultsApiCodecReaderWriter : FlutterStandardReaderWriter
+@end
+@implementation UserDefaultsApiCodecReaderWriter
+- (FlutterStandardWriter *)writerWithData:(NSMutableData *)data {
+  return [[UserDefaultsApiCodecWriter alloc] initWithData:data];
+}
+- (FlutterStandardReader *)readerWithData:(NSData *)data {
+  return [[UserDefaultsApiCodecReader alloc] initWithData:data];
+}
+@end
+
+NSObject<FlutterMessageCodec> *UserDefaultsApiGetCodec() {
+  static dispatch_once_t s_pred = 0;
+  static FlutterStandardMessageCodec *s_sharedObject = nil;
+  dispatch_once(&s_pred, ^{
+    UserDefaultsApiCodecReaderWriter *readerWriter =
+        [[UserDefaultsApiCodecReaderWriter alloc] init];
+    s_sharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter];
+  });
+  return s_sharedObject;
+}
+
+void UserDefaultsApiSetup(id<FlutterBinaryMessenger> binaryMessenger,
+                          NSObject<UserDefaultsApi> *api) {
+  {
+    FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
+        messageChannelWithName:@"dev.flutter.pigeon.UserDefaultsApi.remove"
+               binaryMessenger:binaryMessenger
+                         codec:UserDefaultsApiGetCodec()];
+    if (api) {
+      NSCAssert([api respondsToSelector:@selector(removeKey:error:)],
+                @"UserDefaultsApi api (%@) doesn't respond to @selector(removeKey:error:)", api);
+      [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
+        NSArray *args = message;
+        NSString *arg_key = args[0];
+        FlutterError *error;
+        [api removeKey:arg_key error:&error];
+        callback(wrapResult(nil, error));
+      }];
+    } else {
+      [channel setMessageHandler:nil];
+    }
+  }
+  {
+    FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
+        messageChannelWithName:@"dev.flutter.pigeon.UserDefaultsApi.setBool"
+               binaryMessenger:binaryMessenger
+                         codec:UserDefaultsApiGetCodec()];
+    if (api) {
+      NSCAssert([api respondsToSelector:@selector(setBoolKey:value:error:)],
+                @"UserDefaultsApi api (%@) doesn't respond to @selector(setBoolKey:value:error:)",
+                api);
+      [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
+        NSArray *args = message;
+        NSString *arg_key = args[0];
+        NSNumber *arg_value = args[1];
+        FlutterError *error;
+        [api setBoolKey:arg_key value:arg_value error:&error];
+        callback(wrapResult(nil, error));
+      }];
+    } else {
+      [channel setMessageHandler:nil];
+    }
+  }
+  {
+    FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
+        messageChannelWithName:@"dev.flutter.pigeon.UserDefaultsApi.setDouble"
+               binaryMessenger:binaryMessenger
+                         codec:UserDefaultsApiGetCodec()];
+    if (api) {
+      NSCAssert([api respondsToSelector:@selector(setDoubleKey:value:error:)],
+                @"UserDefaultsApi api (%@) doesn't respond to @selector(setDoubleKey:value:error:)",
+                api);
+      [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
+        NSArray *args = message;
+        NSString *arg_key = args[0];
+        NSNumber *arg_value = args[1];
+        FlutterError *error;
+        [api setDoubleKey:arg_key value:arg_value error:&error];
+        callback(wrapResult(nil, error));
+      }];
+    } else {
+      [channel setMessageHandler:nil];
+    }
+  }
+  {
+    FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
+        messageChannelWithName:@"dev.flutter.pigeon.UserDefaultsApi.setValue"
+               binaryMessenger:binaryMessenger
+                         codec:UserDefaultsApiGetCodec()];
+    if (api) {
+      NSCAssert([api respondsToSelector:@selector(setValueKey:value:error:)],
+                @"UserDefaultsApi api (%@) doesn't respond to @selector(setValueKey:value:error:)",
+                api);
+      [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
+        NSArray *args = message;
+        NSString *arg_key = args[0];
+        id arg_value = args[1];
+        FlutterError *error;
+        [api setValueKey:arg_key value:arg_value error:&error];
+        callback(wrapResult(nil, error));
+      }];
+    } else {
+      [channel setMessageHandler:nil];
+    }
+  }
+  {
+    FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
+        messageChannelWithName:@"dev.flutter.pigeon.UserDefaultsApi.getAll"
+               binaryMessenger:binaryMessenger
+                         codec:UserDefaultsApiGetCodec()];
+    if (api) {
+      NSCAssert([api respondsToSelector:@selector(getAllWithError:)],
+                @"UserDefaultsApi api (%@) doesn't respond to @selector(getAllWithError:)", api);
+      [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
+        FlutterError *error;
+        NSDictionary<NSString *, id> *output = [api getAllWithError:&error];
+        callback(wrapResult(output, error));
+      }];
+    } else {
+      [channel setMessageHandler:nil];
+    }
+  }
+  {
+    FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
+        messageChannelWithName:@"dev.flutter.pigeon.UserDefaultsApi.clear"
+               binaryMessenger:binaryMessenger
+                         codec:UserDefaultsApiGetCodec()];
+    if (api) {
+      NSCAssert([api respondsToSelector:@selector(clearWithError:)],
+                @"UserDefaultsApi api (%@) doesn't respond to @selector(clearWithError:)", api);
+      [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
+        FlutterError *error;
+        [api clearWithError:&error];
+        callback(wrapResult(nil, error));
+      }];
+    } else {
+      [channel setMessageHandler:nil];
+    }
+  }
+}
diff --git a/packages/shared_preferences/shared_preferences_ios/lib/messages.g.dart b/packages/shared_preferences/shared_preferences_ios/lib/messages.g.dart
new file mode 100644
index 0000000..0e76291
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_ios/lib/messages.g.dart
@@ -0,0 +1,179 @@
+// 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 (v1.0.16), 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
+// @dart = 2.12
+import 'dart:async';
+import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List;
+
+import 'package:flutter/foundation.dart' show WriteBuffer, ReadBuffer;
+import 'package:flutter/services.dart';
+
+class _UserDefaultsApiCodec extends StandardMessageCodec {
+  const _UserDefaultsApiCodec();
+}
+
+class UserDefaultsApi {
+  /// Constructor for [UserDefaultsApi].  The [binaryMessenger] named argument is
+  /// available for dependency injection.  If it is left null, the default
+  /// BinaryMessenger will be used which routes to the host platform.
+  UserDefaultsApi({BinaryMessenger? binaryMessenger})
+      : _binaryMessenger = binaryMessenger;
+
+  final BinaryMessenger? _binaryMessenger;
+
+  static const MessageCodec<Object?> codec = _UserDefaultsApiCodec();
+
+  Future<void> remove(String arg_key) async {
+    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+        'dev.flutter.pigeon.UserDefaultsApi.remove', codec,
+        binaryMessenger: _binaryMessenger);
+    final Map<Object?, Object?>? replyMap =
+        await channel.send(<Object>[arg_key]) as Map<Object?, Object?>?;
+    if (replyMap == null) {
+      throw PlatformException(
+        code: 'channel-error',
+        message: 'Unable to establish connection on channel.',
+        details: null,
+      );
+    } else if (replyMap['error'] != null) {
+      final Map<Object?, Object?> error =
+          (replyMap['error'] as Map<Object?, Object?>?)!;
+      throw PlatformException(
+        code: (error['code'] as String?)!,
+        message: error['message'] as String?,
+        details: error['details'],
+      );
+    } else {
+      return;
+    }
+  }
+
+  Future<void> setBool(String arg_key, bool arg_value) async {
+    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+        'dev.flutter.pigeon.UserDefaultsApi.setBool', codec,
+        binaryMessenger: _binaryMessenger);
+    final Map<Object?, Object?>? replyMap = await channel
+        .send(<Object>[arg_key, arg_value]) as Map<Object?, Object?>?;
+    if (replyMap == null) {
+      throw PlatformException(
+        code: 'channel-error',
+        message: 'Unable to establish connection on channel.',
+        details: null,
+      );
+    } else if (replyMap['error'] != null) {
+      final Map<Object?, Object?> error =
+          (replyMap['error'] as Map<Object?, Object?>?)!;
+      throw PlatformException(
+        code: (error['code'] as String?)!,
+        message: error['message'] as String?,
+        details: error['details'],
+      );
+    } else {
+      return;
+    }
+  }
+
+  Future<void> setDouble(String arg_key, double arg_value) async {
+    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+        'dev.flutter.pigeon.UserDefaultsApi.setDouble', codec,
+        binaryMessenger: _binaryMessenger);
+    final Map<Object?, Object?>? replyMap = await channel
+        .send(<Object>[arg_key, arg_value]) as Map<Object?, Object?>?;
+    if (replyMap == null) {
+      throw PlatformException(
+        code: 'channel-error',
+        message: 'Unable to establish connection on channel.',
+        details: null,
+      );
+    } else if (replyMap['error'] != null) {
+      final Map<Object?, Object?> error =
+          (replyMap['error'] as Map<Object?, Object?>?)!;
+      throw PlatformException(
+        code: (error['code'] as String?)!,
+        message: error['message'] as String?,
+        details: error['details'],
+      );
+    } else {
+      return;
+    }
+  }
+
+  Future<void> setValue(String arg_key, Object arg_value) async {
+    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+        'dev.flutter.pigeon.UserDefaultsApi.setValue', codec,
+        binaryMessenger: _binaryMessenger);
+    final Map<Object?, Object?>? replyMap = await channel
+        .send(<Object>[arg_key, arg_value]) as Map<Object?, Object?>?;
+    if (replyMap == null) {
+      throw PlatformException(
+        code: 'channel-error',
+        message: 'Unable to establish connection on channel.',
+        details: null,
+      );
+    } else if (replyMap['error'] != null) {
+      final Map<Object?, Object?> error =
+          (replyMap['error'] as Map<Object?, Object?>?)!;
+      throw PlatformException(
+        code: (error['code'] as String?)!,
+        message: error['message'] as String?,
+        details: error['details'],
+      );
+    } else {
+      return;
+    }
+  }
+
+  Future<Map<String?, Object?>> getAll() async {
+    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+        'dev.flutter.pigeon.UserDefaultsApi.getAll', codec,
+        binaryMessenger: _binaryMessenger);
+    final Map<Object?, Object?>? replyMap =
+        await channel.send(null) as Map<Object?, Object?>?;
+    if (replyMap == null) {
+      throw PlatformException(
+        code: 'channel-error',
+        message: 'Unable to establish connection on channel.',
+        details: null,
+      );
+    } else if (replyMap['error'] != null) {
+      final Map<Object?, Object?> error =
+          (replyMap['error'] as Map<Object?, Object?>?)!;
+      throw PlatformException(
+        code: (error['code'] as String?)!,
+        message: error['message'] as String?,
+        details: error['details'],
+      );
+    } else {
+      return (replyMap['result'] as Map<Object?, Object?>?)!
+          .cast<String?, Object?>();
+    }
+  }
+
+  Future<void> clear() async {
+    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+        'dev.flutter.pigeon.UserDefaultsApi.clear', codec,
+        binaryMessenger: _binaryMessenger);
+    final Map<Object?, Object?>? replyMap =
+        await channel.send(null) as Map<Object?, Object?>?;
+    if (replyMap == null) {
+      throw PlatformException(
+        code: 'channel-error',
+        message: 'Unable to establish connection on channel.',
+        details: null,
+      );
+    } else if (replyMap['error'] != null) {
+      final Map<Object?, Object?> error =
+          (replyMap['error'] as Map<Object?, Object?>?)!;
+      throw PlatformException(
+        code: (error['code'] as String?)!,
+        message: error['message'] as String?,
+        details: error['details'],
+      );
+    } else {
+      return;
+    }
+  }
+}
diff --git a/packages/shared_preferences/shared_preferences_ios/lib/shared_preferences_ios.dart b/packages/shared_preferences/shared_preferences_ios/lib/shared_preferences_ios.dart
index 15f1e2f..1063884 100644
--- a/packages/shared_preferences/shared_preferences_ios/lib/shared_preferences_ios.dart
+++ b/packages/shared_preferences/shared_preferences_ios/lib/shared_preferences_ios.dart
@@ -2,52 +2,65 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:async';
-
 import 'package:flutter/services.dart';
 import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
+import 'messages.g.dart';
 
-const MethodChannel _kChannel =
-    MethodChannel('plugins.flutter.io/shared_preferences_ios');
+typedef _Setter = Future<void> Function(String key, Object value);
 
-/// The macOS implementation of [SharedPreferencesStorePlatform].
-///
-/// This class implements the `package:shared_preferences` functionality for iOS.
+/// iOS implementation of shared_preferences.
 class SharedPreferencesIOS extends SharedPreferencesStorePlatform {
-  /// Registers this class as the default instance of [SharedPreferencesStorePlatform].
+  final UserDefaultsApi _api = UserDefaultsApi();
+  late final Map<String, _Setter> _setters = <String, _Setter>{
+    'Bool': (String key, Object value) {
+      return _api.setBool(key, value as bool);
+    },
+    'Double': (String key, Object value) {
+      return _api.setDouble(key, value as double);
+    },
+    'Int': (String key, Object value) {
+      return _api.setValue(key, value as int);
+    },
+    'String': (String key, Object value) {
+      return _api.setValue(key, value as String);
+    },
+    'StringList': (String key, Object value) {
+      return _api.setValue(key, value as List<String?>);
+    },
+  };
+
+  /// Registers this class as the default instance of [PathProviderPlatform].
   static void registerWith() {
     SharedPreferencesStorePlatform.instance = SharedPreferencesIOS();
   }
 
   @override
-  Future<bool> remove(String key) async {
-    return (await _kChannel.invokeMethod<bool>(
-      'remove',
-      <String, dynamic>{'key': key},
-    ))!;
-  }
-
-  @override
-  Future<bool> setValue(String valueType, String key, Object value) async {
-    return (await _kChannel.invokeMethod<bool>(
-      'set$valueType',
-      <String, dynamic>{'key': key, 'value': value},
-    ))!;
-  }
-
-  @override
   Future<bool> clear() async {
-    return (await _kChannel.invokeMethod<bool>('clear'))!;
+    await _api.clear();
+    return true;
   }
 
   @override
   Future<Map<String, Object>> getAll() async {
-    final Map<String, Object>? preferences =
-        await _kChannel.invokeMapMethod<String, Object>('getAll');
+    final Map<String?, Object?> result = await _api.getAll();
+    return result.cast<String, Object>();
+  }
 
-    if (preferences == null) {
-      return <String, Object>{};
+  @override
+  Future<bool> remove(String key) async {
+    await _api.remove(key);
+    return true;
+  }
+
+  @override
+  Future<bool> setValue(String valueType, String key, Object value) async {
+    final _Setter? setter = _setters[valueType];
+    if (setter == null) {
+      throw PlatformException(
+          code: 'InvalidOperation',
+          message: '"$valueType" is not a supported type.');
     }
-    return preferences;
+    await setter(key, value);
+    return true;
   }
 }
diff --git a/packages/shared_preferences/shared_preferences_ios/pigeons/copyright_header.txt b/packages/shared_preferences/shared_preferences_ios/pigeons/copyright_header.txt
new file mode 100644
index 0000000..fb682b1
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_ios/pigeons/copyright_header.txt
@@ -0,0 +1,3 @@
+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.
\ No newline at end of file
diff --git a/packages/shared_preferences/shared_preferences_ios/pigeons/messages.dart b/packages/shared_preferences/shared_preferences_ios/pigeons/messages.dart
new file mode 100644
index 0000000..6b5648f
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_ios/pigeons/messages.dart
@@ -0,0 +1,22 @@
+// 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 'package:pigeon/pigeon.dart';
+
+@ConfigurePigeon(PigeonOptions(
+  dartOut: 'lib/messages.g.dart',
+  dartTestOut: 'test/messages.g.dart',
+  objcHeaderOut: 'ios/Classes/messages.g.h',
+  objcSourceOut: 'ios/Classes/messages.g.m',
+  copyrightHeader: 'pigeons/copyright_header.txt',
+))
+@HostApi(dartHostTestHandler: 'TestUserDefaultsApi')
+abstract class UserDefaultsApi {
+  void remove(String key);
+  void setBool(String key, bool value);
+  void setDouble(String key, double value);
+  void setValue(String key, Object value);
+  Map<String?, Object?> getAll();
+  void clear();
+}
diff --git a/packages/shared_preferences/shared_preferences_ios/pubspec.yaml b/packages/shared_preferences/shared_preferences_ios/pubspec.yaml
index 68ab035..33bf5ba 100644
--- a/packages/shared_preferences/shared_preferences_ios/pubspec.yaml
+++ b/packages/shared_preferences/shared_preferences_ios/pubspec.yaml
@@ -2,7 +2,7 @@
 description: iOS implementation of the shared_preferences plugin
 repository: https://github.com/flutter/plugins/tree/main/packages/shared_preferences/shared_preferences_ios
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22
-version: 2.0.10
+version: 2.1.0
 
 environment:
   sdk: ">=2.14.0 <3.0.0"
@@ -13,8 +13,8 @@
     implements: shared_preferences
     platforms:
       ios:
-        pluginClass: FLTSharedPreferencesPlugin
         dartPluginClass: SharedPreferencesIOS
+        pluginClass: FLTSharedPreferencesPlugin
 
 dependencies:
   flutter:
@@ -24,3 +24,4 @@
 dev_dependencies:
   flutter_test:
     sdk: flutter
+  pigeon: ^1.0.16
diff --git a/packages/shared_preferences/shared_preferences_ios/test/messages.g.dart b/packages/shared_preferences/shared_preferences_ios/test/messages.g.dart
new file mode 100644
index 0000000..12fbc06
--- /dev/null
+++ b/packages/shared_preferences/shared_preferences_ios/test/messages.g.dart
@@ -0,0 +1,145 @@
+// 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 (v1.0.16), 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
+// @dart = 2.12
+import 'dart:async';
+import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List;
+import 'package:flutter/foundation.dart' show WriteBuffer, ReadBuffer;
+import 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+import 'package:shared_preferences_ios/messages.g.dart';
+
+class _TestUserDefaultsApiCodec extends StandardMessageCodec {
+  const _TestUserDefaultsApiCodec();
+}
+
+abstract class TestUserDefaultsApi {
+  static const MessageCodec<Object?> codec = _TestUserDefaultsApiCodec();
+
+  void remove(String key);
+  void setBool(String key, bool value);
+  void setDouble(String key, double value);
+  void setValue(String key, Object value);
+  Map<String?, Object?> getAll();
+  void clear();
+  static void setup(TestUserDefaultsApi? api,
+      {BinaryMessenger? binaryMessenger}) {
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.UserDefaultsApi.remove', codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.UserDefaultsApi.remove was null.');
+          final List<Object?> args = (message as List<Object?>?)!;
+          final String? arg_key = (args[0] as String?);
+          assert(arg_key != null,
+              'Argument for dev.flutter.pigeon.UserDefaultsApi.remove was null, expected non-null String.');
+          api.remove(arg_key!);
+          return <Object?, Object?>{};
+        });
+      }
+    }
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.UserDefaultsApi.setBool', codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.UserDefaultsApi.setBool was null.');
+          final List<Object?> args = (message as List<Object?>?)!;
+          final String? arg_key = (args[0] as String?);
+          assert(arg_key != null,
+              'Argument for dev.flutter.pigeon.UserDefaultsApi.setBool was null, expected non-null String.');
+          final bool? arg_value = (args[1] as bool?);
+          assert(arg_value != null,
+              'Argument for dev.flutter.pigeon.UserDefaultsApi.setBool was null, expected non-null bool.');
+          api.setBool(arg_key!, arg_value!);
+          return <Object?, Object?>{};
+        });
+      }
+    }
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.UserDefaultsApi.setDouble', codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.UserDefaultsApi.setDouble was null.');
+          final List<Object?> args = (message as List<Object?>?)!;
+          final String? arg_key = (args[0] as String?);
+          assert(arg_key != null,
+              'Argument for dev.flutter.pigeon.UserDefaultsApi.setDouble was null, expected non-null String.');
+          final double? arg_value = (args[1] as double?);
+          assert(arg_value != null,
+              'Argument for dev.flutter.pigeon.UserDefaultsApi.setDouble was null, expected non-null double.');
+          api.setDouble(arg_key!, arg_value!);
+          return <Object?, Object?>{};
+        });
+      }
+    }
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.UserDefaultsApi.setValue', codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.UserDefaultsApi.setValue was null.');
+          final List<Object?> args = (message as List<Object?>?)!;
+          final String? arg_key = (args[0] as String?);
+          assert(arg_key != null,
+              'Argument for dev.flutter.pigeon.UserDefaultsApi.setValue was null, expected non-null String.');
+          final Object? arg_value = (args[1] as Object?);
+          assert(arg_value != null,
+              'Argument for dev.flutter.pigeon.UserDefaultsApi.setValue was null, expected non-null Object.');
+          api.setValue(arg_key!, arg_value!);
+          return <Object?, Object?>{};
+        });
+      }
+    }
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.UserDefaultsApi.getAll', codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((Object? message) async {
+          // ignore message
+          final Map<String?, Object?> output = api.getAll();
+          return <Object?, Object?>{'result': output};
+        });
+      }
+    }
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.UserDefaultsApi.clear', codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((Object? message) async {
+          // ignore message
+          api.clear();
+          return <Object?, Object?>{};
+        });
+      }
+    }
+  }
+}
diff --git a/packages/shared_preferences/shared_preferences_ios/test/shared_preferences_ios_test.dart b/packages/shared_preferences/shared_preferences_ios/test/shared_preferences_ios_test.dart
index 8eb23f2..efafb23 100644
--- a/packages/shared_preferences/shared_preferences_ios/test/shared_preferences_ios_test.dart
+++ b/packages/shared_preferences/shared_preferences_ios/test/shared_preferences_ios_test.dart
@@ -5,113 +5,101 @@
 import 'package:flutter/services.dart';
 import 'package:flutter_test/flutter_test.dart';
 import 'package:shared_preferences_ios/shared_preferences_ios.dart';
-import 'package:shared_preferences_platform_interface/method_channel_shared_preferences.dart';
 import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
 
+import 'messages.g.dart';
+
+class _MockSharedPreferencesApi implements TestUserDefaultsApi {
+  final Map<String, Object> items = <String, Object>{};
+
+  @override
+  Map<String?, Object?> getAll() {
+    return items;
+  }
+
+  @override
+  void remove(String key) {
+    items.remove(key);
+  }
+
+  @override
+  void setBool(String key, bool value) {
+    items[key] = value;
+  }
+
+  @override
+  void setDouble(String key, double value) {
+    items[key] = value;
+  }
+
+  @override
+  void setValue(String key, Object value) {
+    items[key] = value;
+  }
+
+  @override
+  void clear() {
+    items.clear();
+  }
+}
+
 void main() {
   TestWidgetsFlutterBinding.ensureInitialized();
+  _MockSharedPreferencesApi api = _MockSharedPreferencesApi();
+  SharedPreferencesIOS plugin = SharedPreferencesIOS();
 
-  group(MethodChannelSharedPreferencesStore, () {
-    const MethodChannel channel = MethodChannel(
-      'plugins.flutter.io/shared_preferences_ios',
-    );
+  setUp(() {
+    api = _MockSharedPreferencesApi();
+    TestUserDefaultsApi.setup(api);
+    plugin = SharedPreferencesIOS();
+  });
 
-    const Map<String, Object> kTestValues = <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.
-    late InMemorySharedPreferencesStore testData;
+  test('registerWith', () {
+    SharedPreferencesIOS.registerWith();
+    expect(
+        SharedPreferencesStorePlatform.instance, isA<SharedPreferencesIOS>());
+  });
 
-    final List<MethodCall> log = <MethodCall>[];
-    late SharedPreferencesStorePlatform store;
+  test('remove', () async {
+    api.items['flutter.hi'] = 'world';
+    expect(await plugin.remove('flutter.hi'), isTrue);
+    expect(api.items.containsKey('flutter.hi'), isFalse);
+  });
 
-    setUp(() async {
-      testData = InMemorySharedPreferencesStore.empty();
+  test('clear', () async {
+    api.items['flutter.hi'] = 'world';
+    expect(await plugin.clear(), isTrue);
+    expect(api.items.containsKey('flutter.hi'), isFalse);
+  });
 
-      channel.setMockMethodCallHandler((MethodCall methodCall) async {
-        log.add(methodCall);
-        if (methodCall.method == 'getAll') {
-          return await testData.getAll();
-        }
-        if (methodCall.method == 'remove') {
-          final String key = methodCall.arguments['key'] as String;
-          return await testData.remove(key);
-        }
-        if (methodCall.method == 'clear') {
-          return await testData.clear();
-        }
-        final RegExp setterRegExp = RegExp(r'set(.*)');
-        final Match? match = setterRegExp.matchAsPrefix(methodCall.method);
-        if (match?.groupCount == 1) {
-          final String valueType = match!.group(1)!;
-          final String key = methodCall.arguments['key'] as String;
-          final Object value = methodCall.arguments['value'] as Object;
-          return await testData.setValue(valueType, key, value);
-        }
-        fail('Unexpected method call: ${methodCall.method}');
-      });
-      log.clear();
-    });
+  test('getAll', () async {
+    api.items['flutter.hi'] = 'world';
+    api.items['flutter.bye'] = 'dust';
+    final Map<String?, Object?> all = await plugin.getAll();
+    expect(all.length, 2);
+    expect(all['flutter.hi'], api.items['flutter.hi']);
+    expect(all['flutter.bye'], api.items['flutter.bye']);
+  });
 
-    test('registered instance', () {
-      SharedPreferencesIOS.registerWith();
-      expect(
-          SharedPreferencesStorePlatform.instance, isA<SharedPreferencesIOS>());
-    });
+  test('setValue', () async {
+    expect(await plugin.setValue('Bool', 'flutter.Bool', true), isTrue);
+    expect(api.items['flutter.Bool'], true);
+    expect(await plugin.setValue('Double', 'flutter.Double', 1.5), isTrue);
+    expect(api.items['flutter.Double'], 1.5);
+    expect(await plugin.setValue('Int', 'flutter.Int', 12), isTrue);
+    expect(api.items['flutter.Int'], 12);
+    expect(await plugin.setValue('String', 'flutter.String', 'hi'), isTrue);
+    expect(api.items['flutter.String'], 'hi');
+    expect(
+        await plugin
+            .setValue('StringList', 'flutter.StringList', <String>['hi']),
+        isTrue);
+    expect(api.items['flutter.StringList'], <String>['hi']);
+  });
 
-    test('getAll', () async {
-      store = SharedPreferencesIOS();
-      testData = InMemorySharedPreferencesStore.withData(kTestValues);
-      expect(await store.getAll(), kTestValues);
-      expect(log.single.method, 'getAll');
-    });
-
-    test('remove', () async {
-      store = SharedPreferencesIOS();
-      testData = InMemorySharedPreferencesStore.withData(kTestValues);
-      expect(await store.remove('flutter.String'), true);
-      expect(await store.remove('flutter.Bool'), true);
-      expect(await store.remove('flutter.Int'), true);
-      expect(await store.remove('flutter.Double'), true);
-      expect(await testData.getAll(), <String, dynamic>{
-        'flutter.StringList': <String>['foo', 'bar'],
-      });
-
-      expect(log, hasLength(4));
-      for (final MethodCall call in log) {
-        expect(call.method, 'remove');
-      }
-    });
-
-    test('setValue', () async {
-      store = SharedPreferencesIOS();
-      expect(await testData.getAll(), isEmpty);
-      for (final String key in kTestValues.keys) {
-        final Object value = kTestValues[key]!;
-        expect(await store.setValue(key.split('.').last, key, value), true);
-      }
-      expect(await testData.getAll(), kTestValues);
-
-      expect(log, hasLength(5));
-      expect(log[0].method, 'setString');
-      expect(log[1].method, 'setBool');
-      expect(log[2].method, 'setInt');
-      expect(log[3].method, 'setDouble');
-      expect(log[4].method, 'setStringList');
-    });
-
-    test('clear', () async {
-      store = SharedPreferencesIOS();
-      testData = InMemorySharedPreferencesStore.withData(kTestValues);
-      expect(await testData.getAll(), isNotEmpty);
-      expect(await store.clear(), true);
-      expect(await testData.getAll(), isEmpty);
-      expect(log.single.method, 'clear');
-    });
+  test('setValue with unsupported type', () {
+    expect(() async {
+      await plugin.setValue('Map', 'flutter.key', <String, String>{});
+    }, throwsA(isA<PlatformException>()));
   });
 }