[pigeon] removes generated codecs if there are no custom datatypes (#2645)

diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md
index 5e32c04..1ae9408 100644
--- a/packages/pigeon/CHANGELOG.md
+++ b/packages/pigeon/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 4.2.2
+
+* Removes unneeded custom codecs for all languages.
+
 ## 4.2.1
 
 * Adds documentation comment support for Kotlin.
diff --git a/packages/pigeon/lib/cpp_generator.dart b/packages/pigeon/lib/cpp_generator.dart
index ec1b227..9c369a5 100644
--- a/packages/pigeon/lib/cpp_generator.dart
+++ b/packages/pigeon/lib/cpp_generator.dart
@@ -14,6 +14,9 @@
 const DocumentCommentSpecification _docCommentSpec =
     DocumentCommentSpecification(_commentPrefix);
 
+/// The default serializer for Flutter.
+const String _defaultCodecSerializer = 'flutter::StandardCodecSerializer';
+
 /// Options that control how C++ code will be generated.
 class CppOptions {
   /// Creates a [CppOptions] object
@@ -61,83 +64,80 @@
   }
 }
 
-String _getCodecName(Api api) => '${api.name}CodecSerializer';
+String _getCodecSerializerName(Api api) => '${api.name}CodecSerializer';
 
 const String _pointerPrefix = 'pointer';
 const String _encodablePrefix = 'encodable';
 
 void _writeCodecHeader(Indent indent, Api api, Root root) {
-  final String codecName = _getCodecName(api);
-  indent.write('class $codecName : public flutter::StandardCodecSerializer ');
+  assert(getCodecClasses(api, root).isNotEmpty);
+  final String codeSerializerName = _getCodecSerializerName(api);
+  indent.write('class $codeSerializerName : public $_defaultCodecSerializer ');
   indent.scoped('{', '};', () {
     indent.scoped(' public:', '', () {
       indent.writeln('');
       indent.format('''
-inline static $codecName& GetInstance() {
-\tstatic $codecName sInstance;
+inline static $codeSerializerName& GetInstance() {
+\tstatic $codeSerializerName sInstance;
 \treturn sInstance;
 }
 ''');
-      indent.writeln('$codecName();');
+      indent.writeln('$codeSerializerName();');
     });
-    if (getCodecClasses(api, root).isNotEmpty) {
-      indent.writeScoped(' public:', '', () {
-        indent.writeln(
-            'void WriteValue(const flutter::EncodableValue& value, flutter::ByteStreamWriter* stream) const override;');
-      });
-      indent.writeScoped(' protected:', '', () {
-        indent.writeln(
-            'flutter::EncodableValue ReadValueOfType(uint8_t type, flutter::ByteStreamReader* stream) const override;');
-      });
-    }
+    indent.writeScoped(' public:', '', () {
+      indent.writeln(
+          'void WriteValue(const flutter::EncodableValue& value, flutter::ByteStreamWriter* stream) const override;');
+    });
+    indent.writeScoped(' protected:', '', () {
+      indent.writeln(
+          'flutter::EncodableValue ReadValueOfType(uint8_t type, flutter::ByteStreamReader* stream) const override;');
+    });
   }, nestCount: 0);
 }
 
 void _writeCodecSource(Indent indent, Api api, Root root) {
-  final String codecName = _getCodecName(api);
-  indent.writeln('$codecName::$codecName() {}');
-  if (getCodecClasses(api, root).isNotEmpty) {
-    indent.write(
-        'flutter::EncodableValue $codecName::ReadValueOfType(uint8_t type, flutter::ByteStreamReader* stream) const ');
+  assert(getCodecClasses(api, root).isNotEmpty);
+  final String codeSerializerName = _getCodecSerializerName(api);
+  indent.writeln('$codeSerializerName::$codeSerializerName() {}');
+  indent.write(
+      'flutter::EncodableValue $codeSerializerName::ReadValueOfType(uint8_t type, flutter::ByteStreamReader* stream) const ');
+  indent.scoped('{', '}', () {
+    indent.write('switch (type) ');
     indent.scoped('{', '}', () {
-      indent.write('switch (type) ');
-      indent.scoped('{', '}', () {
-        for (final EnumeratedClass customClass in getCodecClasses(api, root)) {
-          indent.write('case ${customClass.enumeration}:');
-          indent.writeScoped('', '', () {
-            indent.writeln(
-                'return flutter::CustomEncodableValue(${customClass.name}(std::get<flutter::EncodableMap>(ReadValue(stream))));');
-          });
-        }
-        indent.write('default:');
+      for (final EnumeratedClass customClass in getCodecClasses(api, root)) {
+        indent.write('case ${customClass.enumeration}:');
         indent.writeScoped('', '', () {
           indent.writeln(
-              'return flutter::StandardCodecSerializer::ReadValueOfType(type, stream);');
-        }, addTrailingNewline: false);
-      });
+              'return flutter::CustomEncodableValue(${customClass.name}(std::get<flutter::EncodableMap>(ReadValue(stream))));');
+        });
+      }
+      indent.write('default:');
+      indent.writeScoped('', '', () {
+        indent.writeln(
+            'return $_defaultCodecSerializer::ReadValueOfType(type, stream);');
+      }, addTrailingNewline: false);
     });
-    indent.writeln('');
+  });
+  indent.writeln('');
+  indent.write(
+      'void $codeSerializerName::WriteValue(const flutter::EncodableValue& value, flutter::ByteStreamWriter* stream) const ');
+  indent.writeScoped('{', '}', () {
     indent.write(
-        'void $codecName::WriteValue(const flutter::EncodableValue& value, flutter::ByteStreamWriter* stream) const ');
-    indent.writeScoped('{', '}', () {
-      indent.write(
-          'if (const flutter::CustomEncodableValue* custom_value = std::get_if<flutter::CustomEncodableValue>(&value)) ');
-      indent.scoped('{', '}', () {
-        for (final EnumeratedClass customClass in getCodecClasses(api, root)) {
-          indent.write(
-              'if (custom_value->type() == typeid(${customClass.name})) ');
-          indent.scoped('{', '}', () {
-            indent.writeln('stream->WriteByte(${customClass.enumeration});');
-            indent.writeln(
-                'WriteValue(std::any_cast<${customClass.name}>(*custom_value).ToEncodableMap(), stream);');
-            indent.writeln('return;');
-          });
-        }
-      });
-      indent.writeln(
-          'flutter::StandardCodecSerializer::WriteValue(value, stream);');
+        'if (const flutter::CustomEncodableValue* custom_value = std::get_if<flutter::CustomEncodableValue>(&value)) ');
+    indent.scoped('{', '}', () {
+      for (final EnumeratedClass customClass in getCodecClasses(api, root)) {
+        indent
+            .write('if (custom_value->type() == typeid(${customClass.name})) ');
+        indent.scoped('{', '}', () {
+          indent.writeln('stream->WriteByte(${customClass.enumeration});');
+          indent.writeln(
+              'WriteValue(std::any_cast<${customClass.name}>(*custom_value).ToEncodableMap(), stream);');
+          indent.writeln('return;');
+        });
+      }
     });
-  }
+    indent.writeln('$_defaultCodecSerializer::WriteValue(value, stream);');
+  });
 }
 
 void _writeErrorOr(Indent indent,
@@ -245,7 +245,7 @@
         // TODO(gaaclarke): Find a way to be more precise with our
         // friendships.
         indent.writeln('friend class ${api.name};');
-        indent.writeln('friend class ${_getCodecName(api)};');
+        indent.writeln('friend class ${_getCodecSerializerName(api)};');
       }
       if (testFriend != null) {
         indent.writeln('friend class $testFriend;');
@@ -484,11 +484,13 @@
 void _writeHostApiSource(Indent indent, Api api, Root root) {
   assert(api.location == ApiLocation.host);
 
-  final String codecName = _getCodecName(api);
+  final String codeSerializerName = getCodecClasses(api, root).isNotEmpty
+      ? _getCodecSerializerName(api)
+      : _defaultCodecSerializer;
   indent.format('''
 /// The codec used by ${api.name}.
 const flutter::StandardMessageCodec& ${api.name}::GetCodec() {
-\treturn flutter::StandardMessageCodec::GetInstance(&$codecName::GetInstance());
+\treturn flutter::StandardMessageCodec::GetInstance(&$codeSerializerName::GetInstance());
 }
 ''');
   indent.writeln(
@@ -740,7 +742,7 @@
   }, nestCount: 0);
 }
 
-void _writeFlutterApiSource(Indent indent, Api api) {
+void _writeFlutterApiSource(Indent indent, Api api, Root root) {
   assert(api.location == ApiLocation.flutter);
   indent.writeln(
       '$_commentPrefix Generated class from Pigeon that represents Flutter messages that can be called from C++.');
@@ -750,10 +752,12 @@
     indent.writeln('this->binary_messenger_ = binary_messenger;');
   });
   indent.writeln('');
-  final String codecName = _getCodecName(api);
+  final String codeSerializerName = getCodecClasses(api, root).isNotEmpty
+      ? _getCodecSerializerName(api)
+      : _defaultCodecSerializer;
   indent.format('''
 const flutter::StandardMessageCodec& ${api.name}::GetCodec() {
-\treturn flutter::StandardMessageCodec::GetInstance(&$codecName::GetInstance());
+\treturn flutter::StandardMessageCodec::GetInstance(&$codeSerializerName::GetInstance());
 }
 ''');
   for (final Method func in api.methods) {
@@ -1081,7 +1085,9 @@
   }
 
   for (final Api api in root.apis) {
-    _writeCodecHeader(indent, api, root);
+    if (getCodecClasses(api, root).isNotEmpty) {
+      _writeCodecHeader(indent, api, root);
+    }
     indent.addln('');
     if (api.location == ApiLocation.host) {
       _writeHostApiHeader(indent, api, root);
@@ -1135,8 +1141,10 @@
   }
 
   for (final Api api in root.apis) {
-    _writeCodecSource(indent, api, root);
-    indent.addln('');
+    if (getCodecClasses(api, root).isNotEmpty) {
+      _writeCodecSource(indent, api, root);
+      indent.addln('');
+    }
     if (api.location == ApiLocation.host) {
       _writeHostApiSource(indent, api, root);
 
@@ -1158,7 +1166,7 @@
 }''');
       indent.addln('');
     } else if (api.location == ApiLocation.flutter) {
-      _writeFlutterApiSource(indent, api);
+      _writeFlutterApiSource(indent, api, root);
     }
   }
 
diff --git a/packages/pigeon/lib/dart_generator.dart b/packages/pigeon/lib/dart_generator.dart
index 4b2ff9d..70da7ca 100644
--- a/packages/pigeon/lib/dart_generator.dart
+++ b/packages/pigeon/lib/dart_generator.dart
@@ -18,6 +18,9 @@
 const DocumentCommentSpecification _docCommentSpec =
     DocumentCommentSpecification(_docCommentPrefix);
 
+/// The standard codec for Flutter, used for any non custom codecs and extended for custom codecs.
+const String _standardMessageCodec = 'StandardMessageCodec';
+
 /// Options that control how Dart code will be generated.
 class DartOptions {
   /// Constructor for DartOptions.
@@ -67,44 +70,43 @@
 ///
 /// class FooCodec extends StandardMessageCodec {...}
 void _writeCodec(Indent indent, String codecName, Api api, Root root) {
-  indent.write('class $codecName extends StandardMessageCodec ');
+  assert(getCodecClasses(api, root).isNotEmpty);
+  final Iterable<EnumeratedClass> codecClasses = getCodecClasses(api, root);
+  indent.write('class $codecName extends $_standardMessageCodec');
   indent.scoped('{', '}', () {
     indent.writeln('const $codecName();');
-    if (getCodecClasses(api, root).isNotEmpty) {
-      indent.writeln('@override');
-      indent.write('void writeValue(WriteBuffer buffer, Object? value) ');
+    indent.writeln('@override');
+    indent.write('void writeValue(WriteBuffer buffer, Object? value) ');
+    indent.scoped('{', '}', () {
+      for (final EnumeratedClass customClass in codecClasses) {
+        indent.write('if (value is ${customClass.name}) ');
+        indent.scoped('{', '} else ', () {
+          indent.writeln('buffer.putUint8(${customClass.enumeration});');
+          indent.writeln('writeValue(buffer, value.encode());');
+        });
+      }
       indent.scoped('{', '}', () {
-        for (final EnumeratedClass customClass in getCodecClasses(api, root)) {
-          indent.write('if (value is ${customClass.name}) ');
-          indent.scoped('{', '} else ', () {
-            indent.writeln('buffer.putUint8(${customClass.enumeration});');
-            indent.writeln('writeValue(buffer, value.encode());');
+        indent.writeln('super.writeValue(buffer, value);');
+      });
+    });
+    indent.writeln('@override');
+    indent.write('Object? readValueOfType(int type, ReadBuffer buffer) ');
+    indent.scoped('{', '}', () {
+      indent.write('switch (type) ');
+      indent.scoped('{', '}', () {
+        for (final EnumeratedClass customClass in codecClasses) {
+          indent.write('case ${customClass.enumeration}: ');
+          indent.writeScoped('', '', () {
+            indent.writeln(
+                'return ${customClass.name}.decode(readValue(buffer)!);');
           });
         }
-        indent.scoped('{', '}', () {
-          indent.writeln('super.writeValue(buffer, value);');
+        indent.write('default:');
+        indent.writeScoped('', '', () {
+          indent.writeln('return super.readValueOfType(type, buffer);');
         });
       });
-      indent.writeln('@override');
-      indent.write('Object? readValueOfType(int type, ReadBuffer buffer) ');
-      indent.scoped('{', '}', () {
-        indent.write('switch (type) ');
-        indent.scoped('{', '}', () {
-          for (final EnumeratedClass customClass
-              in getCodecClasses(api, root)) {
-            indent.write('case ${customClass.enumeration}: ');
-            indent.writeScoped('', '', () {
-              indent.writeln(
-                  'return ${customClass.name}.decode(readValue(buffer)!);');
-            });
-          }
-          indent.write('default:');
-          indent.writeScoped('', '', () {
-            indent.writeln('return super.readValueOfType(type, buffer);');
-          });
-        });
-      });
-    }
+    });
   });
 }
 
@@ -157,8 +159,11 @@
 /// }
 void _writeHostApi(DartOptions opt, Indent indent, Api api, Root root) {
   assert(api.location == ApiLocation.host);
-  final String codecName = _getCodecName(api);
-  _writeCodec(indent, codecName, api, root);
+  String codecName = _standardMessageCodec;
+  if (getCodecClasses(api, root).isNotEmpty) {
+    codecName = _getCodecName(api);
+    _writeCodec(indent, codecName, api, root);
+  }
   indent.addln('');
   bool first = true;
   addDocumentationComments(indent, api.documentationComments, _docCommentSpec);
@@ -169,7 +174,6 @@
 /// available for dependency injection.  If it is left null, the default
 /// BinaryMessenger will be used which routes to the host platform.
 ${api.name}({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger;
-
 final BinaryMessenger? _binaryMessenger;
 ''');
 
@@ -272,8 +276,11 @@
   bool isMockHandler = false,
 }) {
   assert(api.location == ApiLocation.flutter);
-  final String codecName = _getCodecName(api);
-  _writeCodec(indent, codecName, api, root);
+  String codecName = _standardMessageCodec;
+  if (getCodecClasses(api, root).isNotEmpty) {
+    codecName = _getCodecName(api);
+    _writeCodec(indent, codecName, api, root);
+  }
   addDocumentationComments(indent, api.documentationComments, _docCommentSpec);
 
   indent.write('abstract class ${api.name} ');
diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart
index 2d8afea..e23dc62 100644
--- a/packages/pigeon/lib/generator_tools.dart
+++ b/packages/pigeon/lib/generator_tools.dart
@@ -9,7 +9,7 @@
 import 'ast.dart';
 
 /// The current version of pigeon. This must match the version in pubspec.yaml.
-const String pigeonVersion = '4.2.1';
+const String pigeonVersion = '4.2.2';
 
 /// Read all the content from [stdin] to a String.
 String readStdin() {
diff --git a/packages/pigeon/lib/java_generator.dart b/packages/pigeon/lib/java_generator.dart
index d0f65bd..0734569 100644
--- a/packages/pigeon/lib/java_generator.dart
+++ b/packages/pigeon/lib/java_generator.dart
@@ -24,6 +24,9 @@
   blockContinuationToken: _docCommentContinuation,
 );
 
+/// The standard codec for Flutter, used for any non custom codecs and extended for custom codecs.
+const String _standardMessageCodec = 'StandardMessageCodec';
+
 /// Options that control how Java code will be generated.
 class JavaOptions {
   /// Creates a [JavaOptions] object
@@ -93,50 +96,50 @@
 /// Example:
 /// private static class FooCodec extends StandardMessageCodec {...}
 void _writeCodec(Indent indent, Api api, Root root) {
+  assert(getCodecClasses(api, root).isNotEmpty);
+  final Iterable<EnumeratedClass> codecClasses = getCodecClasses(api, root);
   final String codecName = _getCodecName(api);
-  indent.write('private static class $codecName extends StandardMessageCodec ');
+  indent
+      .write('private static class $codecName extends $_standardMessageCodec ');
   indent.scoped('{', '}', () {
     indent
         .writeln('public static final $codecName INSTANCE = new $codecName();');
     indent.writeln('private $codecName() {}');
-    if (getCodecClasses(api, root).isNotEmpty) {
-      indent.writeln('@Override');
-      indent.write(
-          'protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) ');
+    indent.writeln('@Override');
+    indent.write(
+        'protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) ');
+    indent.scoped('{', '}', () {
+      indent.write('switch (type) ');
       indent.scoped('{', '}', () {
-        indent.write('switch (type) ');
-        indent.scoped('{', '}', () {
-          for (final EnumeratedClass customClass
-              in getCodecClasses(api, root)) {
-            indent.write('case (byte)${customClass.enumeration}: ');
-            indent.writeScoped('', '', () {
-              indent.writeln(
-                  'return ${customClass.name}.fromMap((Map<String, Object>) readValue(buffer));');
-            });
-          }
-          indent.write('default:');
+        for (final EnumeratedClass customClass in codecClasses) {
+          indent.write('case (byte)${customClass.enumeration}: ');
           indent.writeScoped('', '', () {
-            indent.writeln('return super.readValueOfType(type, buffer);');
-          });
-        });
-      });
-      indent.writeln('@Override');
-      indent.write(
-          'protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) ');
-      indent.writeScoped('{', '}', () {
-        for (final EnumeratedClass customClass in getCodecClasses(api, root)) {
-          indent.write('if (value instanceof ${customClass.name}) ');
-          indent.scoped('{', '} else ', () {
-            indent.writeln('stream.write(${customClass.enumeration});');
             indent.writeln(
-                'writeValue(stream, ((${customClass.name}) value).toMap());');
+                'return ${customClass.name}.fromMap((Map<String, Object>) readValue(buffer));');
           });
         }
-        indent.scoped('{', '}', () {
-          indent.writeln('super.writeValue(stream, value);');
+        indent.write('default:');
+        indent.writeScoped('', '', () {
+          indent.writeln('return super.readValueOfType(type, buffer);');
         });
       });
-    }
+    });
+    indent.writeln('@Override');
+    indent.write(
+        'protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) ');
+    indent.writeScoped('{', '}', () {
+      for (final EnumeratedClass customClass in codecClasses) {
+        indent.write('if (value instanceof ${customClass.name}) ');
+        indent.scoped('{', '} else ', () {
+          indent.writeln('stream.write(${customClass.enumeration});');
+          indent.writeln(
+              'writeValue(stream, ((${customClass.name}) value).toMap());');
+        });
+      }
+      indent.scoped('{', '}', () {
+        indent.writeln('super.writeValue(stream, value);');
+      });
+    });
   });
 }
 
@@ -309,12 +312,17 @@
     api.methods.forEach(writeInterfaceMethod);
     indent.addln('');
     final String codecName = _getCodecName(api);
-    indent.format('''
-/** The codec used by ${api.name}. */
-static MessageCodec<Object> getCodec() {
-\treturn $codecName.INSTANCE;
-}
-''');
+    indent.writeln('/** The codec used by ${api.name}. */');
+    indent.write('static MessageCodec<Object> getCodec() ');
+    indent.scoped('{', '}', () {
+      indent.write('return ');
+      if (getCodecClasses(api, root).isNotEmpty) {
+        indent.write('$codecName.INSTANCE;');
+      } else {
+        indent.write('new $_standardMessageCodec();');
+      }
+    });
+
     indent.writeln(
         '${_docCommentPrefix}Sets up an instance of `${api.name}` to handle messages through the `binaryMessenger`.$_docCommentSuffix');
     indent.write(
@@ -341,7 +349,7 @@
 ///   }
 ///   public int add(int x, int y, Reply<int> callback) {...}
 /// }
-void _writeFlutterApi(Indent indent, Api api) {
+void _writeFlutterApi(Indent indent, Api api, Root root) {
   assert(api.location == ApiLocation.flutter);
   const List<String> generatedMessages = <String>[
     ' Generated class from Pigeon that represents Flutter messages that can be called from Java.'
@@ -361,11 +369,17 @@
       indent.writeln('void reply(T reply);');
     });
     final String codecName = _getCodecName(api);
-    indent.format('''
-static MessageCodec<Object> getCodec() {
-\treturn $codecName.INSTANCE;
-}
-''');
+    indent.writeln('/** The codec used by ${api.name}. */');
+    indent.write('static MessageCodec<Object> getCodec() ');
+    indent.scoped('{', '}', () {
+      indent.write('return ');
+      if (getCodecClasses(api, root).isNotEmpty) {
+        indent.writeln('$codecName.INSTANCE;');
+      } else {
+        indent.writeln('new $_standardMessageCodec();');
+      }
+    });
+
     for (final Method func in api.methods) {
       final String channelName = makeChannelName(api, func);
       final String returnType = func.returnType.isVoid
@@ -715,7 +729,7 @@
     if (api.location == ApiLocation.host) {
       _writeHostApi(indent, api, root);
     } else if (api.location == ApiLocation.flutter) {
-      _writeFlutterApi(indent, api);
+      _writeFlutterApi(indent, api, root);
     }
   }
 
@@ -765,8 +779,10 @@
     }
 
     for (final Api api in root.apis) {
-      _writeCodec(indent, api, root);
-      indent.addln('');
+      if (getCodecClasses(api, root).isNotEmpty) {
+        _writeCodec(indent, api, root);
+        indent.addln('');
+      }
       writeApi(api);
     }
 
diff --git a/packages/pigeon/lib/kotlin_generator.dart b/packages/pigeon/lib/kotlin_generator.dart
index a940d40..d049f86 100644
--- a/packages/pigeon/lib/kotlin_generator.dart
+++ b/packages/pigeon/lib/kotlin_generator.dart
@@ -71,48 +71,46 @@
 /// Example:
 /// private static class FooCodec extends StandardMessageCodec {...}
 void _writeCodec(Indent indent, Api api, Root root) {
+  assert(getCodecClasses(api, root).isNotEmpty);
+  final Iterable<EnumeratedClass> codecClasses = getCodecClasses(api, root);
   final String codecName = _getCodecName(api);
   indent.writeln('@Suppress("UNCHECKED_CAST")');
   indent.write('private object $codecName : StandardMessageCodec() ');
   indent.scoped('{', '}', () {
-    if (getCodecClasses(api, root).isNotEmpty) {
-      indent.write(
-          'override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? ');
+    indent.write(
+        'override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? ');
+    indent.scoped('{', '}', () {
+      indent.write('return when (type) ');
       indent.scoped('{', '}', () {
-        indent.write('return when (type) ');
-        indent.scoped('{', '}', () {
-          for (final EnumeratedClass customClass
-              in getCodecClasses(api, root)) {
-            indent.write('${customClass.enumeration}.toByte() -> ');
+        for (final EnumeratedClass customClass in codecClasses) {
+          indent.write('${customClass.enumeration}.toByte() -> ');
+          indent.scoped('{', '}', () {
+            indent.write(
+                'return (readValue(buffer) as? Map<String, Any?>)?.let ');
             indent.scoped('{', '}', () {
-              indent.write(
-                  'return (readValue(buffer) as? Map<String, Any?>)?.let ');
-              indent.scoped('{', '}', () {
-                indent.writeln('${customClass.name}.fromMap(it)');
-              });
+              indent.writeln('${customClass.name}.fromMap(it)');
             });
-          }
-          indent.writeln('else -> super.readValueOfType(type, buffer)');
-        });
+          });
+        }
+        indent.writeln('else -> super.readValueOfType(type, buffer)');
       });
+    });
 
-      indent.write(
-          'override fun writeValue(stream: ByteArrayOutputStream, value: Any?) ');
-      indent.writeScoped('{', '}', () {
-        indent.write('when (value) ');
-        indent.scoped('{', '}', () {
-          for (final EnumeratedClass customClass
-              in getCodecClasses(api, root)) {
-            indent.write('is ${customClass.name} -> ');
-            indent.scoped('{', '}', () {
-              indent.writeln('stream.write(${customClass.enumeration})');
-              indent.writeln('writeValue(stream, value.toMap())');
-            });
-          }
-          indent.writeln('else -> super.writeValue(stream, value)');
-        });
+    indent.write(
+        'override fun writeValue(stream: ByteArrayOutputStream, value: Any?) ');
+    indent.writeScoped('{', '}', () {
+      indent.write('when (value) ');
+      indent.scoped('{', '}', () {
+        for (final EnumeratedClass customClass in codecClasses) {
+          indent.write('is ${customClass.name} -> ');
+          indent.scoped('{', '}', () {
+            indent.writeln('stream.write(${customClass.enumeration})');
+            indent.writeln('writeValue(stream, value.toMap())');
+          });
+        }
+        indent.writeln('else -> super.writeValue(stream, value)');
       });
-    }
+    });
   });
 }
 
@@ -129,6 +127,8 @@
 
   final String apiName = api.name;
 
+  final bool isCustomCodec = getCodecClasses(api, root).isNotEmpty;
+
   const List<String> generatedMessages = <String>[
     ' Generated interface from Pigeon that represents a handler of messages from Flutter.'
   ];
@@ -172,8 +172,13 @@
     indent.write('companion object ');
     indent.scoped('{', '}', () {
       indent.writeln('/** The codec used by $apiName. */');
-      indent.scoped('val codec: MessageCodec<Any?> by lazy {', '}', () {
-        indent.writeln(_getCodecName(api));
+      indent.write('val codec: MessageCodec<Any?> by lazy ');
+      indent.scoped('{', '}', () {
+        if (isCustomCodec) {
+          indent.writeln(_getCodecName(api));
+        } else {
+          indent.writeln('StandardMessageCodec()');
+        }
       });
       indent.writeln(
           '/** Sets up an instance of `$apiName` to handle messages through the `binaryMessenger`. */');
@@ -182,8 +187,8 @@
           'fun setUp(binaryMessenger: BinaryMessenger, api: $apiName?) ');
       indent.scoped('{', '}', () {
         for (final Method method in api.methods) {
-          indent.write('');
-          indent.scoped('run {', '}', () {
+          indent.write('run ');
+          indent.scoped('{', '}', () {
             String? taskQueue;
             if (method.taskQueueType != TaskQueueType.serial) {
               taskQueue = 'taskQueue';
@@ -245,7 +250,7 @@
                   }
                 }, addTrailingNewline: false);
                 indent.add(' catch (exception: Error) ');
-                indent.scoped('{', '}', () {
+                indent.scoped('{', '', () {
                   indent.writeln(
                       'wrapped["${Keys.error}"] = wrapError(exception)');
                   if (method.isAsynchronous) {
@@ -257,7 +262,7 @@
                 }
               });
             }, addTrailingNewline: false);
-            indent.scoped(' else {', '}', () {
+            indent.scoped('} else {', '}', () {
               indent.writeln('channel.setMessageHandler(null)');
             });
           });
@@ -279,8 +284,10 @@
 /// class Foo(private val binaryMessenger: BinaryMessenger) {
 ///   fun add(x: Int, y: Int, callback: (Int?) -> Unit) {...}
 /// }
-void _writeFlutterApi(Indent indent, Api api) {
+void _writeFlutterApi(Indent indent, Api api, Root root) {
   assert(api.location == ApiLocation.flutter);
+  final bool isCustomCodec = getCodecClasses(api, root).isNotEmpty;
+
   const List<String> generatedMessages = <String>[
     ' Generated class from Pigeon that represents Flutter messages that can be called from Kotlin.'
   ];
@@ -296,7 +303,11 @@
       indent.writeln('/** The codec used by $apiName. */');
       indent.write('val codec: MessageCodec<Any?> by lazy ');
       indent.scoped('{', '}', () {
-        indent.writeln(_getCodecName(api));
+        if (isCustomCodec) {
+          indent.writeln(_getCodecName(api));
+        } else {
+          indent.writeln('StandardMessageCodec()');
+        }
       });
     });
 
@@ -610,12 +621,14 @@
         indent, klass.documentationComments, _docCommentSpec,
         generatorComments: generatedMessages);
 
-    indent.write('data class ${klass.name}(');
-    indent.scoped('', '', () {
+    indent.write('data class ${klass.name} ');
+    indent.scoped('(', '', () {
       for (final NamedType element in klass.fields) {
         writeField(element);
         if (klass.fields.last != element) {
           indent.addln(',');
+        } else {
+          indent.addln('');
         }
       }
     });
@@ -630,7 +643,7 @@
     if (api.location == ApiLocation.host) {
       _writeHostApi(indent, api, root);
     } else if (api.location == ApiLocation.flutter) {
-      _writeFlutterApi(indent, api);
+      _writeFlutterApi(indent, api, root);
     }
   }
 
@@ -685,8 +698,10 @@
   }
 
   for (final Api api in root.apis) {
-    _writeCodec(indent, api, root);
-    indent.addln('');
+    if (getCodecClasses(api, root).isNotEmpty) {
+      _writeCodec(indent, api, root);
+      indent.addln('');
+    }
     writeApi(api);
   }
 
diff --git a/packages/pigeon/lib/objc_generator.dart b/packages/pigeon/lib/objc_generator.dart
index af8edd4..bc6077a 100644
--- a/packages/pigeon/lib/objc_generator.dart
+++ b/packages/pigeon/lib/objc_generator.dart
@@ -265,52 +265,50 @@
 /// NSObject<FlutterMessageCodec> *FooHostApiCodecGetCodec() {...}
 void _writeCodec(
     Indent indent, String name, ObjcOptions options, Api api, Root root) {
+  assert(getCodecClasses(api, root).isNotEmpty);
+  final Iterable<EnumeratedClass> codecClasses = getCodecClasses(api, root);
   final String readerWriterName = '${name}ReaderWriter';
   final String readerName = '${name}Reader';
   final String writerName = '${name}Writer';
   indent.writeln('@interface $readerName : FlutterStandardReader');
   indent.writeln('@end');
   indent.writeln('@implementation $readerName');
-  if (getCodecClasses(api, root).isNotEmpty) {
-    indent.writeln('- (nullable id)readValueOfType:(UInt8)type ');
+  indent.writeln('- (nullable id)readValueOfType:(UInt8)type ');
+  indent.scoped('{', '}', () {
+    indent.write('switch (type) ');
     indent.scoped('{', '}', () {
-      indent.write('switch (type) ');
-      indent.scoped('{', '}', () {
-        for (final EnumeratedClass customClass in getCodecClasses(api, root)) {
-          indent.write('case ${customClass.enumeration}: ');
-          indent.writeScoped('', '', () {
-            indent.writeln(
-                'return [${_className(options.prefix, customClass.name)} fromMap:[self readValue]];');
-          });
-        }
-        indent.write('default:');
+      for (final EnumeratedClass customClass in codecClasses) {
+        indent.write('case ${customClass.enumeration}: ');
         indent.writeScoped('', '', () {
-          indent.writeln('return [super readValueOfType:type];');
+          indent.writeln(
+              'return [${_className(options.prefix, customClass.name)} fromMap:[self readValue]];');
         });
+      }
+      indent.write('default:');
+      indent.writeScoped('', '', () {
+        indent.writeln('return [super readValueOfType:type];');
       });
     });
-  }
+  });
   indent.writeln('@end');
   indent.addln('');
   indent.writeln('@interface $writerName : FlutterStandardWriter');
   indent.writeln('@end');
   indent.writeln('@implementation $writerName');
-  if (getCodecClasses(api, root).isNotEmpty) {
-    indent.writeln('- (void)writeValue:(id)value ');
-    indent.scoped('{', '}', () {
-      for (final EnumeratedClass customClass in getCodecClasses(api, root)) {
-        indent.write(
-            'if ([value isKindOfClass:[${_className(options.prefix, customClass.name)} class]]) ');
-        indent.scoped('{', '} else ', () {
-          indent.writeln('[self writeByte:${customClass.enumeration}];');
-          indent.writeln('[self writeValue:[value toMap]];');
-        });
-      }
-      indent.scoped('{', '}', () {
-        indent.writeln('[super writeValue:value];');
+  indent.writeln('- (void)writeValue:(id)value ');
+  indent.scoped('{', '}', () {
+    for (final EnumeratedClass customClass in codecClasses) {
+      indent.write(
+          'if ([value isKindOfClass:[${_className(options.prefix, customClass.name)} class]]) ');
+      indent.scoped('{', '} else ', () {
+        indent.writeln('[self writeByte:${customClass.enumeration}];');
+        indent.writeln('[self writeValue:[value toMap]];');
       });
+    }
+    indent.scoped('{', '}', () {
+      indent.writeln('[super writeValue:value];');
     });
-  }
+  });
   indent.writeln('@end');
   indent.addln('');
   indent.format('''
@@ -324,19 +322,35 @@
 \treturn [[$readerName alloc] initWithData:data];
 }
 @end
-
-NSObject<FlutterMessageCodec> *${_getCodecGetterName(options.prefix, api.name)}() {
-\tstatic dispatch_once_t sPred = 0;
-\tstatic FlutterStandardMessageCodec *sSharedObject = nil;
-\tdispatch_once(&sPred, ^{
-\t\t$readerWriterName *readerWriter = [[$readerWriterName alloc] init];
-\t\tsSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter];
-\t});
-\treturn sSharedObject;
-}
 ''');
 }
 
+void _writeCodecGetter(
+    Indent indent, String name, ObjcOptions options, Api api, Root root) {
+  final String readerWriterName = '${name}ReaderWriter';
+
+  indent.write(
+      'NSObject<FlutterMessageCodec> *${_getCodecGetterName(options.prefix, api.name)}() ');
+  indent.scoped('{', '}', () {
+    indent.writeln('static FlutterStandardMessageCodec *sSharedObject = nil;');
+    if (getCodecClasses(api, root).isNotEmpty) {
+      indent.writeln('static dispatch_once_t sPred = 0;');
+      indent.write('dispatch_once(&sPred, ^');
+      indent.scoped('{', '});', () {
+        indent.writeln(
+            '$readerWriterName *readerWriter = [[$readerWriterName alloc] init];');
+        indent.writeln(
+            'sSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter];');
+      });
+    } else {
+      indent.writeln(
+          'sSharedObject = [FlutterStandardMessageCodec sharedInstance];');
+    }
+
+    indent.writeln('return sSharedObject;');
+  });
+}
+
 String _capitalize(String str) =>
     (str.isEmpty) ? '' : str[0].toUpperCase() + str.substring(1);
 
@@ -454,14 +468,15 @@
       lastArgType = 'FlutterError *_Nullable *_Nonnull';
       lastArgName = 'error';
     }
+    final List<String> generatorComments = <String>[];
     if (!func.returnType.isNullable &&
         !func.returnType.isVoid &&
         !func.isAsynchronous) {
-      indent.writeln(
-          '$_docCommentPrefix @return `nil` only when `error != nil`.');
+      generatorComments.add(' @return `nil` only when `error != nil`.');
     }
     addDocumentationComments(
-        indent, func.documentationComments, _docCommentSpec);
+        indent, func.documentationComments, _docCommentSpec,
+        generatorComments: generatorComments);
 
     final String signature = _makeObjcSignature(
       func: func,
@@ -579,7 +594,7 @@
 
   for (final Api api in root.apis) {
     indent.writeln(
-        '${_docCommentPrefix}The codec used by ${_className(options.prefix, api.name)}.');
+        '$_docCommentPrefix The codec used by ${_className(options.prefix, api.name)}.');
     indent.writeln(
         'NSObject<FlutterMessageCodec> *${_getCodecGetterName(options.prefix, api.name)}(void);');
     indent.addln('');
@@ -638,12 +653,14 @@
     indent.inc();
     indent.writeln('initWithName:@"${makeChannelName(api, func)}"');
     indent.writeln('binaryMessenger:binaryMessenger');
-    indent.write('codec:${_getCodecGetterName(options.prefix, api.name)}()');
+    indent.write('codec:');
+    indent.add('${_getCodecGetterName(options.prefix, api.name)}()');
+
     if (taskQueue != null) {
       indent.addln('');
-      indent.writeln('taskQueue:$taskQueue];');
+      indent.addln('taskQueue:$taskQueue];');
     } else {
-      indent.writeln('];');
+      indent.addln('];');
     }
     indent.dec();
     indent.dec();
@@ -831,8 +848,8 @@
       indent.inc();
       indent.writeln('messageChannelWithName:@"${makeChannelName(api, func)}"');
       indent.writeln('binaryMessenger:self.binaryMessenger');
-      indent.writeln(
-          'codec:${_getCodecGetterName(options.prefix, api.name)}()];');
+      indent.write('codec:${_getCodecGetterName(options.prefix, api.name)}()');
+      indent.write('];');
       indent.dec();
       indent.dec();
       indent.write('[channel sendMessage:$sendArgument reply:^(id reply) ');
@@ -982,7 +999,11 @@
 
   void writeApi(Api api) {
     final String codecName = _getCodecName(options.prefix, api.name);
-    _writeCodec(indent, codecName, options, api, root);
+    if (getCodecClasses(api, root).isNotEmpty) {
+      _writeCodec(indent, codecName, options, api, root);
+      indent.addln('');
+    }
+    _writeCodecGetter(indent, codecName, options, api, root);
     indent.addln('');
     if (api.location == ApiLocation.host) {
       _writeHostApiSource(indent, options, api, root);
diff --git a/packages/pigeon/lib/swift_generator.dart b/packages/pigeon/lib/swift_generator.dart
index 7719b05..758199d 100644
--- a/packages/pigeon/lib/swift_generator.dart
+++ b/packages/pigeon/lib/swift_generator.dart
@@ -56,6 +56,7 @@
 /// private class FooHostApiCodecWriter: FlutterStandardWriter {...}
 /// private class FooHostApiCodecReaderWriter: FlutterStandardReaderWriter {...}
 void _writeCodec(Indent indent, Api api, Root root) {
+  assert(getCodecClasses(api, root).isNotEmpty);
   final String codecName = _getCodecName(api);
   final String readerWriterName = '${codecName}ReaderWriter';
   final String readerName = '${codecName}Reader';
@@ -189,8 +190,12 @@
   indent.scoped('{', '}', () {
     final String codecName = _getCodecName(api);
     indent.writeln('$_docCommentPrefix The codec used by $apiName.');
-    indent.writeln(
-        'static var codec: FlutterStandardMessageCodec { $codecName.shared }');
+    String codecArgumentString = '';
+    if (getCodecClasses(api, root).isNotEmpty) {
+      codecArgumentString = ', codec: codec';
+      indent.writeln(
+          'static var codec: FlutterStandardMessageCodec { $codecName.shared }');
+    }
     indent.writeln(
         '$_docCommentPrefix Sets up an instance of `$apiName` to handle messages through the `binaryMessenger`.');
     indent.write(
@@ -203,7 +208,7 @@
             indent, method.documentationComments, _docCommentSpec);
 
         indent.writeln(
-            'let $varChannelName = FlutterBasicMessageChannel(name: "$channelName", binaryMessenger: binaryMessenger, codec: codec)');
+            'let $varChannelName = FlutterBasicMessageChannel(name: "$channelName", binaryMessenger: binaryMessenger$codecArgumentString)');
         indent.write('if let api = api ');
         indent.scoped('{', '}', () {
           indent.write('$varChannelName.setMessageHandler ');
@@ -290,10 +295,14 @@
       indent.writeln('self.binaryMessenger = binaryMessenger');
     });
     final String codecName = _getCodecName(api);
-    indent.write('var codec: FlutterStandardMessageCodec ');
-    indent.scoped('{', '}', () {
-      indent.writeln('return $codecName.shared');
-    });
+    String codecArgumentString = '';
+    if (getCodecClasses(api, root).isNotEmpty) {
+      codecArgumentString = ', codec: codec';
+      indent.write('var codec: FlutterStandardMessageCodec ');
+      indent.scoped('{', '}', () {
+        indent.writeln('return $codecName.shared');
+      });
+    }
     for (final Method func in api.methods) {
       final String channelName = makeChannelName(api, func);
       final String returnType = func.returnType.isVoid
@@ -332,7 +341,7 @@
       indent.scoped('{', '}', () {
         const String channel = 'channel';
         indent.writeln(
-            'let $channel = FlutterBasicMessageChannel(name: "$channelName", binaryMessenger: binaryMessenger, codec: codec)');
+            'let $channel = FlutterBasicMessageChannel(name: "$channelName", binaryMessenger: binaryMessenger$codecArgumentString)');
         indent.write('$channel.sendMessage($sendArgument) ');
         if (func.returnType.isVoid) {
           indent.scoped('{ _ in', '}', () {
@@ -641,8 +650,10 @@
   }
 
   for (final Api api in root.apis) {
-    _writeCodec(indent, api, root);
-    indent.addln('');
+    if (getCodecClasses(api, root).isNotEmpty) {
+      _writeCodec(indent, api, root);
+      indent.addln('');
+    }
     writeApi(api, root);
   }
 
diff --git a/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/MultipleArityTests.swift b/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/MultipleArityTests.swift
index f70f0e9..23f3e34 100644
--- a/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/MultipleArityTests.swift
+++ b/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/MultipleArityTests.swift
@@ -1,7 +1,6 @@
 // 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 XCTest
 @testable import Runner
 
@@ -12,7 +11,7 @@
 }
 
 class MultipleArityTests: XCTestCase {
-  
+  var codec = FlutterStandardMessageCodec.sharedInstance()
   func testSimpleHost() throws {
     let binaryMessenger = MockBinaryMessenger<Int32>(codec: EnumApi2HostCodec.shared)
     MultipleArityHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: MockMultipleArityHostApi())
@@ -37,7 +36,7 @@
   }
   
   func testSimpleFlutter() throws {
-    let binaryMessenger = HandlerBinaryMessenger(codec: MultipleArityHostApiCodec.shared) { args in
+    let binaryMessenger = HandlerBinaryMessenger(codec: codec) { args in
       return (args[0] as! Int) - (args[1] as! Int)
     }
     let api = MultipleArityFlutterApi(binaryMessenger: binaryMessenger)
diff --git a/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/NullableReturnsTests.swift b/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/NullableReturnsTests.swift
index 7d8acf5..b80c891 100644
--- a/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/NullableReturnsTests.swift
+++ b/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/NullableReturnsTests.swift
@@ -1,7 +1,6 @@
 // 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 XCTest
 @testable import Runner
 
@@ -17,8 +16,9 @@
 }
 
 class NullableReturnsTests: XCTestCase {
+  var codec = FlutterStandardMessageCodec.sharedInstance()
   func testNullableParameterWithFlutterApi() {
-    let binaryMessenger = EchoBinaryMessenger(codec: NullableArgFlutterApiCodec.shared)
+    let binaryMessenger = EchoBinaryMessenger(codec: codec)
     binaryMessenger.defaultReturn = 99
     let api = NullableArgFlutterApi(binaryMessenger: binaryMessenger)
     
@@ -32,7 +32,7 @@
   
   func testNullableParameterWithHostApi() {
     let api = MockNullableArgHostApi()
-    let binaryMessenger = MockBinaryMessenger<Int32?>(codec: NullableArgHostApiCodec.shared)
+    let binaryMessenger = MockBinaryMessenger<Int32?>(codec: codec)
     let channel = "dev.flutter.pigeon.NullableArgHostApi.doit"
     
     NullableArgHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: api)
diff --git a/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/PrimitiveTests.swift b/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/PrimitiveTests.swift
index f9c6b5f..d825b00 100644
--- a/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/PrimitiveTests.swift
+++ b/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/PrimitiveTests.swift
@@ -1,7 +1,6 @@
 // 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 XCTest
 @testable import Runner
 
@@ -18,9 +17,10 @@
 }
 
 class PrimitiveTests: XCTestCase {
+  var codec = FlutterStandardMessageCodec.sharedInstance()
   
   func testIntPrimitiveHost() throws {
-    let binaryMessenger = MockBinaryMessenger<Int32>(codec: PrimitiveHostApiCodec.shared)
+    let binaryMessenger = MockBinaryMessenger<Int32>(codec: codec)
     PrimitiveHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: MockPrimitiveHostApi())
     let channelName = "dev.flutter.pigeon.PrimitiveHostApi.anInt"
     XCTAssertNotNil(binaryMessenger.handlers[channelName])
@@ -42,7 +42,7 @@
   }
   
   func testIntPrimitiveFlutter() throws {
-    let binaryMessenger = EchoBinaryMessenger(codec: PrimitiveHostApiCodec.shared)
+    let binaryMessenger = EchoBinaryMessenger(codec: codec)
     let api = PrimitiveFlutterApi(binaryMessenger: binaryMessenger)
     
     let expectation = XCTestExpectation(description: "callback")
@@ -54,7 +54,7 @@
   }
   
   func testBoolPrimitiveHost() throws {
-    let binaryMessenger = MockBinaryMessenger<Bool>(codec: PrimitiveHostApiCodec.shared)
+    let binaryMessenger = MockBinaryMessenger<Bool>(codec: codec)
     PrimitiveHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: MockPrimitiveHostApi())
     let channelName = "dev.flutter.pigeon.PrimitiveHostApi.aBool"
     XCTAssertNotNil(binaryMessenger.handlers[channelName])
@@ -76,7 +76,7 @@
   }
   
   func testBoolPrimitiveFlutter() throws {
-    let binaryMessenger = EchoBinaryMessenger(codec: PrimitiveHostApiCodec.shared)
+    let binaryMessenger = EchoBinaryMessenger(codec: codec)
     let api = PrimitiveFlutterApi(binaryMessenger: binaryMessenger)
     
     let expectation = XCTestExpectation(description: "callback")
@@ -88,7 +88,7 @@
   }
   
   func testDoublePrimitiveHost() throws {
-    let binaryMessenger = MockBinaryMessenger<Double>(codec: PrimitiveHostApiCodec.shared)
+    let binaryMessenger = MockBinaryMessenger<Double>(codec: codec)
     PrimitiveHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: MockPrimitiveHostApi())
     let channelName = "dev.flutter.pigeon.PrimitiveHostApi.aDouble"
     XCTAssertNotNil(binaryMessenger.handlers[channelName])
@@ -110,7 +110,7 @@
   }
   
   func testDoublePrimitiveFlutter() throws {
-    let binaryMessenger = EchoBinaryMessenger(codec: PrimitiveHostApiCodec.shared)
+    let binaryMessenger = EchoBinaryMessenger(codec: codec)
     let api = PrimitiveFlutterApi(binaryMessenger: binaryMessenger)
     
     let expectation = XCTestExpectation(description: "callback")
@@ -123,7 +123,7 @@
   }
   
   func testStringPrimitiveHost() throws {
-    let binaryMessenger = MockBinaryMessenger<String>(codec: PrimitiveHostApiCodec.shared)
+    let binaryMessenger = MockBinaryMessenger<String>(codec: codec)
     PrimitiveHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: MockPrimitiveHostApi())
     let channelName = "dev.flutter.pigeon.PrimitiveHostApi.aString"
     XCTAssertNotNil(binaryMessenger.handlers[channelName])
@@ -145,7 +145,7 @@
   }
   
   func testStringPrimitiveFlutter() throws {
-    let binaryMessenger = EchoBinaryMessenger(codec: PrimitiveHostApiCodec.shared)
+    let binaryMessenger = EchoBinaryMessenger(codec: codec)
     let api = PrimitiveFlutterApi(binaryMessenger: binaryMessenger)
     
     let expectation = XCTestExpectation(description: "callback")
@@ -158,7 +158,7 @@
   }
   
   func testListPrimitiveHost() throws {
-    let binaryMessenger = MockBinaryMessenger<[Int]>(codec: PrimitiveHostApiCodec.shared)
+    let binaryMessenger = MockBinaryMessenger<[Int]>(codec: codec)
     PrimitiveHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: MockPrimitiveHostApi())
     let channelName = "dev.flutter.pigeon.PrimitiveHostApi.aList"
     XCTAssertNotNil(binaryMessenger.handlers[channelName])
@@ -180,7 +180,7 @@
   }
   
   func testListPrimitiveFlutter() throws {
-    let binaryMessenger = EchoBinaryMessenger(codec: PrimitiveHostApiCodec.shared)
+    let binaryMessenger = EchoBinaryMessenger(codec: codec)
     let api = PrimitiveFlutterApi(binaryMessenger: binaryMessenger)
     
     let expectation = XCTestExpectation(description: "callback")
@@ -193,7 +193,7 @@
   }
   
   func testMapPrimitiveHost() throws {
-    let binaryMessenger = MockBinaryMessenger<[String: Int]>(codec: PrimitiveHostApiCodec.shared)
+    let binaryMessenger = MockBinaryMessenger<[String: Int]>(codec: codec)
     PrimitiveHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: MockPrimitiveHostApi())
     let channelName = "dev.flutter.pigeon.PrimitiveHostApi.aMap"
     XCTAssertNotNil(binaryMessenger.handlers[channelName])
@@ -215,7 +215,7 @@
   }
   
   func testMapPrimitiveFlutter() throws {
-    let binaryMessenger = EchoBinaryMessenger(codec: PrimitiveHostApiCodec.shared)
+    let binaryMessenger = EchoBinaryMessenger(codec: codec)
     let api = PrimitiveFlutterApi(binaryMessenger: binaryMessenger)
     
     let expectation = XCTestExpectation(description: "callback")
diff --git a/packages/pigeon/platform_tests/ios_unit_tests/ios/RunnerTests/NullableReturnsTest.m b/packages/pigeon/platform_tests/ios_unit_tests/ios/RunnerTests/NullableReturnsTest.m
index a5eef4c..3f47f70 100644
--- a/packages/pigeon/platform_tests/ios_unit_tests/ios/RunnerTests/NullableReturnsTest.m
+++ b/packages/pigeon/platform_tests/ios_unit_tests/ios/RunnerTests/NullableReturnsTest.m
@@ -33,7 +33,7 @@
 
 - (void)testNullableParameterWithFlutterApi {
   EchoBinaryMessenger *binaryMessenger =
-      [[EchoBinaryMessenger alloc] initWithCodec:NRNullableArgFlutterApiGetCodec()];
+      [[EchoBinaryMessenger alloc] initWithCodec:NRNullableArgHostApiGetCodec()];
   NRNullableArgFlutterApi *api =
       [[NRNullableArgFlutterApi alloc] initWithBinaryMessenger:binaryMessenger];
   XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml
index cb524d5..84029e2 100644
--- a/packages/pigeon/pubspec.yaml
+++ b/packages/pigeon/pubspec.yaml
@@ -2,7 +2,7 @@
 description: Code generator tool to make communication between Flutter and the host platform type-safe and easier.
 repository: https://github.com/flutter/packages/tree/main/packages/pigeon
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3Apigeon
-version: 4.2.1 # This must match the version in lib/generator_tools.dart
+version: 4.2.2 # This must match the version in lib/generator_tools.dart
 
 environment:
   sdk: ">=2.12.0 <3.0.0"
diff --git a/packages/pigeon/test/cpp_generator_test.dart b/packages/pigeon/test/cpp_generator_test.dart
index 8b36e46..cdf3876 100644
--- a/packages/pigeon/test/cpp_generator_test.dart
+++ b/packages/pigeon/test/cpp_generator_test.dart
@@ -1122,4 +1122,78 @@
       expect(code, contains('//$comment'));
     }
   });
+
+  test('doesnt create codecs if no custom datatypes', () {
+    final Root root = Root(
+      apis: <Api>[
+        Api(
+          name: 'Api',
+          location: ApiLocation.flutter,
+          methods: <Method>[
+            Method(
+              name: 'method',
+              returnType: const TypeDeclaration.voidDeclaration(),
+              arguments: <NamedType>[
+                NamedType(
+                  name: 'field',
+                  type: const TypeDeclaration(
+                    baseName: 'int',
+                    isNullable: true,
+                  ),
+                ),
+              ],
+            )
+          ],
+        )
+      ],
+      classes: <Class>[],
+      enums: <Enum>[],
+    );
+    final StringBuffer sink = StringBuffer();
+    generateCppHeader('', const CppOptions(), root, sink);
+    final String code = sink.toString();
+    expect(code, isNot(contains(' : public flutter::StandardCodecSerializer')));
+  });
+
+  test('creates custom codecs if custom datatypes present', () {
+    final Root root = Root(apis: <Api>[
+      Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[
+        Method(
+          name: 'doSomething',
+          arguments: <NamedType>[
+            NamedType(
+                type: const TypeDeclaration(
+                  baseName: 'Input',
+                  isNullable: false,
+                ),
+                name: '')
+          ],
+          returnType:
+              const TypeDeclaration(baseName: 'Output', isNullable: false),
+          isAsynchronous: true,
+        )
+      ])
+    ], classes: <Class>[
+      Class(name: 'Input', fields: <NamedType>[
+        NamedType(
+            type: const TypeDeclaration(
+              baseName: 'String',
+              isNullable: true,
+            ),
+            name: 'input')
+      ]),
+      Class(name: 'Output', fields: <NamedType>[
+        NamedType(
+            type: const TypeDeclaration(
+              baseName: 'String',
+              isNullable: true,
+            ),
+            name: 'output')
+      ])
+    ], enums: <Enum>[]);
+    final StringBuffer sink = StringBuffer();
+    generateCppHeader('', const CppOptions(), root, sink);
+    final String code = sink.toString();
+    expect(code, contains(' : public flutter::StandardCodecSerializer'));
+  });
 }
diff --git a/packages/pigeon/test/dart_generator_test.dart b/packages/pigeon/test/dart_generator_test.dart
index cf467d2..582b29e 100644
--- a/packages/pigeon/test/dart_generator_test.dart
+++ b/packages/pigeon/test/dart_generator_test.dart
@@ -1234,4 +1234,79 @@
       expect(code, contains('///$comment'));
     }
   });
+
+  test('doesnt create codecs if no custom datatypes', () {
+    final Root root = Root(
+      apis: <Api>[
+        Api(
+          name: 'Api',
+          location: ApiLocation.flutter,
+          methods: <Method>[
+            Method(
+              name: 'method',
+              returnType: const TypeDeclaration.voidDeclaration(),
+              arguments: <NamedType>[
+                NamedType(
+                  name: 'field',
+                  type: const TypeDeclaration(
+                    baseName: 'int',
+                    isNullable: true,
+                  ),
+                ),
+              ],
+            )
+          ],
+        )
+      ],
+      classes: <Class>[],
+      enums: <Enum>[],
+    );
+    final StringBuffer sink = StringBuffer();
+    generateDart(const DartOptions(), root, sink);
+    final String code = sink.toString();
+    expect(code, isNot(contains('extends StandardMessageCodec')));
+    expect(code, contains('StandardMessageCodec'));
+  });
+
+  test('creates custom codecs if custom datatypes present', () {
+    final Root root = Root(apis: <Api>[
+      Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[
+        Method(
+          name: 'doSomething',
+          arguments: <NamedType>[
+            NamedType(
+                type: const TypeDeclaration(
+                  baseName: 'Input',
+                  isNullable: false,
+                ),
+                name: '')
+          ],
+          returnType:
+              const TypeDeclaration(baseName: 'Output', isNullable: false),
+          isAsynchronous: true,
+        )
+      ])
+    ], classes: <Class>[
+      Class(name: 'Input', fields: <NamedType>[
+        NamedType(
+            type: const TypeDeclaration(
+              baseName: 'String',
+              isNullable: true,
+            ),
+            name: 'input')
+      ]),
+      Class(name: 'Output', fields: <NamedType>[
+        NamedType(
+            type: const TypeDeclaration(
+              baseName: 'String',
+              isNullable: true,
+            ),
+            name: 'output')
+      ])
+    ], enums: <Enum>[]);
+    final StringBuffer sink = StringBuffer();
+    generateDart(const DartOptions(), root, sink);
+    final String code = sink.toString();
+    expect(code, contains('extends StandardMessageCodec'));
+  });
 }
diff --git a/packages/pigeon/test/java_generator_test.dart b/packages/pigeon/test/java_generator_test.dart
index 7621eec..bbe6db8 100644
--- a/packages/pigeon/test/java_generator_test.dart
+++ b/packages/pigeon/test/java_generator_test.dart
@@ -1158,4 +1158,81 @@
           true);
     }
   });
+
+  test('doesnt create codecs if no custom datatypes', () {
+    final Root root = Root(
+      apis: <Api>[
+        Api(
+          name: 'Api',
+          location: ApiLocation.flutter,
+          methods: <Method>[
+            Method(
+              name: 'method',
+              returnType: const TypeDeclaration.voidDeclaration(),
+              arguments: <NamedType>[
+                NamedType(
+                  name: 'field',
+                  type: const TypeDeclaration(
+                    baseName: 'int',
+                    isNullable: true,
+                  ),
+                ),
+              ],
+            )
+          ],
+        )
+      ],
+      classes: <Class>[],
+      enums: <Enum>[],
+    );
+    final StringBuffer sink = StringBuffer();
+    const JavaOptions javaOptions = JavaOptions(className: 'Messages');
+    generateJava(javaOptions, root, sink);
+    final String code = sink.toString();
+    expect(code, isNot(contains(' extends StandardMessageCodec')));
+    expect(code, contains('StandardMessageCodec'));
+  });
+
+  test('creates custom codecs if custom datatypes present', () {
+    final Root root = Root(apis: <Api>[
+      Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[
+        Method(
+          name: 'doSomething',
+          arguments: <NamedType>[
+            NamedType(
+                type: const TypeDeclaration(
+                  baseName: 'Input',
+                  isNullable: false,
+                ),
+                name: '')
+          ],
+          returnType:
+              const TypeDeclaration(baseName: 'Output', isNullable: false),
+          isAsynchronous: true,
+        )
+      ])
+    ], classes: <Class>[
+      Class(name: 'Input', fields: <NamedType>[
+        NamedType(
+            type: const TypeDeclaration(
+              baseName: 'String',
+              isNullable: true,
+            ),
+            name: 'input')
+      ]),
+      Class(name: 'Output', fields: <NamedType>[
+        NamedType(
+            type: const TypeDeclaration(
+              baseName: 'String',
+              isNullable: true,
+            ),
+            name: 'output')
+      ])
+    ], enums: <Enum>[]);
+    final StringBuffer sink = StringBuffer();
+    const JavaOptions javaOptions = JavaOptions(className: 'Messages');
+    generateJava(javaOptions, root, sink);
+    final String code = sink.toString();
+    expect(code, contains(' extends StandardMessageCodec'));
+  });
 }
diff --git a/packages/pigeon/test/kotlin_generator_test.dart b/packages/pigeon/test/kotlin_generator_test.dart
index 35cd887..c9c8c6f 100644
--- a/packages/pigeon/test/kotlin_generator_test.dart
+++ b/packages/pigeon/test/kotlin_generator_test.dart
@@ -29,7 +29,7 @@
     const KotlinOptions kotlinOptions = KotlinOptions();
     generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
-    expect(code, contains('data class Foobar('));
+    expect(code, contains('data class Foobar ('));
     expect(code, contains('val field1: Long? = null'));
     expect(code, contains('fun fromMap(map: Map<String, Any?>): Foobar'));
     expect(code, contains('fun toMap(): Map<String, Any?>'));
@@ -194,8 +194,6 @@
 
     const KotlinOptions kotlinOptions = KotlinOptions();
     generateKotlin(kotlinOptions, root, sink);
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('val aBool: Boolean? = null'));
     expect(code, contains('val aInt: Long? = null'));
@@ -246,8 +244,8 @@
       ])
     ], enums: <Enum>[]);
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code,
         contains('class Api(private val binaryMessenger: BinaryMessenger)'));
@@ -283,8 +281,8 @@
       ]),
     ], enums: <Enum>[]);
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, isNot(matches('.*doSomething(.*) ->')));
     expect(code, matches('doSomething(.*)'));
@@ -319,8 +317,8 @@
       ]),
     ], enums: <Enum>[]);
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('callback: () -> Unit'));
     expect(code, contains('callback()'));
@@ -348,8 +346,8 @@
       ]),
     ], enums: <Enum>[]);
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('fun doSomething(): Output'));
     expect(code, contains('wrapped["result"] = api.doSomething()'));
@@ -379,8 +377,8 @@
       ]),
     ], enums: <Enum>[]);
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('fun doSomething(callback: (Output) -> Unit)'));
     expect(code, contains('channel.send(null)'));
@@ -399,8 +397,8 @@
       ]),
     ], enums: <Enum>[]);
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('data class Foobar'));
     expect(code, contains('val field1: List<Any?>? = null'));
@@ -419,8 +417,8 @@
       ]),
     ], enums: <Enum>[]);
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('data class Foobar'));
     expect(code, contains('val field1: Map<Any, Any?>? = null'));
@@ -457,8 +455,8 @@
       enums: <Enum>[],
     );
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('data class Outer'));
     expect(code, contains('data class Nested'));
@@ -512,8 +510,8 @@
       ])
     ], enums: <Enum>[]);
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('interface Api'));
     expect(code, contains('api.doSomething(argArg) {'));
@@ -560,8 +558,8 @@
       ])
     ], enums: <Enum>[]);
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('class Api'));
     expect(code, matches('fun doSomething.*Input.*callback.*Output.*Unit'));
@@ -593,8 +591,8 @@
       enums: <Enum>[anEnum],
     );
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('enum class Enum1(val raw: Int)'));
     expect(code, contains('ONE(0)'));
@@ -608,10 +606,10 @@
   test('header', () {
     final Root root = Root(apis: <Api>[], classes: <Class>[], enums: <Enum>[]);
     final StringBuffer sink = StringBuffer();
-    final KotlinOptions swiftOptions = KotlinOptions(
+    final KotlinOptions kotlinOptions = KotlinOptions(
       copyrightHeader: makeIterable('hello world'),
     );
-    generateKotlin(swiftOptions, root, sink);
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, startsWith('// hello world'));
   });
@@ -637,8 +635,8 @@
       enums: <Enum>[],
     );
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('data class Foobar'));
     expect(code, contains('val field1: List<Long?>'));
@@ -666,8 +664,8 @@
       enums: <Enum>[],
     );
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('data class Foobar'));
     expect(code, contains('val field1: Map<String?, String?>'));
@@ -697,8 +695,8 @@
       enums: <Enum>[],
     );
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('fun doit(arg: List<Long?>'));
   });
@@ -727,8 +725,8 @@
       enums: <Enum>[],
     );
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('fun doit(argArg: List<Long?>'));
   });
@@ -752,8 +750,8 @@
       enums: <Enum>[],
     );
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('fun doit(): List<Long?>'));
     expect(code, contains('wrapped["result"] = api.doit()'));
@@ -779,8 +777,8 @@
       enums: <Enum>[],
     );
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('fun doit(callback: (List<Long?>) -> Unit'));
     expect(code, contains('val result = it as List<Long?>'));
@@ -807,8 +805,8 @@
       ])
     ], classes: <Class>[], enums: <Enum>[]);
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('fun add(x: Long, y: Long): Long'));
     expect(code, contains('val args = message as List<Any?>'));
@@ -844,8 +842,8 @@
       ])
     ], classes: <Class>[], enums: <Enum>[]);
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('val channel = BasicMessageChannel'));
     expect(code, contains('val result = it as Long'));
@@ -872,8 +870,8 @@
       enums: <Enum>[],
     );
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('fun doit(): Long?'));
   });
@@ -896,8 +894,8 @@
       enums: <Enum>[],
     );
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('fun doit(callback: (Long?) -> Unit'));
   });
@@ -923,8 +921,8 @@
       enums: <Enum>[],
     );
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(
         code,
@@ -953,8 +951,8 @@
       enums: <Enum>[],
     );
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('fun doit(fooArg: Long?, callback: () -> Unit'));
   });
@@ -988,8 +986,8 @@
       ]),
     ], enums: <Enum>[]);
     final StringBuffer sink = StringBuffer();
-    const KotlinOptions swiftOptions = KotlinOptions();
-    generateKotlin(swiftOptions, root, sink);
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
     final String code = sink.toString();
     expect(code, contains('val input: String\n'));
   });
@@ -1070,4 +1068,81 @@
           true);
     }
   });
+
+  test('doesnt create codecs if no custom datatypes', () {
+    final Root root = Root(
+      apis: <Api>[
+        Api(
+          name: 'Api',
+          location: ApiLocation.flutter,
+          methods: <Method>[
+            Method(
+              name: 'method',
+              returnType: const TypeDeclaration.voidDeclaration(),
+              arguments: <NamedType>[
+                NamedType(
+                  name: 'field',
+                  type: const TypeDeclaration(
+                    baseName: 'int',
+                    isNullable: true,
+                  ),
+                ),
+              ],
+            )
+          ],
+        )
+      ],
+      classes: <Class>[],
+      enums: <Enum>[],
+    );
+    final StringBuffer sink = StringBuffer();
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
+    final String code = sink.toString();
+    expect(code, isNot(contains(' : StandardMessageCodec() ')));
+    expect(code, contains('StandardMessageCodec'));
+  });
+
+  test('creates custom codecs if custom datatypes present', () {
+    final Root root = Root(apis: <Api>[
+      Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[
+        Method(
+          name: 'doSomething',
+          arguments: <NamedType>[
+            NamedType(
+                type: const TypeDeclaration(
+                  baseName: 'Input',
+                  isNullable: false,
+                ),
+                name: '')
+          ],
+          returnType:
+              const TypeDeclaration(baseName: 'Output', isNullable: false),
+          isAsynchronous: true,
+        )
+      ])
+    ], classes: <Class>[
+      Class(name: 'Input', fields: <NamedType>[
+        NamedType(
+            type: const TypeDeclaration(
+              baseName: 'String',
+              isNullable: true,
+            ),
+            name: 'input')
+      ]),
+      Class(name: 'Output', fields: <NamedType>[
+        NamedType(
+            type: const TypeDeclaration(
+              baseName: 'String',
+              isNullable: true,
+            ),
+            name: 'output')
+      ])
+    ], enums: <Enum>[]);
+    final StringBuffer sink = StringBuffer();
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    generateKotlin(kotlinOptions, root, sink);
+    final String code = sink.toString();
+    expect(code, contains(' : StandardMessageCodec() '));
+  });
 }
diff --git a/packages/pigeon/test/objc_generator_test.dart b/packages/pigeon/test/objc_generator_test.dart
index ff698b3..efd177c 100644
--- a/packages/pigeon/test/objc_generator_test.dart
+++ b/packages/pigeon/test/objc_generator_test.dart
@@ -1812,4 +1812,78 @@
       expect(code, contains('///$comment'));
     }
   });
+
+  test('doesnt create codecs if no custom datatypes', () {
+    final Root root = Root(
+      apis: <Api>[
+        Api(
+          name: 'Api',
+          location: ApiLocation.flutter,
+          methods: <Method>[
+            Method(
+              name: 'method',
+              returnType: const TypeDeclaration.voidDeclaration(),
+              arguments: <NamedType>[
+                NamedType(
+                  name: 'field',
+                  type: const TypeDeclaration(
+                    baseName: 'int',
+                    isNullable: true,
+                  ),
+                ),
+              ],
+            )
+          ],
+        )
+      ],
+      classes: <Class>[],
+      enums: <Enum>[],
+    );
+    final StringBuffer sink = StringBuffer();
+    generateObjcSource(const ObjcOptions(), root, sink);
+    final String code = sink.toString();
+    expect(code, isNot(contains(' : FlutterStandardReader')));
+  });
+
+  test('creates custom codecs if custom datatypes present', () {
+    final Root root = Root(apis: <Api>[
+      Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[
+        Method(
+          name: 'doSomething',
+          arguments: <NamedType>[
+            NamedType(
+                type: const TypeDeclaration(
+                  baseName: 'Input',
+                  isNullable: false,
+                ),
+                name: '')
+          ],
+          returnType:
+              const TypeDeclaration(baseName: 'Output', isNullable: false),
+          isAsynchronous: true,
+        )
+      ])
+    ], classes: <Class>[
+      Class(name: 'Input', fields: <NamedType>[
+        NamedType(
+            type: const TypeDeclaration(
+              baseName: 'String',
+              isNullable: true,
+            ),
+            name: 'input')
+      ]),
+      Class(name: 'Output', fields: <NamedType>[
+        NamedType(
+            type: const TypeDeclaration(
+              baseName: 'String',
+              isNullable: true,
+            ),
+            name: 'output')
+      ])
+    ], enums: <Enum>[]);
+    final StringBuffer sink = StringBuffer();
+    generateObjcSource(const ObjcOptions(), root, sink);
+    final String code = sink.toString();
+    expect(code, contains(' : FlutterStandardReader'));
+  });
 }
diff --git a/packages/pigeon/test/swift_generator_test.dart b/packages/pigeon/test/swift_generator_test.dart
index c40d85a..ab0af5b 100644
--- a/packages/pigeon/test/swift_generator_test.dart
+++ b/packages/pigeon/test/swift_generator_test.dart
@@ -1020,4 +1020,80 @@
       expect(code, contains('///$comment'));
     }
   });
+
+  test('doesnt create codecs if no custom datatypes', () {
+    final Root root = Root(
+      apis: <Api>[
+        Api(
+          name: 'Api',
+          location: ApiLocation.flutter,
+          methods: <Method>[
+            Method(
+              name: 'method',
+              returnType: const TypeDeclaration.voidDeclaration(),
+              arguments: <NamedType>[
+                NamedType(
+                  name: 'field',
+                  type: const TypeDeclaration(
+                    baseName: 'int',
+                    isNullable: true,
+                  ),
+                ),
+              ],
+            )
+          ],
+        )
+      ],
+      classes: <Class>[],
+      enums: <Enum>[],
+    );
+    final StringBuffer sink = StringBuffer();
+    const SwiftOptions swiftOptions = SwiftOptions();
+    generateSwift(swiftOptions, root, sink);
+    final String code = sink.toString();
+    expect(code, isNot(contains(': FlutterStandardReader ')));
+  });
+
+  test('creates custom codecs if custom datatypes present', () {
+    final Root root = Root(apis: <Api>[
+      Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[
+        Method(
+          name: 'doSomething',
+          arguments: <NamedType>[
+            NamedType(
+                type: const TypeDeclaration(
+                  baseName: 'Input',
+                  isNullable: false,
+                ),
+                name: '')
+          ],
+          returnType:
+              const TypeDeclaration(baseName: 'Output', isNullable: false),
+          isAsynchronous: true,
+        )
+      ])
+    ], classes: <Class>[
+      Class(name: 'Input', fields: <NamedType>[
+        NamedType(
+            type: const TypeDeclaration(
+              baseName: 'String',
+              isNullable: true,
+            ),
+            name: 'input')
+      ]),
+      Class(name: 'Output', fields: <NamedType>[
+        NamedType(
+            type: const TypeDeclaration(
+              baseName: 'String',
+              isNullable: true,
+            ),
+            name: 'output')
+      ])
+    ], enums: <Enum>[]);
+    final StringBuffer sink = StringBuffer();
+    const SwiftOptions swiftOptions = SwiftOptions();
+    generateSwift(swiftOptions, root, sink);
+    final String code = sink.toString();
+    expect(code, contains(': FlutterStandardReader '));
+  });
 }