diff --git a/.ci/flutter_master.version b/.ci/flutter_master.version index e8948f8d5021..065cd8af8a31 100644 --- a/.ci/flutter_master.version +++ b/.ci/flutter_master.version @@ -1 +1 @@ -6790525ce673734ef3a913e301a7001e2f500703 +fe71cadf1959268ca5dd545863a195d78c232b74 diff --git a/.ci/flutter_stable.version b/.ci/flutter_stable.version index 7b741fa7ed37..a4fc9715437c 100644 --- a/.ci/flutter_stable.version +++ b/.ci/flutter_stable.version @@ -1 +1 @@ -2663184aa79047d0a33a14a3b607954f8fdd8730 +603104015dd692ea3403755b55d07813d5cf8965 diff --git a/.github/labeler.yml b/.github/labeler.yml index c1a7a366025d..ec925d3343e0 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -138,6 +138,11 @@ - any-glob-to-any-file: - packages/palette_generator/**/* +'p: path_parsing': + - changed-files: + - any-glob-to-any-file: + - third_party/packages/path_parsing/**/* + 'p: path_provider': - changed-files: - any-glob-to-any-file: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 79a2ba562b45..b8b866e72f34 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,7 +36,7 @@ jobs: cd $GITHUB_WORKSPACE # Checks out a copy of the repo. - name: Check out code - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: fetch-depth: 0 # Fetch all history so the tool can get all the tags to determine version. - name: Set up tools diff --git a/CODEOWNERS b/CODEOWNERS index bfdb5af89d81..0785e52ba2cb 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -46,6 +46,7 @@ packages/webview_flutter/** @bparrishMines packages/xdg_directories/** @stuartmorgan third_party/packages/cupertino_icons/** @MitchellGoodwin third_party/packages/cupertino_icons/test/goldens/** @LongCatIsLooong +third_party/packages/path_parsing/** @domesticmouse # Plugin platform implementation rules. These should stay last, since the last # matching entry takes precedence. diff --git a/README.md b/README.md index 08507abcb9f2..e256308ebee0 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ These are the packages hosted in this repository: | [metrics\_center](./packages/metrics_center/) | [![pub package](https://img.shields.io/pub/v/metrics_center.svg)](https://pub.dev/packages/metrics_center) | [![pub points](https://img.shields.io/pub/points/metrics_center)](https://pub.dev/packages/metrics_center/score) | [![popularity](https://img.shields.io/pub/popularity/metrics_center)](https://pub.dev/packages/metrics_center/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20metrics_center?label=)](https://github.com/flutter/flutter/labels/p%3A%20metrics_center) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20metrics_center?label=)](https://github.com/flutter/packages/labels/p%3A%20metrics_center) | | [multicast\_dns](./packages/multicast_dns/) | [![pub package](https://img.shields.io/pub/v/multicast_dns.svg)](https://pub.dev/packages/multicast_dns) | [![pub points](https://img.shields.io/pub/points/multicast_dns)](https://pub.dev/packages/multicast_dns/score) | [![popularity](https://img.shields.io/pub/popularity/multicast_dns)](https://pub.dev/packages/multicast_dns/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20multicast_dns?label=)](https://github.com/flutter/flutter/labels/p%3A%20multicast_dns) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20multicast_dns?label=)](https://github.com/flutter/packages/labels/p%3A%20multicast_dns) | | [palette\_generator](./packages/palette_generator/) | [![pub package](https://img.shields.io/pub/v/palette_generator.svg)](https://pub.dev/packages/palette_generator) | [![pub points](https://img.shields.io/pub/points/palette_generator)](https://pub.dev/packages/palette_generator/score) | [![popularity](https://img.shields.io/pub/popularity/palette_generator)](https://pub.dev/packages/palette_generator/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20palette_generator?label=)](https://github.com/flutter/flutter/labels/p%3A%20palette_generator) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20palette_generator?label=)](https://github.com/flutter/packages/labels/p%3A%20palette_generator) | +| [path\_parsing](./third_party/packages/path_parsing/) | [![pub package](https://img.shields.io/pub/v/path_parsing.svg)](https://pub.dev/packages/path_parsing) | [![pub points](https://img.shields.io/pub/points/path_parsing)](https://pub.dev/packages/path_parsing/score) | [![popularity](https://img.shields.io/pub/popularity/path_parsing)](https://pub.dev/packages/path_parsing/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20path_parsing?label=)](https://github.com/flutter/flutter/labels/p%3A%20path_parsing) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20path_parsing?label=)](https://github.com/flutter/packages/labels/p%3A%20path_parsing) | | [path\_provider](./packages/path_provider/) | [![pub package](https://img.shields.io/pub/v/path_provider.svg)](https://pub.dev/packages/path_provider) | [![pub points](https://img.shields.io/pub/points/path_provider)](https://pub.dev/packages/path_provider/score) | [![popularity](https://img.shields.io/pub/popularity/path_provider)](https://pub.dev/packages/path_provider/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20path_provider?label=)](https://github.com/flutter/flutter/labels/p%3A%20path_provider) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20path_provider?label=)](https://github.com/flutter/packages/labels/p%3A%20path_provider) | | [pigeon](./packages/pigeon/) | [![pub package](https://img.shields.io/pub/v/pigeon.svg)](https://pub.dev/packages/pigeon) | [![pub points](https://img.shields.io/pub/points/pigeon)](https://pub.dev/packages/pigeon/score) | [![popularity](https://img.shields.io/pub/popularity/pigeon)](https://pub.dev/packages/pigeon/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20pigeon?label=)](https://github.com/flutter/flutter/labels/p%3A%20pigeon) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20pigeon?label=)](https://github.com/flutter/packages/labels/p%3A%20pigeon) | | [pointer\_interceptor](./packages/pointer_interceptor/) | [![pub package](https://img.shields.io/pub/v/pointer_interceptor.svg)](https://pub.dev/packages/pointer_interceptor) | [![pub points](https://img.shields.io/pub/points/pointer_interceptor)](https://pub.dev/packages/pointer_interceptor/score) | [![popularity](https://img.shields.io/pub/popularity/pointer_interceptor)](https://pub.dev/packages/pointer_interceptor/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20pointer_interceptor?label=)](https://github.com/flutter/flutter/labels/p%3A%20pointer_interceptor) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20pointer_interceptor?label=)](https://github.com/flutter/packages/labels/p%3A%20pointer_interceptor) | diff --git a/analysis_options.yaml b/analysis_options.yaml index 05f98247f13a..496ddf31bf76 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -48,7 +48,6 @@ linter: - avoid_init_to_null - avoid_js_rounded_ints # - avoid_multiple_declarations_per_line # seems to be a stylistic choice we don't subscribe to - - avoid_null_checks_in_equality_operators # - avoid_positional_boolean_parameters # would have been nice to enable this but by now there's too many places that break it - avoid_print # - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356) @@ -219,7 +218,6 @@ linter: - unnecessary_to_list_in_spreads - unreachable_from_main - unrelated_type_equality_checks - - unsafe_html - use_build_context_synchronously - use_colored_box # - use_decorated_box # leads to bugs: DecoratedBox and Container are not equivalent (Container inserts extra padding) diff --git a/packages/camera/camera/example/integration_test/camera_test.dart b/packages/camera/camera/example/integration_test/camera_test.dart index e1fe14a6132e..1c5c8526c733 100644 --- a/packages/camera/camera/example/integration_test/camera_test.dart +++ b/packages/camera/camera/example/integration_test/camera_test.dart @@ -13,6 +13,10 @@ import 'package:integration_test/integration_test.dart'; import 'package:path_provider/path_provider.dart'; import 'package:video_player/video_player.dart'; +// Skip due to video_player error. +// See https://github.com/flutter/flutter/issues/157181 +bool skipFor157181 = Platform.isAndroid; + void main() { late Directory testDir; @@ -177,7 +181,7 @@ void main() { await videoController.dispose(); expect(duration, lessThan(recordingTime)); - }); + }, skip: skipFor157181); testWidgets('Pause and resume video recording', (WidgetTester tester) async { final List cameras = await availableCameras(); @@ -225,7 +229,7 @@ void main() { await videoController.dispose(); expect(duration, lessThan(recordingTime - timePaused)); - }, skip: !Platform.isAndroid); + }, skip: !Platform.isAndroid || skipFor157181); testWidgets( 'Android image streaming', diff --git a/packages/camera/camera_android/CHANGELOG.md b/packages/camera/camera_android/CHANGELOG.md index 72bdb025af99..c844cc61abbf 100644 --- a/packages/camera/camera_android/CHANGELOG.md +++ b/packages/camera/camera_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.10.9+16 + +* Updates annotations lib to 1.9.0. + ## 0.10.9+15 * Converts Dart to native platform calls to Pigeon. diff --git a/packages/camera/camera_android/android/build.gradle b/packages/camera/camera_android/android/build.gradle index 23fe2c6d4b9b..cbe399571dcd 100644 --- a/packages/camera/camera_android/android/build.gradle +++ b/packages/camera/camera_android/android/build.gradle @@ -66,7 +66,7 @@ buildFeatures { } dependencies { - implementation 'androidx.annotation:annotation:1.8.2' + implementation 'androidx.annotation:annotation:1.9.0' testImplementation 'junit:junit:4.13.2' testImplementation 'org.mockito:mockito-inline:5.0.0' testImplementation 'androidx.test:core:1.4.0' diff --git a/packages/camera/camera_android/pubspec.yaml b/packages/camera/camera_android/pubspec.yaml index d666175eaa5d..6bc18c3c7c63 100644 --- a/packages/camera/camera_android/pubspec.yaml +++ b/packages/camera/camera_android/pubspec.yaml @@ -3,7 +3,7 @@ description: Android implementation of the camera plugin. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.10.9+15 +version: 0.10.9+16 environment: sdk: ^3.5.0 diff --git a/packages/camera/camera_android_camerax/example/integration_test/integration_test.dart b/packages/camera/camera_android_camerax/example/integration_test/integration_test.dart index e733e1a36d6a..5da28d229e73 100644 --- a/packages/camera/camera_android_camerax/example/integration_test/integration_test.dart +++ b/packages/camera/camera_android_camerax/example/integration_test/integration_test.dart @@ -15,6 +15,10 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:video_player/video_player.dart'; +// Skip due to video_player error. +// See https://github.com/flutter/flutter/issues/157181 +const bool skipFor157181 = true; + void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); @@ -210,7 +214,7 @@ void main() { await videoController.dispose(); expect(duration, lessThan(postStopTime)); - }); + }, skip: skipFor157181); testWidgets('Pause and resume video recording', (WidgetTester tester) async { final List cameras = await availableCameras(); @@ -255,5 +259,5 @@ void main() { await videoController.dispose(); expect(duration, lessThan(recordingTime - timePaused)); - }); + }, skip: skipFor157181); } diff --git a/packages/espresso/example/android/app/build.gradle b/packages/espresso/example/android/app/build.gradle index be165715ca28..84b682fdb760 100644 --- a/packages/espresso/example/android/app/build.gradle +++ b/packages/espresso/example/android/app/build.gradle @@ -36,7 +36,6 @@ android { versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - multiDexEnabled true } buildTypes { diff --git a/packages/file_selector/file_selector_android/CHANGELOG.md b/packages/file_selector/file_selector_android/CHANGELOG.md index 5117a91fa786..8c1f93d36d32 100644 --- a/packages/file_selector/file_selector_android/CHANGELOG.md +++ b/packages/file_selector/file_selector_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.1+10 + +* Bumps androidx.annotation:annotation from 1.8.2 to 1.9.0. + ## 0.5.1+9 * Updates Java compatibility version to 11. diff --git a/packages/file_selector/file_selector_android/android/build.gradle b/packages/file_selector/file_selector_android/android/build.gradle index 59682ba6ada9..144e667a2d63 100644 --- a/packages/file_selector/file_selector_android/android/build.gradle +++ b/packages/file_selector/file_selector_android/android/build.gradle @@ -35,7 +35,7 @@ android { } dependencies { - implementation 'androidx.annotation:annotation:1.8.2' + implementation 'androidx.annotation:annotation:1.9.0' testImplementation 'junit:junit:4.13.2' testImplementation 'org.mockito:mockito-inline:5.1.0' testImplementation 'androidx.test:core:1.3.0' diff --git a/packages/file_selector/file_selector_android/pubspec.yaml b/packages/file_selector/file_selector_android/pubspec.yaml index e439bc266b16..389fa903eb0b 100644 --- a/packages/file_selector/file_selector_android/pubspec.yaml +++ b/packages/file_selector/file_selector_android/pubspec.yaml @@ -2,7 +2,7 @@ name: file_selector_android description: Android implementation of the file_selector package. repository: https://github.com/flutter/packages/tree/main/packages/file_selector/file_selector_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22 -version: 0.5.1+9 +version: 0.5.1+10 environment: sdk: ^3.5.0 diff --git a/packages/flutter_markdown/CHANGELOG.md b/packages/flutter_markdown/CHANGELOG.md index dba9cb958789..002d6d150abd 100644 --- a/packages/flutter_markdown/CHANGELOG.md +++ b/packages/flutter_markdown/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.7.4+1 + +* Makes it so that custom blocks are not limited to being a Column or + SizedBox. + ## 0.7.4 * Makes paragraphs in blockquotes soft-wrap like a normal `
` instead of hard-wrapping like a `
` block.
diff --git a/packages/flutter_markdown/lib/src/builder.dart b/packages/flutter_markdown/lib/src/builder.dart
index 3a0f4b15e993..ea9af16acfbe 100644
--- a/packages/flutter_markdown/lib/src/builder.dart
+++ b/packages/flutter_markdown/lib/src/builder.dart
@@ -383,20 +383,29 @@ class MarkdownBuilder implements md.NodeVisitor {
       _addAnonymousBlockIfNeeded();
 
       final _BlockElement current = _blocks.removeLast();
-      Widget child;
 
-      if (current.children.isNotEmpty) {
-        child = Column(
-          mainAxisSize: MainAxisSize.min,
-          crossAxisAlignment: fitContent
-              ? CrossAxisAlignment.start
-              : CrossAxisAlignment.stretch,
-          children: current.children,
-        );
-      } else {
-        child = const SizedBox();
+      Widget defaultChild() {
+        if (current.children.isNotEmpty) {
+          return Column(
+            mainAxisSize: MainAxisSize.min,
+            crossAxisAlignment: fitContent
+                ? CrossAxisAlignment.start
+                : CrossAxisAlignment.stretch,
+            children: current.children,
+          );
+        } else {
+          return const SizedBox();
+        }
       }
 
+      Widget child = builders[tag]?.visitElementAfterWithContext(
+            delegate.context,
+            element,
+            styleSheet.styles[tag],
+            _inlines.isNotEmpty ? _inlines.last.style : null,
+          ) ??
+          defaultChild();
+
       if (_isListTag(tag)) {
         assert(_listIndents.isNotEmpty);
         _listIndents.removeLast();
diff --git a/packages/flutter_markdown/pubspec.yaml b/packages/flutter_markdown/pubspec.yaml
index f0ac1fd83533..5f743a8b032a 100644
--- a/packages/flutter_markdown/pubspec.yaml
+++ b/packages/flutter_markdown/pubspec.yaml
@@ -4,7 +4,7 @@ description: A Markdown renderer for Flutter. Create rich text output,
   formatted with simple Markdown tags.
 repository: https://github.com/flutter/packages/tree/main/packages/flutter_markdown
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+flutter_markdown%22
-version: 0.7.4
+version: 0.7.4+1
 
 environment:
   sdk: ^3.3.0
diff --git a/packages/flutter_markdown/test/custom_syntax_test.dart b/packages/flutter_markdown/test/custom_syntax_test.dart
index 28d55cdfd0b5..8dc0c806e51f 100644
--- a/packages/flutter_markdown/test/custom_syntax_test.dart
+++ b/packages/flutter_markdown/test/custom_syntax_test.dart
@@ -59,6 +59,35 @@ void defineTests() {
       },
     );
 
+    testWidgets(
+      'Block with custom tag',
+      (WidgetTester tester) async {
+        const String textBefore = 'Before ';
+        const String textAfter = ' After';
+        const String blockContent = 'Custom content rendered in a ColoredBox';
+
+        await tester.pumpWidget(
+          boilerplate(
+            Markdown(
+              data:
+                  '$textBefore\n{{custom}}\n$blockContent\n{{/custom}}\n$textAfter',
+              extensionSet: md.ExtensionSet.none,
+              blockSyntaxes: [CustomTagBlockSyntax()],
+              builders: {
+                'custom': CustomTagBlockBuilder(),
+              },
+            ),
+          ),
+        );
+
+        final ColoredBox container =
+            tester.widgetList(find.byType(ColoredBox)).first as ColoredBox;
+        expect(container.color, Colors.red);
+        expect(container.child, isInstanceOf());
+        expect((container.child! as Text).data, blockContent);
+      },
+    );
+
     testWidgets(
       'link for wikistyle',
       (WidgetTester tester) async {
@@ -380,3 +409,54 @@ class NoteSyntax extends md.BlockSyntax {
   @override
   RegExp get pattern => RegExp(r'^\[!NOTE] ');
 }
+
+class CustomTagBlockBuilder extends MarkdownElementBuilder {
+  @override
+  bool isBlockElement() => true;
+
+  @override
+  Widget visitElementAfterWithContext(
+    BuildContext context,
+    md.Element element,
+    TextStyle? preferredStyle,
+    TextStyle? parentStyle,
+  ) {
+    if (element.tag == 'custom') {
+      final String content = element.attributes['content']!;
+      return ColoredBox(
+          color: Colors.red, child: Text(content, style: preferredStyle));
+    }
+    return const SizedBox.shrink();
+  }
+}
+
+class CustomTagBlockSyntax extends md.BlockSyntax {
+  @override
+  bool canParse(md.BlockParser parser) {
+    return parser.current.content.startsWith('{{custom}}');
+  }
+
+  @override
+  RegExp get pattern => RegExp(r'\{\{custom\}\}([\s\S]*?)\{\{/custom\}\}');
+
+  @override
+  md.Node parse(md.BlockParser parser) {
+    parser.advance();
+
+    final StringBuffer buffer = StringBuffer();
+    while (
+        !parser.current.content.startsWith('{{/custom}}') && !parser.isDone) {
+      buffer.writeln(parser.current.content);
+      parser.advance();
+    }
+
+    if (!parser.isDone) {
+      parser.advance();
+    }
+
+    final String content = buffer.toString().trim();
+    final md.Element element = md.Element.empty('custom');
+    element.attributes['content'] = content;
+    return element;
+  }
+}
diff --git a/packages/google_maps_flutter/google_maps_flutter/example/android/app/build.gradle b/packages/google_maps_flutter/google_maps_flutter/example/android/app/build.gradle
index a1ea94ae55cd..18969013153b 100644
--- a/packages/google_maps_flutter/google_maps_flutter/example/android/app/build.gradle
+++ b/packages/google_maps_flutter/google_maps_flutter/example/android/app/build.gradle
@@ -32,7 +32,6 @@ android {
         applicationId "io.flutter.plugins.googlemapsexample"
         minSdkVersion 20
         targetSdkVersion 28
-        multiDexEnabled true
         versionCode flutterVersionCode.toInteger()
         versionName flutterVersionName
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/packages/google_maps_flutter/google_maps_flutter_android/example/android/app/build.gradle b/packages/google_maps_flutter/google_maps_flutter_android/example/android/app/build.gradle
index fc357ff0e1ec..8107f238eb47 100644
--- a/packages/google_maps_flutter/google_maps_flutter_android/example/android/app/build.gradle
+++ b/packages/google_maps_flutter/google_maps_flutter_android/example/android/app/build.gradle
@@ -33,7 +33,6 @@ android {
         applicationId "io.flutter.plugins.googlemapsexample"
         minSdkVersion flutter.minSdkVersion
         targetSdkVersion 34
-        multiDexEnabled true
         versionCode flutterVersionCode.toInteger()
         versionName flutterVersionName
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart
index b8ec01d3c111..f6af32046ccd 100644
--- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart
+++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart
@@ -258,7 +258,6 @@ gmaps.InfoWindowOptions? _infoWindowOptionsFromMarker(Marker marker) {
       // XSS attacks through the contents of the marker InfoWindow.
       // See: https://pub.dev/documentation/sanitize_html/latest/sanitize_html/sanitizeHtml.html
       // See: b/159137885, b/159598165
-      // ignore: unsafe_html
       snippet.innerHTMLString = sanitizeHtml(markerSnippet);
     }
 
diff --git a/packages/google_sign_in/google_sign_in/example/android/app/build.gradle b/packages/google_sign_in/google_sign_in/example/android/app/build.gradle
index 422b58cc5199..0251b4794a29 100644
--- a/packages/google_sign_in/google_sign_in/example/android/app/build.gradle
+++ b/packages/google_sign_in/google_sign_in/example/android/app/build.gradle
@@ -33,7 +33,6 @@ android {
         applicationId "io.flutter.plugins.googlesigninexample"
         minSdkVersion flutter.minSdkVersion
         targetSdkVersion 28
-        multiDexEnabled true
         versionCode flutterVersionCode.toInteger()
         versionName flutterVersionName
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/packages/google_sign_in/google_sign_in_android/example/android/app/build.gradle b/packages/google_sign_in/google_sign_in_android/example/android/app/build.gradle
index a92aa744a44c..867de3fd0ac3 100644
--- a/packages/google_sign_in/google_sign_in_android/example/android/app/build.gradle
+++ b/packages/google_sign_in/google_sign_in_android/example/android/app/build.gradle
@@ -33,7 +33,6 @@ android {
         applicationId "io.flutter.plugins.googlesigninexample"
         minSdkVersion flutter.minSdkVersion
         targetSdkVersion 34
-        multiDexEnabled true
         versionCode flutterVersionCode.toInteger()
         versionName flutterVersionName
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/packages/image_picker/image_picker/example/android/app/build.gradle b/packages/image_picker/image_picker/example/android/app/build.gradle
index e72b68977644..f11653b7fa1e 100755
--- a/packages/image_picker/image_picker/example/android/app/build.gradle
+++ b/packages/image_picker/image_picker/example/android/app/build.gradle
@@ -34,7 +34,6 @@ android {
         applicationId "io.flutter.plugins.imagepicker.example"
         minSdkVersion flutter.minSdkVersion
         targetSdkVersion 28
-        multiDexEnabled true
         versionCode flutterVersionCode.toInteger()
         versionName flutterVersionName
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/packages/image_picker/image_picker_android/CHANGELOG.md b/packages/image_picker/image_picker_android/CHANGELOG.md
index 8dd98f1e099a..7616f8f6dce4 100644
--- a/packages/image_picker/image_picker_android/CHANGELOG.md
+++ b/packages/image_picker/image_picker_android/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.8.12+17
+
+* Bumps androidx.annotation:annotation from 1.8.2 to 1.9.0.
+
 ## 0.8.12+16
 
 * Updates Pigeon for non-nullable collection type support.
diff --git a/packages/image_picker/image_picker_android/android/build.gradle b/packages/image_picker/image_picker_android/android/build.gradle
index 729ff82d46fd..e1d46ee3340c 100644
--- a/packages/image_picker/image_picker_android/android/build.gradle
+++ b/packages/image_picker/image_picker_android/android/build.gradle
@@ -36,7 +36,7 @@ android {
     }
     dependencies {
         implementation 'androidx.core:core:1.13.1'
-        implementation 'androidx.annotation:annotation:1.8.2'
+        implementation 'androidx.annotation:annotation:1.9.0'
         implementation 'androidx.exifinterface:exifinterface:1.3.7'
         implementation 'androidx.activity:activity:1.9.2'
 
diff --git a/packages/image_picker/image_picker_android/example/android/app/build.gradle b/packages/image_picker/image_picker_android/example/android/app/build.gradle
index 9582952de9f3..8d1665a9de7e 100755
--- a/packages/image_picker/image_picker_android/example/android/app/build.gradle
+++ b/packages/image_picker/image_picker_android/example/android/app/build.gradle
@@ -34,7 +34,6 @@ android {
         applicationId "io.flutter.plugins.imagepicker.example"
         minSdkVersion flutter.minSdkVersion
         targetSdkVersion 34
-        multiDexEnabled true
         versionCode flutterVersionCode.toInteger()
         versionName flutterVersionName
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/packages/image_picker/image_picker_android/pubspec.yaml b/packages/image_picker/image_picker_android/pubspec.yaml
index 7aa133de61ec..605dc0c1585a 100755
--- a/packages/image_picker/image_picker_android/pubspec.yaml
+++ b/packages/image_picker/image_picker_android/pubspec.yaml
@@ -2,7 +2,7 @@ name: image_picker_android
 description: Android implementation of the image_picker plugin.
 repository: https://github.com/flutter/packages/tree/main/packages/image_picker/image_picker_android
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22
-version: 0.8.12+16
+version: 0.8.12+17
 
 environment:
   sdk: ^3.5.0
diff --git a/packages/image_picker/image_picker_for_web/example/integration_test/image_resizer_test.dart b/packages/image_picker/image_picker_for_web/example/integration_test/image_resizer_test.dart
index dc01ef6d1972..33f397a8c791 100644
--- a/packages/image_picker/image_picker_for_web/example/integration_test/image_resizer_test.dart
+++ b/packages/image_picker/image_picker_for_web/example/integration_test/image_resizer_test.dart
@@ -11,7 +11,6 @@ import 'package:flutter_test/flutter_test.dart';
 import 'package:image_picker_for_web/src/image_resizer.dart';
 import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
 import 'package:integration_test/integration_test.dart';
-import 'package:web/helpers.dart';
 import 'package:web/web.dart' as web;
 
 //This is a sample 10x10 png image
@@ -136,5 +135,5 @@ web.Blob _base64ToBlob(String data) {
     n--;
   }
 
-  return Blob([u8arr.toJS].toJS);
+  return web.Blob([u8arr.toJS].toJS);
 }
diff --git a/packages/image_picker/image_picker_for_web/lib/src/image_resizer.dart b/packages/image_picker/image_picker_for_web/lib/src/image_resizer.dart
index 7b32a451b67d..8cba8cfe91de 100644
--- a/packages/image_picker/image_picker_for_web/lib/src/image_resizer.dart
+++ b/packages/image_picker/image_picker_for_web/lib/src/image_resizer.dart
@@ -8,7 +8,6 @@ import 'dart:math';
 import 'dart:ui';
 
 import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
-import 'package:web/helpers.dart';
 import 'package:web/web.dart' as web;
 
 import 'image_resizer_utils.dart';
@@ -48,7 +47,6 @@ class ImageResizer {
         Completer();
     final web.HTMLImageElement imageElement = web.HTMLImageElement();
     imageElement
-      // ignore: unsafe_html
       ..src = blobUrl
       ..onLoad.listen((web.Event event) {
         imageLoadCompleter.complete(imageElement);
diff --git a/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md b/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md
index 64b82888c0ff..e3084fe05632 100644
--- a/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md
+++ b/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.3.6+11
+
+* Bumps androidx.annotation:annotation from 1.8.2 to 1.9.0.
+
 ## 0.3.6+10
 
 * Updates Pigeon for non-nullable collection type support.
diff --git a/packages/in_app_purchase/in_app_purchase_android/android/build.gradle b/packages/in_app_purchase/in_app_purchase_android/android/build.gradle
index 202915228446..7a790d8d8406 100644
--- a/packages/in_app_purchase/in_app_purchase_android/android/build.gradle
+++ b/packages/in_app_purchase/in_app_purchase_android/android/build.gradle
@@ -59,7 +59,7 @@ android {
 }
 
 dependencies {
-    implementation 'androidx.annotation:annotation:1.8.2'
+    implementation 'androidx.annotation:annotation:1.9.0'
     implementation 'com.android.billingclient:billing:6.2.0'
     testImplementation 'junit:junit:4.13.2'
     testImplementation 'org.json:json:20240303'
diff --git a/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml b/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml
index e376efe6fc27..dfd6878462d8 100644
--- a/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml
+++ b/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml
@@ -2,7 +2,7 @@ name: in_app_purchase_android
 description: An implementation for the Android platform of the Flutter `in_app_purchase` plugin. This uses the Android BillingClient APIs.
 repository: https://github.com/flutter/packages/tree/main/packages/in_app_purchase/in_app_purchase_android
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22
-version: 0.3.6+10
+version: 0.3.6+11
 
 environment:
   sdk: ^3.5.0
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md b/packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md
index 1fb5e1bb97d8..e34d332e942f 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md
+++ b/packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md
@@ -1,10 +1,14 @@
+## 0.3.18+3
+
+* Updates Pigeon for non-nullable collection type support.
+
 ## 0.3.18+2
 
 * Adds support for StoreKit2's `purchase` and `transactions`
 
 ## 0.3.18+1
 
-* Adds support for StoreKit2's `canMakePayments` and `products` 
+* Adds support for StoreKit2's `canMakePayments` and `products`
 
 ## 0.3.18
 
@@ -53,7 +57,7 @@
 
 ## 0.3.12
 
-* Converts `refreshReceipt()`, `startObservingPaymentQueue()`, `stopObservingPaymentQueue()`, 
+* Converts `refreshReceipt()`, `startObservingPaymentQueue()`, `stopObservingPaymentQueue()`,
 `registerPaymentQueueDelegate()`, `removePaymentQueueDelegate()`, `showPriceConsentIfNeeded()` to pigeon.
 
 ## 0.3.11
@@ -80,7 +84,7 @@
 
 ## 0.3.7
 
-* Adds `Future storefront()` in SKPaymentQueueWrapper class. 
+* Adds `Future storefront()` in SKPaymentQueueWrapper class.
 
 ## 0.3.6+7
 
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAObjectTranslator.h b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAObjectTranslator.h
index ffb0f1fe9588..bca07a586535 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAObjectTranslator.h
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAObjectTranslator.h
@@ -57,33 +57,33 @@ NS_ASSUME_NONNULL_BEGIN
                                                   withError:(NSString *_Nullable *_Nullable)error
     API_AVAILABLE(ios(12.2));
 
-+ (nullable SKPaymentTransactionMessage *)convertTransactionToPigeon:
++ (nullable FIASKPaymentTransactionMessage *)convertTransactionToPigeon:
     (nullable SKPaymentTransaction *)transaction;
 
-+ (nullable SKStorefrontMessage *)convertStorefrontToPigeon:(nullable SKStorefront *)storefront
++ (nullable FIASKStorefrontMessage *)convertStorefrontToPigeon:(nullable SKStorefront *)storefront
     API_AVAILABLE(ios(13.0));
 
-+ (nullable SKPaymentDiscountMessage *)convertPaymentDiscountToPigeon:
++ (nullable FIASKPaymentDiscountMessage *)convertPaymentDiscountToPigeon:
     (nullable SKPaymentDiscount *)discount API_AVAILABLE(ios(12.2));
 
-+ (nullable SKPaymentMessage *)convertPaymentToPigeon:(nullable SKPayment *)payment
++ (nullable FIASKPaymentMessage *)convertPaymentToPigeon:(nullable SKPayment *)payment
     API_AVAILABLE(ios(12.2));
 
-+ (nullable SKErrorMessage *)convertSKErrorToPigeon:(nullable NSError *)error;
++ (nullable FIASKErrorMessage *)convertSKErrorToPigeon:(nullable NSError *)error;
 
-+ (nullable SKProductsResponseMessage *)convertProductsResponseToPigeon:
++ (nullable FIASKProductsResponseMessage *)convertProductsResponseToPigeon:
     (nullable SKProductsResponse *)payment;
 
-+ (nullable SKProductMessage *)convertProductToPigeon:(nullable SKProduct *)product
++ (nullable FIASKProductMessage *)convertProductToPigeon:(nullable SKProduct *)product
     API_AVAILABLE(ios(12.2));
 
-+ (nullable SKProductDiscountMessage *)convertProductDiscountToPigeon:
++ (nullable FIASKProductDiscountMessage *)convertProductDiscountToPigeon:
     (nullable SKProductDiscount *)productDiscount API_AVAILABLE(ios(12.2));
 
-+ (nullable SKPriceLocaleMessage *)convertNSLocaleToPigeon:(nullable NSLocale *)locale
++ (nullable FIASKPriceLocaleMessage *)convertNSLocaleToPigeon:(nullable NSLocale *)locale
     API_AVAILABLE(ios(12.2));
 
-+ (nullable SKProductSubscriptionPeriodMessage *)convertSKProductSubscriptionPeriodToPigeon:
++ (nullable FIASKProductSubscriptionPeriodMessage *)convertSKProductSubscriptionPeriodToPigeon:
     (nullable SKProductSubscriptionPeriod *)period API_AVAILABLE(ios(12.2));
 @end
 
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAObjectTranslator.m b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAObjectTranslator.m
index bf05976534b9..04f9817250b5 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAObjectTranslator.m
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAObjectTranslator.m
@@ -291,12 +291,12 @@ + (SKPaymentDiscount *)getSKPaymentDiscountFromMap:(NSDictionary *)map
   return discount;
 }
 
-+ (nullable SKPaymentTransactionMessage *)convertTransactionToPigeon:
++ (nullable FIASKPaymentTransactionMessage *)convertTransactionToPigeon:
     (nullable SKPaymentTransaction *)transaction API_AVAILABLE(ios(12.2)) {
   if (!transaction) {
     return nil;
   }
-  SKPaymentTransactionMessage *msg = [SKPaymentTransactionMessage
+  return [FIASKPaymentTransactionMessage
             makeWithPayment:[self convertPaymentToPigeon:transaction.payment]
            transactionState:[self convertTransactionStateToPigeon:transaction.transactionState]
         originalTransaction:transaction.originalTransaction
@@ -306,10 +306,9 @@ + (nullable SKPaymentTransactionMessage *)convertTransactionToPigeon:
                                                                timeIntervalSince1970]]
       transactionIdentifier:transaction.transactionIdentifier
                       error:[self convertSKErrorToPigeon:transaction.error]];
-  return msg;
 }
 
-+ (nullable SKErrorMessage *)convertSKErrorToPigeon:(nullable NSError *)error {
++ (nullable FIASKErrorMessage *)convertSKErrorToPigeon:(nullable NSError *)error {
   if (!error) {
     return nil;
   }
@@ -320,34 +319,31 @@ + (nullable SKErrorMessage *)convertSKErrorToPigeon:(nullable NSError *)error {
     userInfo[key] = [FIAObjectTranslator encodeNSErrorUserInfo:value];
   }
 
-  SKErrorMessage *msg = [SKErrorMessage makeWithCode:error.code
-                                              domain:error.domain
-                                            userInfo:userInfo];
-  return msg;
+  return [FIASKErrorMessage makeWithCode:error.code domain:error.domain userInfo:userInfo];
 }
 
-+ (SKPaymentTransactionStateMessage)convertTransactionStateToPigeon:
++ (FIASKPaymentTransactionStateMessage)convertTransactionStateToPigeon:
     (SKPaymentTransactionState)state {
   switch (state) {
     case SKPaymentTransactionStatePurchasing:
-      return SKPaymentTransactionStateMessagePurchasing;
+      return FIASKPaymentTransactionStateMessagePurchasing;
     case SKPaymentTransactionStatePurchased:
-      return SKPaymentTransactionStateMessagePurchased;
+      return FIASKPaymentTransactionStateMessagePurchased;
     case SKPaymentTransactionStateFailed:
-      return SKPaymentTransactionStateMessageFailed;
+      return FIASKPaymentTransactionStateMessageFailed;
     case SKPaymentTransactionStateRestored:
-      return SKPaymentTransactionStateMessageRestored;
+      return FIASKPaymentTransactionStateMessageRestored;
     case SKPaymentTransactionStateDeferred:
-      return SKPaymentTransactionStateMessageDeferred;
+      return FIASKPaymentTransactionStateMessageDeferred;
   }
 }
 
-+ (nullable SKPaymentMessage *)convertPaymentToPigeon:(nullable SKPayment *)payment
++ (nullable FIASKPaymentMessage *)convertPaymentToPigeon:(nullable SKPayment *)payment
     API_AVAILABLE(ios(12.2)) {
   if (!payment) {
     return nil;
   }
-  SKPaymentMessage *msg = [SKPaymentMessage
+  return [FIASKPaymentMessage
        makeWithProductIdentifier:payment.productIdentifier
              applicationUsername:payment.applicationUsername
                      requestData:[[NSString alloc] initWithData:payment.requestData
@@ -355,92 +351,85 @@ + (nullable SKPaymentMessage *)convertPaymentToPigeon:(nullable SKPayment *)paym
                         quantity:payment.quantity
       simulatesAskToBuyInSandbox:payment.simulatesAskToBuyInSandbox
                  paymentDiscount:[self convertPaymentDiscountToPigeon:payment.paymentDiscount]];
-  return msg;
 }
 
-+ (nullable SKPaymentDiscountMessage *)convertPaymentDiscountToPigeon:
++ (nullable FIASKPaymentDiscountMessage *)convertPaymentDiscountToPigeon:
     (nullable SKPaymentDiscount *)discount API_AVAILABLE(ios(12.2)) {
   if (!discount) {
     return nil;
   }
-  SKPaymentDiscountMessage *msg =
-      [SKPaymentDiscountMessage makeWithIdentifier:discount.identifier
-                                     keyIdentifier:discount.keyIdentifier
-                                             nonce:[discount.nonce UUIDString]
-                                         signature:discount.signature
-                                         timestamp:[discount.timestamp intValue]];
-
-  return msg;
+  return [FIASKPaymentDiscountMessage makeWithIdentifier:discount.identifier
+                                           keyIdentifier:discount.keyIdentifier
+                                                   nonce:[discount.nonce UUIDString]
+                                               signature:discount.signature
+                                               timestamp:[discount.timestamp intValue]];
 }
 
-+ (nullable SKStorefrontMessage *)convertStorefrontToPigeon:(nullable SKStorefront *)storefront
++ (nullable FIASKStorefrontMessage *)convertStorefrontToPigeon:(nullable SKStorefront *)storefront
     API_AVAILABLE(ios(13.0)) {
   if (!storefront) {
     return nil;
   }
-  SKStorefrontMessage *msg = [SKStorefrontMessage makeWithCountryCode:storefront.countryCode
-                                                           identifier:storefront.identifier];
-  return msg;
+  return [FIASKStorefrontMessage makeWithCountryCode:storefront.countryCode
+                                          identifier:storefront.identifier];
 }
 
-+ (nullable SKProductSubscriptionPeriodMessage *)convertSKProductSubscriptionPeriodToPigeon:
++ (nullable FIASKProductSubscriptionPeriodMessage *)convertSKProductSubscriptionPeriodToPigeon:
     (nullable SKProductSubscriptionPeriod *)period API_AVAILABLE(ios(12.2)) {
   if (!period) {
     return nil;
   }
 
-  SKSubscriptionPeriodUnitMessage unit;
+  FIASKSubscriptionPeriodUnitMessage unit;
   switch (period.unit) {
     case SKProductPeriodUnitDay:
-      unit = SKSubscriptionPeriodUnitMessageDay;
+      unit = FIASKSubscriptionPeriodUnitMessageDay;
       break;
     case SKProductPeriodUnitWeek:
-      unit = SKSubscriptionPeriodUnitMessageWeek;
+      unit = FIASKSubscriptionPeriodUnitMessageWeek;
       break;
     case SKProductPeriodUnitMonth:
-      unit = SKSubscriptionPeriodUnitMessageMonth;
+      unit = FIASKSubscriptionPeriodUnitMessageMonth;
       break;
     case SKProductPeriodUnitYear:
-      unit = SKSubscriptionPeriodUnitMessageYear;
+      unit = FIASKSubscriptionPeriodUnitMessageYear;
       break;
   }
 
-  SKProductSubscriptionPeriodMessage *msg =
-      [SKProductSubscriptionPeriodMessage makeWithNumberOfUnits:period.numberOfUnits unit:unit];
-
-  return msg;
+  return [FIASKProductSubscriptionPeriodMessage makeWithNumberOfUnits:period.numberOfUnits
+                                                                 unit:unit];
 }
 
-+ (nullable SKProductDiscountMessage *)convertProductDiscountToPigeon:
++ (nullable FIASKProductDiscountMessage *)convertProductDiscountToPigeon:
     (nullable SKProductDiscount *)productDiscount API_AVAILABLE(ios(12.2)) {
   if (!productDiscount) {
     return nil;
   }
 
-  SKProductDiscountPaymentModeMessage paymentMode;
+  FIASKProductDiscountPaymentModeMessage paymentMode;
   switch (productDiscount.paymentMode) {
     case SKProductDiscountPaymentModeFreeTrial:
-      paymentMode = SKProductDiscountPaymentModeMessageFreeTrial;
+      paymentMode = FIASKProductDiscountPaymentModeMessageFreeTrial;
       break;
     case SKProductDiscountPaymentModePayAsYouGo:
-      paymentMode = SKProductDiscountPaymentModeMessagePayAsYouGo;
+      paymentMode = FIASKProductDiscountPaymentModeMessagePayAsYouGo;
       break;
     case SKProductDiscountPaymentModePayUpFront:
-      paymentMode = SKProductDiscountPaymentModeMessagePayUpFront;
+      paymentMode = FIASKProductDiscountPaymentModeMessagePayUpFront;
       break;
   }
 
-  SKProductDiscountTypeMessage type;
+  FIASKProductDiscountTypeMessage type;
   switch (productDiscount.type) {
     case SKProductDiscountTypeIntroductory:
-      type = SKProductDiscountTypeMessageIntroductory;
+      type = FIASKProductDiscountTypeMessageIntroductory;
       break;
     case SKProductDiscountTypeSubscription:
-      type = SKProductDiscountTypeMessageSubscription;
+      type = FIASKProductDiscountTypeMessageSubscription;
       break;
   }
 
-  SKProductDiscountMessage *msg = [SKProductDiscountMessage
+  return [FIASKProductDiscountMessage
            makeWithPrice:productDiscount.price.description
              priceLocale:[self convertNSLocaleToPigeon:productDiscount.priceLocale]
          numberOfPeriods:productDiscount.numberOfPeriods
@@ -449,37 +438,33 @@ + (nullable SKProductDiscountMessage *)convertProductDiscountToPigeon:
                                                                               .subscriptionPeriod]
               identifier:productDiscount.identifier
                     type:type];
-
-  return msg;
 }
 
-+ (nullable SKPriceLocaleMessage *)convertNSLocaleToPigeon:(nullable NSLocale *)locale
++ (nullable FIASKPriceLocaleMessage *)convertNSLocaleToPigeon:(nullable NSLocale *)locale
     API_AVAILABLE(ios(12.2)) {
   if (!locale) {
     return nil;
   }
-  SKPriceLocaleMessage *msg = [SKPriceLocaleMessage makeWithCurrencySymbol:locale.currencySymbol
-                                                              currencyCode:locale.currencyCode
-                                                               countryCode:locale.countryCode];
-
-  return msg;
+  return [FIASKPriceLocaleMessage makeWithCurrencySymbol:locale.currencySymbol
+                                            currencyCode:locale.currencyCode
+                                             countryCode:locale.countryCode];
 }
 
-+ (nullable SKProductMessage *)convertProductToPigeon:(nullable SKProduct *)product
++ (nullable FIASKProductMessage *)convertProductToPigeon:(nullable SKProduct *)product
     API_AVAILABLE(ios(12.2)) {
   if (!product) {
     return nil;
   }
 
   NSArray *skProductDiscounts = product.discounts;
-  NSMutableArray *pigeonProductDiscounts =
+  NSMutableArray *pigeonProductDiscounts =
       [NSMutableArray arrayWithCapacity:skProductDiscounts.count];
 
   for (SKProductDiscount *productDiscount in skProductDiscounts) {
     [pigeonProductDiscounts addObject:[self convertProductDiscountToPigeon:productDiscount]];
   };
 
-  SKProductMessage *msg = [SKProductMessage
+  return [FIASKProductMessage
         makeWithProductIdentifier:product.productIdentifier
                    localizedTitle:product.localizedTitle
              localizedDescription:product.localizedDescription
@@ -490,27 +475,24 @@ + (nullable SKProductMessage *)convertProductToPigeon:(nullable SKProduct *)prod
                    [self convertSKProductSubscriptionPeriodToPigeon:product.subscriptionPeriod]
                 introductoryPrice:[self convertProductDiscountToPigeon:product.introductoryPrice]
                         discounts:pigeonProductDiscounts];
-
-  return msg;
 }
 
-+ (nullable SKProductsResponseMessage *)convertProductsResponseToPigeon:
++ (nullable FIASKProductsResponseMessage *)convertProductsResponseToPigeon:
     (nullable SKProductsResponse *)productsResponse API_AVAILABLE(ios(12.2)) {
   if (!productsResponse) {
     return nil;
   }
   NSArray *skProducts = productsResponse.products;
-  NSMutableArray *pigeonProducts =
+  NSMutableArray *pigeonProducts =
       [NSMutableArray arrayWithCapacity:skProducts.count];
 
   for (SKProduct *product in skProducts) {
     [pigeonProducts addObject:[self convertProductToPigeon:product]];
   };
 
-  SKProductsResponseMessage *msg = [SKProductsResponseMessage
+  return [FIASKProductsResponseMessage
                makeWithProducts:pigeonProducts
       invalidProductIdentifiers:productsResponse.invalidProductIdentifiers ?: @[]];
-  return msg;
 }
 
 @end
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/InAppPurchasePlugin.swift b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/InAppPurchasePlugin.swift
index 43d500a8e3df..23b8972c96c1 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/InAppPurchasePlugin.swift
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/InAppPurchasePlugin.swift
@@ -11,7 +11,7 @@ import StoreKit
   import FlutterMacOS
 #endif
 
-public class InAppPurchasePlugin: NSObject, FlutterPlugin, InAppPurchaseAPI {
+public class InAppPurchasePlugin: NSObject, FlutterPlugin, FIAInAppPurchaseAPI {
   private let receiptManager: FIAPReceiptManager
   private var productsCache: NSMutableDictionary = [:]
   private var paymentQueueDelegateCallbackChannel: FlutterMethodChannel?
@@ -55,7 +55,7 @@ public class InAppPurchasePlugin: NSObject, FlutterPlugin, InAppPurchaseAPI {
     let instance = InAppPurchasePlugin(registrar: registrar)
     registrar.addMethodCallDelegate(instance, channel: channel)
     registrar.addApplicationDelegate(instance)
-    SetUpInAppPurchaseAPI(messenger, instance)
+    SetUpFIAInAppPurchaseAPI(messenger, instance)
     if #available(iOS 15.0, macOS 12.0, *) {
       InAppPurchase2APISetup.setUp(binaryMessenger: messenger, api: instance)
     }
@@ -120,7 +120,7 @@ public class InAppPurchasePlugin: NSObject, FlutterPlugin, InAppPurchaseAPI {
   }
 
   public func transactionsWithError(_ error: AutoreleasingUnsafeMutablePointer)
-    -> [SKPaymentTransactionMessage]?
+    -> [FIASKPaymentTransactionMessage]?
   {
     return getPaymentQueueHandler()
       .getUnfinishedTransactions()
@@ -130,7 +130,7 @@ public class InAppPurchasePlugin: NSObject, FlutterPlugin, InAppPurchaseAPI {
   }
 
   public func storefrontWithError(_ error: AutoreleasingUnsafeMutablePointer)
-    -> SKStorefrontMessage?
+    -> FIASKStorefrontMessage?
   {
     if #available(iOS 13.0, *), let storefront = getPaymentQueueHandler().storefront {
       return FIAObjectTranslator.convertStorefront(toPigeon: storefront)
@@ -140,7 +140,7 @@ public class InAppPurchasePlugin: NSObject, FlutterPlugin, InAppPurchaseAPI {
 
   public func startProductRequestProductIdentifiers(
     _ productIdentifiers: [String],
-    completion: @escaping (SKProductsResponseMessage?, FlutterError?) -> Void
+    completion: @escaping (FIASKProductsResponseMessage?, FlutterError?) -> Void
   ) {
     let request = getProductRequest(withIdentifiers: Set(productIdentifiers))
     let handler = handlerFactory(request)
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/StoreKit2/sk2_pigeon.g.swift b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/StoreKit2/sk2_pigeon.g.swift
index 6a327812444d..f6ff6bfe63b3 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/StoreKit2/sk2_pigeon.g.swift
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/StoreKit2/sk2_pigeon.g.swift
@@ -1,7 +1,7 @@
 // Copyright 2013 The Flutter Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-// Autogenerated from Pigeon (v22.0.0), do not edit directly.
+// Autogenerated from Pigeon (v22.4.2), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 import Foundation
@@ -123,8 +123,7 @@ struct SK2SubscriptionOfferMessage {
     let price = pigeonVar_list[1] as! Double
     let type = pigeonVar_list[2] as! SK2SubscriptionOfferTypeMessage
     let period = pigeonVar_list[3] as! SK2SubscriptionPeriodMessage
-    let periodCount =
-      pigeonVar_list[4] is Int64 ? pigeonVar_list[4] as! Int64 : Int64(pigeonVar_list[4] as! Int32)
+    let periodCount = pigeonVar_list[4] as! Int64
     let paymentMode = pigeonVar_list[5] as! SK2SubscriptionOfferPaymentModeMessage
 
     return SK2SubscriptionOfferMessage(
@@ -157,8 +156,7 @@ struct SK2SubscriptionPeriodMessage {
 
   // swift-format-ignore: AlwaysUseLowerCamelCase
   static func fromList(_ pigeonVar_list: [Any?]) -> SK2SubscriptionPeriodMessage? {
-    let value =
-      pigeonVar_list[0] is Int64 ? pigeonVar_list[0] as! Int64 : Int64(pigeonVar_list[0] as! Int32)
+    let value = pigeonVar_list[0] as! Int64
     let unit = pigeonVar_list[1] as! SK2SubscriptionPeriodUnitMessage
 
     return SK2SubscriptionPeriodMessage(
@@ -177,9 +175,7 @@ struct SK2SubscriptionPeriodMessage {
 /// Generated class from Pigeon that represents data sent in messages.
 struct SK2SubscriptionInfoMessage {
   /// An array of all the promotional offers configured for this subscription.
-  /// This should be List but pigeon doesnt support
-  /// null-safe generics. https://github.com/flutter/flutter/issues/97848
-  var promotionalOffers: [SK2SubscriptionOfferMessage?]
+  var promotionalOffers: [SK2SubscriptionOfferMessage]
   /// The group identifier for this subscription.
   var subscriptionGroupID: String
   /// The duration that this subscription lasts before auto-renewing.
@@ -187,7 +183,7 @@ struct SK2SubscriptionInfoMessage {
 
   // swift-format-ignore: AlwaysUseLowerCamelCase
   static func fromList(_ pigeonVar_list: [Any?]) -> SK2SubscriptionInfoMessage? {
-    let promotionalOffers = pigeonVar_list[0] as! [SK2SubscriptionOfferMessage?]
+    let promotionalOffers = pigeonVar_list[0] as! [SK2SubscriptionOfferMessage]
     let subscriptionGroupID = pigeonVar_list[1] as! String
     let subscriptionPeriod = pigeonVar_list[2] as! SK2SubscriptionPeriodMessage
 
@@ -295,11 +291,7 @@ struct SK2ProductPurchaseOptionsMessage {
   // swift-format-ignore: AlwaysUseLowerCamelCase
   static func fromList(_ pigeonVar_list: [Any?]) -> SK2ProductPurchaseOptionsMessage? {
     let appAccountToken: String? = nilOrValue(pigeonVar_list[0])
-    let quantity: Int64? =
-      isNullish(pigeonVar_list[1])
-      ? nil
-      : (pigeonVar_list[1] is Int64?
-        ? pigeonVar_list[1] as! Int64? : Int64(pigeonVar_list[1] as! Int32))
+    let quantity: Int64? = nilOrValue(pigeonVar_list[1])
 
     return SK2ProductPurchaseOptionsMessage(
       appAccountToken: appAccountToken,
@@ -327,14 +319,11 @@ struct SK2TransactionMessage {
 
   // swift-format-ignore: AlwaysUseLowerCamelCase
   static func fromList(_ pigeonVar_list: [Any?]) -> SK2TransactionMessage? {
-    let id =
-      pigeonVar_list[0] is Int64 ? pigeonVar_list[0] as! Int64 : Int64(pigeonVar_list[0] as! Int32)
-    let originalId =
-      pigeonVar_list[1] is Int64 ? pigeonVar_list[1] as! Int64 : Int64(pigeonVar_list[1] as! Int32)
+    let id = pigeonVar_list[0] as! Int64
+    let originalId = pigeonVar_list[1] as! Int64
     let productId = pigeonVar_list[2] as! String
     let purchaseDate = pigeonVar_list[3] as! String
-    let purchasedQuantity =
-      pigeonVar_list[4] is Int64 ? pigeonVar_list[4] as! Int64 : Int64(pigeonVar_list[4] as! Int32)
+    let purchasedQuantity = pigeonVar_list[4] as! Int64
     let appAccountToken: String? = nilOrValue(pigeonVar_list[5])
     let restoring = pigeonVar_list[6] as! Bool
     let error: SK2ErrorMessage? = nilOrValue(pigeonVar_list[7])
@@ -368,14 +357,13 @@ struct SK2TransactionMessage {
 struct SK2ErrorMessage {
   var code: Int64
   var domain: String
-  var userInfo: [String?: Any?]? = nil
+  var userInfo: [String: Any]? = nil
 
   // swift-format-ignore: AlwaysUseLowerCamelCase
   static func fromList(_ pigeonVar_list: [Any?]) -> SK2ErrorMessage? {
-    let code =
-      pigeonVar_list[0] is Int64 ? pigeonVar_list[0] as! Int64 : Int64(pigeonVar_list[0] as! Int32)
+    let code = pigeonVar_list[0] as! Int64
     let domain = pigeonVar_list[1] as! String
-    let userInfo: [String?: Any?]? = nilOrValue(pigeonVar_list[2])
+    let userInfo: [String: Any]? = nilOrValue(pigeonVar_list[2])
 
     return SK2ErrorMessage(
       code: code,
@@ -396,31 +384,31 @@ private class sk2_pigeonPigeonCodecReader: FlutterStandardReader {
   override func readValue(ofType type: UInt8) -> Any? {
     switch type {
     case 129:
-      let enumResultAsInt: Int? = nilOrValue(self.readValue() as? Int)
+      let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?)
       if let enumResultAsInt = enumResultAsInt {
         return SK2ProductTypeMessage(rawValue: enumResultAsInt)
       }
       return nil
     case 130:
-      let enumResultAsInt: Int? = nilOrValue(self.readValue() as? Int)
+      let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?)
       if let enumResultAsInt = enumResultAsInt {
         return SK2SubscriptionOfferTypeMessage(rawValue: enumResultAsInt)
       }
       return nil
     case 131:
-      let enumResultAsInt: Int? = nilOrValue(self.readValue() as? Int)
+      let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?)
       if let enumResultAsInt = enumResultAsInt {
         return SK2SubscriptionOfferPaymentModeMessage(rawValue: enumResultAsInt)
       }
       return nil
     case 132:
-      let enumResultAsInt: Int? = nilOrValue(self.readValue() as? Int)
+      let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?)
       if let enumResultAsInt = enumResultAsInt {
         return SK2SubscriptionPeriodUnitMessage(rawValue: enumResultAsInt)
       }
       return nil
     case 133:
-      let enumResultAsInt: Int? = nilOrValue(self.readValue() as? Int)
+      let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?)
       if let enumResultAsInt = enumResultAsInt {
         return SK2ProductPurchaseResultMessage(rawValue: enumResultAsInt)
       }
@@ -612,7 +600,7 @@ class InAppPurchase2APISetup {
     if let api = api {
       finishChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
-        let idArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32)
+        let idArg = args[0] as! Int64
         api.finish(id: idArg) { result in
           switch result {
           case .success:
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/messages.g.h b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/messages.g.h
index 7775d8d47ba8..a6059f269d73 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/messages.g.h
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/messages.g.h
@@ -1,7 +1,7 @@
 // Copyright 2013 The Flutter Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-// Autogenerated from Pigeon (v16.0.4), do not edit directly.
+// Autogenerated from Pigeon (v22.4.2), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 #import 
@@ -13,117 +13,117 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
-typedef NS_ENUM(NSUInteger, SKPaymentTransactionStateMessage) {
+typedef NS_ENUM(NSUInteger, FIASKPaymentTransactionStateMessage) {
   /// Indicates the transaction is being processed in App Store.
   ///
   /// You should update your UI to indicate that you are waiting for the
   /// transaction to update to another state. Never complete a transaction that
   /// is still in a purchasing state.
-  SKPaymentTransactionStateMessagePurchasing = 0,
+  FIASKPaymentTransactionStateMessagePurchasing = 0,
   /// The user's payment has been succesfully processed.
   ///
   /// You should provide the user the content that they purchased.
-  SKPaymentTransactionStateMessagePurchased = 1,
+  FIASKPaymentTransactionStateMessagePurchased = 1,
   /// The transaction failed.
   ///
   /// Check the [PaymentTransactionWrapper.error] property from
   /// [PaymentTransactionWrapper] for details.
-  SKPaymentTransactionStateMessageFailed = 2,
+  FIASKPaymentTransactionStateMessageFailed = 2,
   /// This transaction is restoring content previously purchased by the user.
   ///
   /// The previous transaction information can be obtained in
   /// [PaymentTransactionWrapper.originalTransaction] from
   /// [PaymentTransactionWrapper].
-  SKPaymentTransactionStateMessageRestored = 3,
+  FIASKPaymentTransactionStateMessageRestored = 3,
   /// The transaction is in the queue but pending external action. Wait for
   /// another callback to get the final state.
   ///
   /// You should update your UI to indicate that you are waiting for the
   /// transaction to update to another state.
-  SKPaymentTransactionStateMessageDeferred = 4,
+  FIASKPaymentTransactionStateMessageDeferred = 4,
   /// Indicates the transaction is in an unspecified state.
-  SKPaymentTransactionStateMessageUnspecified = 5,
+  FIASKPaymentTransactionStateMessageUnspecified = 5,
 };
 
-/// Wrapper for SKPaymentTransactionStateMessage to allow for nullability.
-@interface SKPaymentTransactionStateMessageBox : NSObject
-@property(nonatomic, assign) SKPaymentTransactionStateMessage value;
-- (instancetype)initWithValue:(SKPaymentTransactionStateMessage)value;
+/// Wrapper for FIASKPaymentTransactionStateMessage to allow for nullability.
+@interface FIASKPaymentTransactionStateMessageBox : NSObject
+@property(nonatomic, assign) FIASKPaymentTransactionStateMessage value;
+- (instancetype)initWithValue:(FIASKPaymentTransactionStateMessage)value;
 @end
 
-typedef NS_ENUM(NSUInteger, SKProductDiscountTypeMessage) {
+typedef NS_ENUM(NSUInteger, FIASKProductDiscountTypeMessage) {
   /// A constant indicating the discount type is an introductory offer.
-  SKProductDiscountTypeMessageIntroductory = 0,
+  FIASKProductDiscountTypeMessageIntroductory = 0,
   /// A constant indicating the discount type is a promotional offer.
-  SKProductDiscountTypeMessageSubscription = 1,
+  FIASKProductDiscountTypeMessageSubscription = 1,
 };
 
-/// Wrapper for SKProductDiscountTypeMessage to allow for nullability.
-@interface SKProductDiscountTypeMessageBox : NSObject
-@property(nonatomic, assign) SKProductDiscountTypeMessage value;
-- (instancetype)initWithValue:(SKProductDiscountTypeMessage)value;
+/// Wrapper for FIASKProductDiscountTypeMessage to allow for nullability.
+@interface FIASKProductDiscountTypeMessageBox : NSObject
+@property(nonatomic, assign) FIASKProductDiscountTypeMessage value;
+- (instancetype)initWithValue:(FIASKProductDiscountTypeMessage)value;
 @end
 
-typedef NS_ENUM(NSUInteger, SKProductDiscountPaymentModeMessage) {
+typedef NS_ENUM(NSUInteger, FIASKProductDiscountPaymentModeMessage) {
   /// Allows user to pay the discounted price at each payment period.
-  SKProductDiscountPaymentModeMessagePayAsYouGo = 0,
+  FIASKProductDiscountPaymentModeMessagePayAsYouGo = 0,
   /// Allows user to pay the discounted price upfront and receive the product for the rest of time
   /// that was paid for.
-  SKProductDiscountPaymentModeMessagePayUpFront = 1,
+  FIASKProductDiscountPaymentModeMessagePayUpFront = 1,
   /// User pays nothing during the discounted period.
-  SKProductDiscountPaymentModeMessageFreeTrial = 2,
+  FIASKProductDiscountPaymentModeMessageFreeTrial = 2,
   /// Unspecified mode.
-  SKProductDiscountPaymentModeMessageUnspecified = 3,
+  FIASKProductDiscountPaymentModeMessageUnspecified = 3,
 };
 
-/// Wrapper for SKProductDiscountPaymentModeMessage to allow for nullability.
-@interface SKProductDiscountPaymentModeMessageBox : NSObject
-@property(nonatomic, assign) SKProductDiscountPaymentModeMessage value;
-- (instancetype)initWithValue:(SKProductDiscountPaymentModeMessage)value;
+/// Wrapper for FIASKProductDiscountPaymentModeMessage to allow for nullability.
+@interface FIASKProductDiscountPaymentModeMessageBox : NSObject
+@property(nonatomic, assign) FIASKProductDiscountPaymentModeMessage value;
+- (instancetype)initWithValue:(FIASKProductDiscountPaymentModeMessage)value;
 @end
 
-typedef NS_ENUM(NSUInteger, SKSubscriptionPeriodUnitMessage) {
-  SKSubscriptionPeriodUnitMessageDay = 0,
-  SKSubscriptionPeriodUnitMessageWeek = 1,
-  SKSubscriptionPeriodUnitMessageMonth = 2,
-  SKSubscriptionPeriodUnitMessageYear = 3,
+typedef NS_ENUM(NSUInteger, FIASKSubscriptionPeriodUnitMessage) {
+  FIASKSubscriptionPeriodUnitMessageDay = 0,
+  FIASKSubscriptionPeriodUnitMessageWeek = 1,
+  FIASKSubscriptionPeriodUnitMessageMonth = 2,
+  FIASKSubscriptionPeriodUnitMessageYear = 3,
 };
 
-/// Wrapper for SKSubscriptionPeriodUnitMessage to allow for nullability.
-@interface SKSubscriptionPeriodUnitMessageBox : NSObject
-@property(nonatomic, assign) SKSubscriptionPeriodUnitMessage value;
-- (instancetype)initWithValue:(SKSubscriptionPeriodUnitMessage)value;
+/// Wrapper for FIASKSubscriptionPeriodUnitMessage to allow for nullability.
+@interface FIASKSubscriptionPeriodUnitMessageBox : NSObject
+@property(nonatomic, assign) FIASKSubscriptionPeriodUnitMessage value;
+- (instancetype)initWithValue:(FIASKSubscriptionPeriodUnitMessage)value;
 @end
 
-@class SKPaymentTransactionMessage;
-@class SKPaymentMessage;
-@class SKErrorMessage;
-@class SKPaymentDiscountMessage;
-@class SKStorefrontMessage;
-@class SKProductsResponseMessage;
-@class SKProductMessage;
-@class SKPriceLocaleMessage;
-@class SKProductDiscountMessage;
-@class SKProductSubscriptionPeriodMessage;
+@class FIASKPaymentTransactionMessage;
+@class FIASKPaymentMessage;
+@class FIASKErrorMessage;
+@class FIASKPaymentDiscountMessage;
+@class FIASKStorefrontMessage;
+@class FIASKProductsResponseMessage;
+@class FIASKProductMessage;
+@class FIASKPriceLocaleMessage;
+@class FIASKProductDiscountMessage;
+@class FIASKProductSubscriptionPeriodMessage;
 
-@interface SKPaymentTransactionMessage : NSObject
+@interface FIASKPaymentTransactionMessage : NSObject
 /// `init` unavailable to enforce nonnull fields, see the `make` class method.
 - (instancetype)init NS_UNAVAILABLE;
-+ (instancetype)makeWithPayment:(SKPaymentMessage *)payment
-               transactionState:(SKPaymentTransactionStateMessage)transactionState
-            originalTransaction:(nullable SKPaymentTransactionMessage *)originalTransaction
++ (instancetype)makeWithPayment:(FIASKPaymentMessage *)payment
+               transactionState:(FIASKPaymentTransactionStateMessage)transactionState
+            originalTransaction:(nullable FIASKPaymentTransactionMessage *)originalTransaction
            transactionTimeStamp:(nullable NSNumber *)transactionTimeStamp
           transactionIdentifier:(nullable NSString *)transactionIdentifier
-                          error:(nullable SKErrorMessage *)error;
-@property(nonatomic, strong) SKPaymentMessage *payment;
-@property(nonatomic, assign) SKPaymentTransactionStateMessage transactionState;
-@property(nonatomic, strong, nullable) SKPaymentTransactionMessage *originalTransaction;
+                          error:(nullable FIASKErrorMessage *)error;
+@property(nonatomic, strong) FIASKPaymentMessage *payment;
+@property(nonatomic, assign) FIASKPaymentTransactionStateMessage transactionState;
+@property(nonatomic, strong, nullable) FIASKPaymentTransactionMessage *originalTransaction;
 @property(nonatomic, strong, nullable) NSNumber *transactionTimeStamp;
 @property(nonatomic, copy, nullable) NSString *transactionIdentifier;
-@property(nonatomic, strong, nullable) SKErrorMessage *error;
+@property(nonatomic, strong, nullable) FIASKErrorMessage *error;
 @end
 
-@interface SKPaymentMessage : NSObject
+@interface FIASKPaymentMessage : NSObject
 /// `init` unavailable to enforce nonnull fields, see the `make` class method.
 - (instancetype)init NS_UNAVAILABLE;
 + (instancetype)makeWithProductIdentifier:(NSString *)productIdentifier
@@ -131,16 +131,16 @@ typedef NS_ENUM(NSUInteger, SKSubscriptionPeriodUnitMessage) {
                               requestData:(nullable NSString *)requestData
                                  quantity:(NSInteger)quantity
                simulatesAskToBuyInSandbox:(BOOL)simulatesAskToBuyInSandbox
-                          paymentDiscount:(nullable SKPaymentDiscountMessage *)paymentDiscount;
+                          paymentDiscount:(nullable FIASKPaymentDiscountMessage *)paymentDiscount;
 @property(nonatomic, copy) NSString *productIdentifier;
 @property(nonatomic, copy, nullable) NSString *applicationUsername;
 @property(nonatomic, copy, nullable) NSString *requestData;
 @property(nonatomic, assign) NSInteger quantity;
 @property(nonatomic, assign) BOOL simulatesAskToBuyInSandbox;
-@property(nonatomic, strong, nullable) SKPaymentDiscountMessage *paymentDiscount;
+@property(nonatomic, strong, nullable) FIASKPaymentDiscountMessage *paymentDiscount;
 @end
 
-@interface SKErrorMessage : NSObject
+@interface FIASKErrorMessage : NSObject
 /// `init` unavailable to enforce nonnull fields, see the `make` class method.
 - (instancetype)init NS_UNAVAILABLE;
 + (instancetype)makeWithCode:(NSInteger)code
@@ -151,7 +151,7 @@ typedef NS_ENUM(NSUInteger, SKSubscriptionPeriodUnitMessage) {
 @property(nonatomic, copy, nullable) NSDictionary *userInfo;
 @end
 
-@interface SKPaymentDiscountMessage : NSObject
+@interface FIASKPaymentDiscountMessage : NSObject
 /// `init` unavailable to enforce nonnull fields, see the `make` class method.
 - (instancetype)init NS_UNAVAILABLE;
 + (instancetype)makeWithIdentifier:(NSString *)identifier
@@ -166,7 +166,7 @@ typedef NS_ENUM(NSUInteger, SKSubscriptionPeriodUnitMessage) {
 @property(nonatomic, assign) NSInteger timestamp;
 @end
 
-@interface SKStorefrontMessage : NSObject
+@interface FIASKStorefrontMessage : NSObject
 /// `init` unavailable to enforce nonnull fields, see the `make` class method.
 - (instancetype)init NS_UNAVAILABLE;
 + (instancetype)makeWithCountryCode:(NSString *)countryCode identifier:(NSString *)identifier;
@@ -174,38 +174,38 @@ typedef NS_ENUM(NSUInteger, SKSubscriptionPeriodUnitMessage) {
 @property(nonatomic, copy) NSString *identifier;
 @end
 
-@interface SKProductsResponseMessage : NSObject
-+ (instancetype)makeWithProducts:(nullable NSArray *)products
+@interface FIASKProductsResponseMessage : NSObject
++ (instancetype)makeWithProducts:(nullable NSArray *)products
        invalidProductIdentifiers:(nullable NSArray *)invalidProductIdentifiers;
-@property(nonatomic, copy, nullable) NSArray *products;
+@property(nonatomic, copy, nullable) NSArray *products;
 @property(nonatomic, copy, nullable) NSArray *invalidProductIdentifiers;
 @end
 
-@interface SKProductMessage : NSObject
+@interface FIASKProductMessage : NSObject
 /// `init` unavailable to enforce nonnull fields, see the `make` class method.
 - (instancetype)init NS_UNAVAILABLE;
-+ (instancetype)makeWithProductIdentifier:(NSString *)productIdentifier
-                           localizedTitle:(NSString *)localizedTitle
-                     localizedDescription:(nullable NSString *)localizedDescription
-                              priceLocale:(SKPriceLocaleMessage *)priceLocale
-              subscriptionGroupIdentifier:(nullable NSString *)subscriptionGroupIdentifier
-                                    price:(NSString *)price
-                       subscriptionPeriod:
-                           (nullable SKProductSubscriptionPeriodMessage *)subscriptionPeriod
-                        introductoryPrice:(nullable SKProductDiscountMessage *)introductoryPrice
-                                discounts:(nullable NSArray *)discounts;
++ (instancetype)
+      makeWithProductIdentifier:(NSString *)productIdentifier
+                 localizedTitle:(NSString *)localizedTitle
+           localizedDescription:(nullable NSString *)localizedDescription
+                    priceLocale:(FIASKPriceLocaleMessage *)priceLocale
+    subscriptionGroupIdentifier:(nullable NSString *)subscriptionGroupIdentifier
+                          price:(NSString *)price
+             subscriptionPeriod:(nullable FIASKProductSubscriptionPeriodMessage *)subscriptionPeriod
+              introductoryPrice:(nullable FIASKProductDiscountMessage *)introductoryPrice
+                      discounts:(nullable NSArray *)discounts;
 @property(nonatomic, copy) NSString *productIdentifier;
 @property(nonatomic, copy) NSString *localizedTitle;
 @property(nonatomic, copy, nullable) NSString *localizedDescription;
-@property(nonatomic, strong) SKPriceLocaleMessage *priceLocale;
+@property(nonatomic, strong) FIASKPriceLocaleMessage *priceLocale;
 @property(nonatomic, copy, nullable) NSString *subscriptionGroupIdentifier;
 @property(nonatomic, copy) NSString *price;
-@property(nonatomic, strong, nullable) SKProductSubscriptionPeriodMessage *subscriptionPeriod;
-@property(nonatomic, strong, nullable) SKProductDiscountMessage *introductoryPrice;
-@property(nonatomic, copy, nullable) NSArray *discounts;
+@property(nonatomic, strong, nullable) FIASKProductSubscriptionPeriodMessage *subscriptionPeriod;
+@property(nonatomic, strong, nullable) FIASKProductDiscountMessage *introductoryPrice;
+@property(nonatomic, copy, nullable) NSArray *discounts;
 @end
 
-@interface SKPriceLocaleMessage : NSObject
+@interface FIASKPriceLocaleMessage : NSObject
 /// `init` unavailable to enforce nonnull fields, see the `make` class method.
 - (instancetype)init NS_UNAVAILABLE;
 + (instancetype)makeWithCurrencySymbol:(NSString *)currencySymbol
@@ -219,51 +219,51 @@ typedef NS_ENUM(NSUInteger, SKSubscriptionPeriodUnitMessage) {
 @property(nonatomic, copy) NSString *countryCode;
 @end
 
-@interface SKProductDiscountMessage : NSObject
+@interface FIASKProductDiscountMessage : NSObject
 /// `init` unavailable to enforce nonnull fields, see the `make` class method.
 - (instancetype)init NS_UNAVAILABLE;
 + (instancetype)makeWithPrice:(NSString *)price
-                  priceLocale:(SKPriceLocaleMessage *)priceLocale
+                  priceLocale:(FIASKPriceLocaleMessage *)priceLocale
               numberOfPeriods:(NSInteger)numberOfPeriods
-                  paymentMode:(SKProductDiscountPaymentModeMessage)paymentMode
-           subscriptionPeriod:(SKProductSubscriptionPeriodMessage *)subscriptionPeriod
+                  paymentMode:(FIASKProductDiscountPaymentModeMessage)paymentMode
+           subscriptionPeriod:(FIASKProductSubscriptionPeriodMessage *)subscriptionPeriod
                    identifier:(nullable NSString *)identifier
-                         type:(SKProductDiscountTypeMessage)type;
+                         type:(FIASKProductDiscountTypeMessage)type;
 @property(nonatomic, copy) NSString *price;
-@property(nonatomic, strong) SKPriceLocaleMessage *priceLocale;
+@property(nonatomic, strong) FIASKPriceLocaleMessage *priceLocale;
 @property(nonatomic, assign) NSInteger numberOfPeriods;
-@property(nonatomic, assign) SKProductDiscountPaymentModeMessage paymentMode;
-@property(nonatomic, strong) SKProductSubscriptionPeriodMessage *subscriptionPeriod;
+@property(nonatomic, assign) FIASKProductDiscountPaymentModeMessage paymentMode;
+@property(nonatomic, strong) FIASKProductSubscriptionPeriodMessage *subscriptionPeriod;
 @property(nonatomic, copy, nullable) NSString *identifier;
-@property(nonatomic, assign) SKProductDiscountTypeMessage type;
+@property(nonatomic, assign) FIASKProductDiscountTypeMessage type;
 @end
 
-@interface SKProductSubscriptionPeriodMessage : NSObject
+@interface FIASKProductSubscriptionPeriodMessage : NSObject
 /// `init` unavailable to enforce nonnull fields, see the `make` class method.
 - (instancetype)init NS_UNAVAILABLE;
 + (instancetype)makeWithNumberOfUnits:(NSInteger)numberOfUnits
-                                 unit:(SKSubscriptionPeriodUnitMessage)unit;
+                                 unit:(FIASKSubscriptionPeriodUnitMessage)unit;
 @property(nonatomic, assign) NSInteger numberOfUnits;
-@property(nonatomic, assign) SKSubscriptionPeriodUnitMessage unit;
+@property(nonatomic, assign) FIASKSubscriptionPeriodUnitMessage unit;
 @end
 
-/// The codec used by InAppPurchaseAPI.
-NSObject *InAppPurchaseAPIGetCodec(void);
+/// The codec used by all APIs.
+NSObject *FIAGetMessagesCodec(void);
 
-@protocol InAppPurchaseAPI
+@protocol FIAInAppPurchaseAPI
 /// Returns if the current device is able to make payments
 ///
 /// @return `nil` only when `error != nil`.
 - (nullable NSNumber *)canMakePaymentsWithError:(FlutterError *_Nullable *_Nonnull)error;
 /// @return `nil` only when `error != nil`.
-- (nullable NSArray *)transactionsWithError:
+- (nullable NSArray *)transactionsWithError:
     (FlutterError *_Nullable *_Nonnull)error;
 /// @return `nil` only when `error != nil`.
-- (nullable SKStorefrontMessage *)storefrontWithError:(FlutterError *_Nullable *_Nonnull)error;
+- (nullable FIASKStorefrontMessage *)storefrontWithError:(FlutterError *_Nullable *_Nonnull)error;
 - (void)addPaymentPaymentMap:(NSDictionary *)paymentMap
                        error:(FlutterError *_Nullable *_Nonnull)error;
 - (void)startProductRequestProductIdentifiers:(NSArray *)productIdentifiers
-                                   completion:(void (^)(SKProductsResponseMessage *_Nullable,
+                                   completion:(void (^)(FIASKProductsResponseMessage *_Nullable,
                                                         FlutterError *_Nullable))completion;
 - (void)finishTransactionFinishMap:(NSDictionary *)finishMap
                              error:(FlutterError *_Nullable *_Nonnull)error;
@@ -280,7 +280,11 @@ NSObject *InAppPurchaseAPIGetCodec(void);
 - (void)showPriceConsentIfNeededWithError:(FlutterError *_Nullable *_Nonnull)error;
 @end
 
-extern void SetUpInAppPurchaseAPI(id binaryMessenger,
-                                  NSObject *_Nullable api);
+extern void SetUpFIAInAppPurchaseAPI(id binaryMessenger,
+                                     NSObject *_Nullable api);
+
+extern void SetUpFIAInAppPurchaseAPIWithSuffix(id binaryMessenger,
+                                               NSObject *_Nullable api,
+                                               NSString *messageChannelSuffix);
 
 NS_ASSUME_NONNULL_END
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/messages.g.m b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/messages.g.m
index 50a358479fa3..62988eb04fee 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/messages.g.m
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/messages.g.m
@@ -1,7 +1,7 @@
 // Copyright 2013 The Flutter Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-// Autogenerated from Pigeon (v16.0.5), do not edit directly.
+// Autogenerated from Pigeon (v22.4.2), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 #import "messages.g.h"
@@ -16,7 +16,7 @@
 #error File requires ARC to be enabled.
 #endif
 
-static NSArray *wrapResult(id result, FlutterError *error) {
+static NSArray *wrapResult(id result, FlutterError *error) {
   if (error) {
     return @[
       error.code ?: [NSNull null], error.message ?: [NSNull null], error.details ?: [NSNull null]
@@ -25,13 +25,13 @@
   return @[ result ?: [NSNull null] ];
 }
 
-static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) {
+static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) {
   id result = array[key];
   return (result == [NSNull null]) ? nil : result;
 }
 
-@implementation SKPaymentTransactionStateMessageBox
-- (instancetype)initWithValue:(SKPaymentTransactionStateMessage)value {
+@implementation FIASKPaymentTransactionStateMessageBox
+- (instancetype)initWithValue:(FIASKPaymentTransactionStateMessage)value {
   self = [super init];
   if (self) {
     _value = value;
@@ -40,8 +40,8 @@ - (instancetype)initWithValue:(SKPaymentTransactionStateMessage)value {
 }
 @end
 
-@implementation SKProductDiscountTypeMessageBox
-- (instancetype)initWithValue:(SKProductDiscountTypeMessage)value {
+@implementation FIASKProductDiscountTypeMessageBox
+- (instancetype)initWithValue:(FIASKProductDiscountTypeMessage)value {
   self = [super init];
   if (self) {
     _value = value;
@@ -50,8 +50,8 @@ - (instancetype)initWithValue:(SKProductDiscountTypeMessage)value {
 }
 @end
 
-@implementation SKProductDiscountPaymentModeMessageBox
-- (instancetype)initWithValue:(SKProductDiscountPaymentModeMessage)value {
+@implementation FIASKProductDiscountPaymentModeMessageBox
+- (instancetype)initWithValue:(FIASKProductDiscountPaymentModeMessage)value {
   self = [super init];
   if (self) {
     _value = value;
@@ -60,8 +60,8 @@ - (instancetype)initWithValue:(SKProductDiscountPaymentModeMessage)value {
 }
 @end
 
-@implementation SKSubscriptionPeriodUnitMessageBox
-- (instancetype)initWithValue:(SKSubscriptionPeriodUnitMessage)value {
+@implementation FIASKSubscriptionPeriodUnitMessageBox
+- (instancetype)initWithValue:(FIASKSubscriptionPeriodUnitMessage)value {
   self = [super init];
   if (self) {
     _value = value;
@@ -70,74 +70,74 @@ - (instancetype)initWithValue:(SKSubscriptionPeriodUnitMessage)value {
 }
 @end
 
-@interface SKPaymentTransactionMessage ()
-+ (SKPaymentTransactionMessage *)fromList:(NSArray *)list;
-+ (nullable SKPaymentTransactionMessage *)nullableFromList:(NSArray *)list;
-- (NSArray *)toList;
+@interface FIASKPaymentTransactionMessage ()
++ (FIASKPaymentTransactionMessage *)fromList:(NSArray *)list;
++ (nullable FIASKPaymentTransactionMessage *)nullableFromList:(NSArray *)list;
+- (NSArray *)toList;
 @end
 
-@interface SKPaymentMessage ()
-+ (SKPaymentMessage *)fromList:(NSArray *)list;
-+ (nullable SKPaymentMessage *)nullableFromList:(NSArray *)list;
-- (NSArray *)toList;
+@interface FIASKPaymentMessage ()
++ (FIASKPaymentMessage *)fromList:(NSArray *)list;
++ (nullable FIASKPaymentMessage *)nullableFromList:(NSArray *)list;
+- (NSArray *)toList;
 @end
 
-@interface SKErrorMessage ()
-+ (SKErrorMessage *)fromList:(NSArray *)list;
-+ (nullable SKErrorMessage *)nullableFromList:(NSArray *)list;
-- (NSArray *)toList;
+@interface FIASKErrorMessage ()
++ (FIASKErrorMessage *)fromList:(NSArray *)list;
++ (nullable FIASKErrorMessage *)nullableFromList:(NSArray *)list;
+- (NSArray *)toList;
 @end
 
-@interface SKPaymentDiscountMessage ()
-+ (SKPaymentDiscountMessage *)fromList:(NSArray *)list;
-+ (nullable SKPaymentDiscountMessage *)nullableFromList:(NSArray *)list;
-- (NSArray *)toList;
+@interface FIASKPaymentDiscountMessage ()
++ (FIASKPaymentDiscountMessage *)fromList:(NSArray *)list;
++ (nullable FIASKPaymentDiscountMessage *)nullableFromList:(NSArray *)list;
+- (NSArray *)toList;
 @end
 
-@interface SKStorefrontMessage ()
-+ (SKStorefrontMessage *)fromList:(NSArray *)list;
-+ (nullable SKStorefrontMessage *)nullableFromList:(NSArray *)list;
-- (NSArray *)toList;
+@interface FIASKStorefrontMessage ()
++ (FIASKStorefrontMessage *)fromList:(NSArray *)list;
++ (nullable FIASKStorefrontMessage *)nullableFromList:(NSArray *)list;
+- (NSArray *)toList;
 @end
 
-@interface SKProductsResponseMessage ()
-+ (SKProductsResponseMessage *)fromList:(NSArray *)list;
-+ (nullable SKProductsResponseMessage *)nullableFromList:(NSArray *)list;
-- (NSArray *)toList;
+@interface FIASKProductsResponseMessage ()
++ (FIASKProductsResponseMessage *)fromList:(NSArray *)list;
++ (nullable FIASKProductsResponseMessage *)nullableFromList:(NSArray *)list;
+- (NSArray *)toList;
 @end
 
-@interface SKProductMessage ()
-+ (SKProductMessage *)fromList:(NSArray *)list;
-+ (nullable SKProductMessage *)nullableFromList:(NSArray *)list;
-- (NSArray *)toList;
+@interface FIASKProductMessage ()
++ (FIASKProductMessage *)fromList:(NSArray *)list;
++ (nullable FIASKProductMessage *)nullableFromList:(NSArray *)list;
+- (NSArray *)toList;
 @end
 
-@interface SKPriceLocaleMessage ()
-+ (SKPriceLocaleMessage *)fromList:(NSArray *)list;
-+ (nullable SKPriceLocaleMessage *)nullableFromList:(NSArray *)list;
-- (NSArray *)toList;
+@interface FIASKPriceLocaleMessage ()
++ (FIASKPriceLocaleMessage *)fromList:(NSArray *)list;
++ (nullable FIASKPriceLocaleMessage *)nullableFromList:(NSArray *)list;
+- (NSArray *)toList;
 @end
 
-@interface SKProductDiscountMessage ()
-+ (SKProductDiscountMessage *)fromList:(NSArray *)list;
-+ (nullable SKProductDiscountMessage *)nullableFromList:(NSArray *)list;
-- (NSArray *)toList;
+@interface FIASKProductDiscountMessage ()
++ (FIASKProductDiscountMessage *)fromList:(NSArray *)list;
++ (nullable FIASKProductDiscountMessage *)nullableFromList:(NSArray *)list;
+- (NSArray *)toList;
 @end
 
-@interface SKProductSubscriptionPeriodMessage ()
-+ (SKProductSubscriptionPeriodMessage *)fromList:(NSArray *)list;
-+ (nullable SKProductSubscriptionPeriodMessage *)nullableFromList:(NSArray *)list;
-- (NSArray *)toList;
+@interface FIASKProductSubscriptionPeriodMessage ()
++ (FIASKProductSubscriptionPeriodMessage *)fromList:(NSArray *)list;
++ (nullable FIASKProductSubscriptionPeriodMessage *)nullableFromList:(NSArray *)list;
+- (NSArray *)toList;
 @end
 
-@implementation SKPaymentTransactionMessage
-+ (instancetype)makeWithPayment:(SKPaymentMessage *)payment
-               transactionState:(SKPaymentTransactionStateMessage)transactionState
-            originalTransaction:(nullable SKPaymentTransactionMessage *)originalTransaction
+@implementation FIASKPaymentTransactionMessage
++ (instancetype)makeWithPayment:(FIASKPaymentMessage *)payment
+               transactionState:(FIASKPaymentTransactionStateMessage)transactionState
+            originalTransaction:(nullable FIASKPaymentTransactionMessage *)originalTransaction
            transactionTimeStamp:(nullable NSNumber *)transactionTimeStamp
           transactionIdentifier:(nullable NSString *)transactionIdentifier
-                          error:(nullable SKErrorMessage *)error {
-  SKPaymentTransactionMessage *pigeonResult = [[SKPaymentTransactionMessage alloc] init];
+                          error:(nullable FIASKErrorMessage *)error {
+  FIASKPaymentTransactionMessage *pigeonResult = [[FIASKPaymentTransactionMessage alloc] init];
   pigeonResult.payment = payment;
   pigeonResult.transactionState = transactionState;
   pigeonResult.originalTransaction = originalTransaction;
@@ -146,40 +146,41 @@ + (instancetype)makeWithPayment:(SKPaymentMessage *)payment
   pigeonResult.error = error;
   return pigeonResult;
 }
-+ (SKPaymentTransactionMessage *)fromList:(NSArray *)list {
-  SKPaymentTransactionMessage *pigeonResult = [[SKPaymentTransactionMessage alloc] init];
-  pigeonResult.payment = [SKPaymentMessage nullableFromList:(GetNullableObjectAtIndex(list, 0))];
-  pigeonResult.transactionState = [GetNullableObjectAtIndex(list, 1) integerValue];
-  pigeonResult.originalTransaction =
-      [SKPaymentTransactionMessage nullableFromList:(GetNullableObjectAtIndex(list, 2))];
++ (FIASKPaymentTransactionMessage *)fromList:(NSArray *)list {
+  FIASKPaymentTransactionMessage *pigeonResult = [[FIASKPaymentTransactionMessage alloc] init];
+  pigeonResult.payment = GetNullableObjectAtIndex(list, 0);
+  FIASKPaymentTransactionStateMessageBox *boxedFIASKPaymentTransactionStateMessage =
+      GetNullableObjectAtIndex(list, 1);
+  pigeonResult.transactionState = boxedFIASKPaymentTransactionStateMessage.value;
+  pigeonResult.originalTransaction = GetNullableObjectAtIndex(list, 2);
   pigeonResult.transactionTimeStamp = GetNullableObjectAtIndex(list, 3);
   pigeonResult.transactionIdentifier = GetNullableObjectAtIndex(list, 4);
-  pigeonResult.error = [SKErrorMessage nullableFromList:(GetNullableObjectAtIndex(list, 5))];
+  pigeonResult.error = GetNullableObjectAtIndex(list, 5);
   return pigeonResult;
 }
-+ (nullable SKPaymentTransactionMessage *)nullableFromList:(NSArray *)list {
-  return (list) ? [SKPaymentTransactionMessage fromList:list] : nil;
++ (nullable FIASKPaymentTransactionMessage *)nullableFromList:(NSArray *)list {
+  return (list) ? [FIASKPaymentTransactionMessage fromList:list] : nil;
 }
-- (NSArray *)toList {
+- (NSArray *)toList {
   return @[
-    (self.payment ? [self.payment toList] : [NSNull null]),
-    @(self.transactionState),
-    (self.originalTransaction ? [self.originalTransaction toList] : [NSNull null]),
+    self.payment ?: [NSNull null],
+    [[FIASKPaymentTransactionStateMessageBox alloc] initWithValue:self.transactionState],
+    self.originalTransaction ?: [NSNull null],
     self.transactionTimeStamp ?: [NSNull null],
     self.transactionIdentifier ?: [NSNull null],
-    (self.error ? [self.error toList] : [NSNull null]),
+    self.error ?: [NSNull null],
   ];
 }
 @end
 
-@implementation SKPaymentMessage
+@implementation FIASKPaymentMessage
 + (instancetype)makeWithProductIdentifier:(NSString *)productIdentifier
                       applicationUsername:(nullable NSString *)applicationUsername
                               requestData:(nullable NSString *)requestData
                                  quantity:(NSInteger)quantity
                simulatesAskToBuyInSandbox:(BOOL)simulatesAskToBuyInSandbox
-                          paymentDiscount:(nullable SKPaymentDiscountMessage *)paymentDiscount {
-  SKPaymentMessage *pigeonResult = [[SKPaymentMessage alloc] init];
+                          paymentDiscount:(nullable FIASKPaymentDiscountMessage *)paymentDiscount {
+  FIASKPaymentMessage *pigeonResult = [[FIASKPaymentMessage alloc] init];
   pigeonResult.productIdentifier = productIdentifier;
   pigeonResult.applicationUsername = applicationUsername;
   pigeonResult.requestData = requestData;
@@ -188,53 +189,52 @@ + (instancetype)makeWithProductIdentifier:(NSString *)productIdentifier
   pigeonResult.paymentDiscount = paymentDiscount;
   return pigeonResult;
 }
-+ (SKPaymentMessage *)fromList:(NSArray *)list {
-  SKPaymentMessage *pigeonResult = [[SKPaymentMessage alloc] init];
++ (FIASKPaymentMessage *)fromList:(NSArray *)list {
+  FIASKPaymentMessage *pigeonResult = [[FIASKPaymentMessage alloc] init];
   pigeonResult.productIdentifier = GetNullableObjectAtIndex(list, 0);
   pigeonResult.applicationUsername = GetNullableObjectAtIndex(list, 1);
   pigeonResult.requestData = GetNullableObjectAtIndex(list, 2);
   pigeonResult.quantity = [GetNullableObjectAtIndex(list, 3) integerValue];
   pigeonResult.simulatesAskToBuyInSandbox = [GetNullableObjectAtIndex(list, 4) boolValue];
-  pigeonResult.paymentDiscount =
-      [SKPaymentDiscountMessage nullableFromList:(GetNullableObjectAtIndex(list, 5))];
+  pigeonResult.paymentDiscount = GetNullableObjectAtIndex(list, 5);
   return pigeonResult;
 }
-+ (nullable SKPaymentMessage *)nullableFromList:(NSArray *)list {
-  return (list) ? [SKPaymentMessage fromList:list] : nil;
++ (nullable FIASKPaymentMessage *)nullableFromList:(NSArray *)list {
+  return (list) ? [FIASKPaymentMessage fromList:list] : nil;
 }
-- (NSArray *)toList {
+- (NSArray *)toList {
   return @[
     self.productIdentifier ?: [NSNull null],
     self.applicationUsername ?: [NSNull null],
     self.requestData ?: [NSNull null],
     @(self.quantity),
     @(self.simulatesAskToBuyInSandbox),
-    (self.paymentDiscount ? [self.paymentDiscount toList] : [NSNull null]),
+    self.paymentDiscount ?: [NSNull null],
   ];
 }
 @end
 
-@implementation SKErrorMessage
+@implementation FIASKErrorMessage
 + (instancetype)makeWithCode:(NSInteger)code
                       domain:(NSString *)domain
                     userInfo:(nullable NSDictionary *)userInfo {
-  SKErrorMessage *pigeonResult = [[SKErrorMessage alloc] init];
+  FIASKErrorMessage *pigeonResult = [[FIASKErrorMessage alloc] init];
   pigeonResult.code = code;
   pigeonResult.domain = domain;
   pigeonResult.userInfo = userInfo;
   return pigeonResult;
 }
-+ (SKErrorMessage *)fromList:(NSArray *)list {
-  SKErrorMessage *pigeonResult = [[SKErrorMessage alloc] init];
++ (FIASKErrorMessage *)fromList:(NSArray *)list {
+  FIASKErrorMessage *pigeonResult = [[FIASKErrorMessage alloc] init];
   pigeonResult.code = [GetNullableObjectAtIndex(list, 0) integerValue];
   pigeonResult.domain = GetNullableObjectAtIndex(list, 1);
   pigeonResult.userInfo = GetNullableObjectAtIndex(list, 2);
   return pigeonResult;
 }
-+ (nullable SKErrorMessage *)nullableFromList:(NSArray *)list {
-  return (list) ? [SKErrorMessage fromList:list] : nil;
++ (nullable FIASKErrorMessage *)nullableFromList:(NSArray *)list {
+  return (list) ? [FIASKErrorMessage fromList:list] : nil;
 }
-- (NSArray *)toList {
+- (NSArray *)toList {
   return @[
     @(self.code),
     self.domain ?: [NSNull null],
@@ -243,13 +243,13 @@ - (NSArray *)toList {
 }
 @end
 
-@implementation SKPaymentDiscountMessage
+@implementation FIASKPaymentDiscountMessage
 + (instancetype)makeWithIdentifier:(NSString *)identifier
                      keyIdentifier:(NSString *)keyIdentifier
                              nonce:(NSString *)nonce
                          signature:(NSString *)signature
                          timestamp:(NSInteger)timestamp {
-  SKPaymentDiscountMessage *pigeonResult = [[SKPaymentDiscountMessage alloc] init];
+  FIASKPaymentDiscountMessage *pigeonResult = [[FIASKPaymentDiscountMessage alloc] init];
   pigeonResult.identifier = identifier;
   pigeonResult.keyIdentifier = keyIdentifier;
   pigeonResult.nonce = nonce;
@@ -257,8 +257,8 @@ + (instancetype)makeWithIdentifier:(NSString *)identifier
   pigeonResult.timestamp = timestamp;
   return pigeonResult;
 }
-+ (SKPaymentDiscountMessage *)fromList:(NSArray *)list {
-  SKPaymentDiscountMessage *pigeonResult = [[SKPaymentDiscountMessage alloc] init];
++ (FIASKPaymentDiscountMessage *)fromList:(NSArray *)list {
+  FIASKPaymentDiscountMessage *pigeonResult = [[FIASKPaymentDiscountMessage alloc] init];
   pigeonResult.identifier = GetNullableObjectAtIndex(list, 0);
   pigeonResult.keyIdentifier = GetNullableObjectAtIndex(list, 1);
   pigeonResult.nonce = GetNullableObjectAtIndex(list, 2);
@@ -266,10 +266,10 @@ + (SKPaymentDiscountMessage *)fromList:(NSArray *)list {
   pigeonResult.timestamp = [GetNullableObjectAtIndex(list, 4) integerValue];
   return pigeonResult;
 }
-+ (nullable SKPaymentDiscountMessage *)nullableFromList:(NSArray *)list {
-  return (list) ? [SKPaymentDiscountMessage fromList:list] : nil;
++ (nullable FIASKPaymentDiscountMessage *)nullableFromList:(NSArray *)list {
+  return (list) ? [FIASKPaymentDiscountMessage fromList:list] : nil;
 }
-- (NSArray *)toList {
+- (NSArray *)toList {
   return @[
     self.identifier ?: [NSNull null],
     self.keyIdentifier ?: [NSNull null],
@@ -280,23 +280,23 @@ - (NSArray *)toList {
 }
 @end
 
-@implementation SKStorefrontMessage
+@implementation FIASKStorefrontMessage
 + (instancetype)makeWithCountryCode:(NSString *)countryCode identifier:(NSString *)identifier {
-  SKStorefrontMessage *pigeonResult = [[SKStorefrontMessage alloc] init];
+  FIASKStorefrontMessage *pigeonResult = [[FIASKStorefrontMessage alloc] init];
   pigeonResult.countryCode = countryCode;
   pigeonResult.identifier = identifier;
   return pigeonResult;
 }
-+ (SKStorefrontMessage *)fromList:(NSArray *)list {
-  SKStorefrontMessage *pigeonResult = [[SKStorefrontMessage alloc] init];
++ (FIASKStorefrontMessage *)fromList:(NSArray *)list {
+  FIASKStorefrontMessage *pigeonResult = [[FIASKStorefrontMessage alloc] init];
   pigeonResult.countryCode = GetNullableObjectAtIndex(list, 0);
   pigeonResult.identifier = GetNullableObjectAtIndex(list, 1);
   return pigeonResult;
 }
-+ (nullable SKStorefrontMessage *)nullableFromList:(NSArray *)list {
-  return (list) ? [SKStorefrontMessage fromList:list] : nil;
++ (nullable FIASKStorefrontMessage *)nullableFromList:(NSArray *)list {
+  return (list) ? [FIASKStorefrontMessage fromList:list] : nil;
 }
-- (NSArray *)toList {
+- (NSArray *)toList {
   return @[
     self.countryCode ?: [NSNull null],
     self.identifier ?: [NSNull null],
@@ -304,24 +304,24 @@ - (NSArray *)toList {
 }
 @end
 
-@implementation SKProductsResponseMessage
-+ (instancetype)makeWithProducts:(nullable NSArray *)products
+@implementation FIASKProductsResponseMessage
++ (instancetype)makeWithProducts:(nullable NSArray *)products
        invalidProductIdentifiers:(nullable NSArray *)invalidProductIdentifiers {
-  SKProductsResponseMessage *pigeonResult = [[SKProductsResponseMessage alloc] init];
+  FIASKProductsResponseMessage *pigeonResult = [[FIASKProductsResponseMessage alloc] init];
   pigeonResult.products = products;
   pigeonResult.invalidProductIdentifiers = invalidProductIdentifiers;
   return pigeonResult;
 }
-+ (SKProductsResponseMessage *)fromList:(NSArray *)list {
-  SKProductsResponseMessage *pigeonResult = [[SKProductsResponseMessage alloc] init];
++ (FIASKProductsResponseMessage *)fromList:(NSArray *)list {
+  FIASKProductsResponseMessage *pigeonResult = [[FIASKProductsResponseMessage alloc] init];
   pigeonResult.products = GetNullableObjectAtIndex(list, 0);
   pigeonResult.invalidProductIdentifiers = GetNullableObjectAtIndex(list, 1);
   return pigeonResult;
 }
-+ (nullable SKProductsResponseMessage *)nullableFromList:(NSArray *)list {
-  return (list) ? [SKProductsResponseMessage fromList:list] : nil;
++ (nullable FIASKProductsResponseMessage *)nullableFromList:(NSArray *)list {
+  return (list) ? [FIASKProductsResponseMessage fromList:list] : nil;
 }
-- (NSArray *)toList {
+- (NSArray *)toList {
   return @[
     self.products ?: [NSNull null],
     self.invalidProductIdentifiers ?: [NSNull null],
@@ -329,18 +329,18 @@ - (NSArray *)toList {
 }
 @end
 
-@implementation SKProductMessage
+@implementation FIASKProductMessage
 + (instancetype)
       makeWithProductIdentifier:(NSString *)productIdentifier
                  localizedTitle:(NSString *)localizedTitle
            localizedDescription:(nullable NSString *)localizedDescription
-                    priceLocale:(SKPriceLocaleMessage *)priceLocale
+                    priceLocale:(FIASKPriceLocaleMessage *)priceLocale
     subscriptionGroupIdentifier:(nullable NSString *)subscriptionGroupIdentifier
                           price:(NSString *)price
-             subscriptionPeriod:(nullable SKProductSubscriptionPeriodMessage *)subscriptionPeriod
-              introductoryPrice:(nullable SKProductDiscountMessage *)introductoryPrice
-                      discounts:(nullable NSArray *)discounts {
-  SKProductMessage *pigeonResult = [[SKProductMessage alloc] init];
+             subscriptionPeriod:(nullable FIASKProductSubscriptionPeriodMessage *)subscriptionPeriod
+              introductoryPrice:(nullable FIASKProductDiscountMessage *)introductoryPrice
+                      discounts:(nullable NSArray *)discounts {
+  FIASKProductMessage *pigeonResult = [[FIASKProductMessage alloc] init];
   pigeonResult.productIdentifier = productIdentifier;
   pigeonResult.localizedTitle = localizedTitle;
   pigeonResult.localizedDescription = localizedDescription;
@@ -352,61 +352,58 @@ @implementation SKProductMessage
   pigeonResult.discounts = discounts;
   return pigeonResult;
 }
-+ (SKProductMessage *)fromList:(NSArray *)list {
-  SKProductMessage *pigeonResult = [[SKProductMessage alloc] init];
++ (FIASKProductMessage *)fromList:(NSArray *)list {
+  FIASKProductMessage *pigeonResult = [[FIASKProductMessage alloc] init];
   pigeonResult.productIdentifier = GetNullableObjectAtIndex(list, 0);
   pigeonResult.localizedTitle = GetNullableObjectAtIndex(list, 1);
   pigeonResult.localizedDescription = GetNullableObjectAtIndex(list, 2);
-  pigeonResult.priceLocale =
-      [SKPriceLocaleMessage nullableFromList:(GetNullableObjectAtIndex(list, 3))];
+  pigeonResult.priceLocale = GetNullableObjectAtIndex(list, 3);
   pigeonResult.subscriptionGroupIdentifier = GetNullableObjectAtIndex(list, 4);
   pigeonResult.price = GetNullableObjectAtIndex(list, 5);
-  pigeonResult.subscriptionPeriod =
-      [SKProductSubscriptionPeriodMessage nullableFromList:(GetNullableObjectAtIndex(list, 6))];
-  pigeonResult.introductoryPrice =
-      [SKProductDiscountMessage nullableFromList:(GetNullableObjectAtIndex(list, 7))];
+  pigeonResult.subscriptionPeriod = GetNullableObjectAtIndex(list, 6);
+  pigeonResult.introductoryPrice = GetNullableObjectAtIndex(list, 7);
   pigeonResult.discounts = GetNullableObjectAtIndex(list, 8);
   return pigeonResult;
 }
-+ (nullable SKProductMessage *)nullableFromList:(NSArray *)list {
-  return (list) ? [SKProductMessage fromList:list] : nil;
++ (nullable FIASKProductMessage *)nullableFromList:(NSArray *)list {
+  return (list) ? [FIASKProductMessage fromList:list] : nil;
 }
-- (NSArray *)toList {
+- (NSArray *)toList {
   return @[
     self.productIdentifier ?: [NSNull null],
     self.localizedTitle ?: [NSNull null],
     self.localizedDescription ?: [NSNull null],
-    (self.priceLocale ? [self.priceLocale toList] : [NSNull null]),
+    self.priceLocale ?: [NSNull null],
     self.subscriptionGroupIdentifier ?: [NSNull null],
     self.price ?: [NSNull null],
-    (self.subscriptionPeriod ? [self.subscriptionPeriod toList] : [NSNull null]),
-    (self.introductoryPrice ? [self.introductoryPrice toList] : [NSNull null]),
+    self.subscriptionPeriod ?: [NSNull null],
+    self.introductoryPrice ?: [NSNull null],
     self.discounts ?: [NSNull null],
   ];
 }
 @end
 
-@implementation SKPriceLocaleMessage
+@implementation FIASKPriceLocaleMessage
 + (instancetype)makeWithCurrencySymbol:(NSString *)currencySymbol
                           currencyCode:(NSString *)currencyCode
                            countryCode:(NSString *)countryCode {
-  SKPriceLocaleMessage *pigeonResult = [[SKPriceLocaleMessage alloc] init];
+  FIASKPriceLocaleMessage *pigeonResult = [[FIASKPriceLocaleMessage alloc] init];
   pigeonResult.currencySymbol = currencySymbol;
   pigeonResult.currencyCode = currencyCode;
   pigeonResult.countryCode = countryCode;
   return pigeonResult;
 }
-+ (SKPriceLocaleMessage *)fromList:(NSArray *)list {
-  SKPriceLocaleMessage *pigeonResult = [[SKPriceLocaleMessage alloc] init];
++ (FIASKPriceLocaleMessage *)fromList:(NSArray *)list {
+  FIASKPriceLocaleMessage *pigeonResult = [[FIASKPriceLocaleMessage alloc] init];
   pigeonResult.currencySymbol = GetNullableObjectAtIndex(list, 0);
   pigeonResult.currencyCode = GetNullableObjectAtIndex(list, 1);
   pigeonResult.countryCode = GetNullableObjectAtIndex(list, 2);
   return pigeonResult;
 }
-+ (nullable SKPriceLocaleMessage *)nullableFromList:(NSArray *)list {
-  return (list) ? [SKPriceLocaleMessage fromList:list] : nil;
++ (nullable FIASKPriceLocaleMessage *)nullableFromList:(NSArray *)list {
+  return (list) ? [FIASKPriceLocaleMessage fromList:list] : nil;
 }
-- (NSArray *)toList {
+- (NSArray *)toList {
   return @[
     self.currencySymbol ?: [NSNull null],
     self.currencyCode ?: [NSNull null],
@@ -415,15 +412,15 @@ - (NSArray *)toList {
 }
 @end
 
-@implementation SKProductDiscountMessage
+@implementation FIASKProductDiscountMessage
 + (instancetype)makeWithPrice:(NSString *)price
-                  priceLocale:(SKPriceLocaleMessage *)priceLocale
+                  priceLocale:(FIASKPriceLocaleMessage *)priceLocale
               numberOfPeriods:(NSInteger)numberOfPeriods
-                  paymentMode:(SKProductDiscountPaymentModeMessage)paymentMode
-           subscriptionPeriod:(SKProductSubscriptionPeriodMessage *)subscriptionPeriod
+                  paymentMode:(FIASKProductDiscountPaymentModeMessage)paymentMode
+           subscriptionPeriod:(FIASKProductSubscriptionPeriodMessage *)subscriptionPeriod
                    identifier:(nullable NSString *)identifier
-                         type:(SKProductDiscountTypeMessage)type {
-  SKProductDiscountMessage *pigeonResult = [[SKProductDiscountMessage alloc] init];
+                         type:(FIASKProductDiscountTypeMessage)type {
+  FIASKProductDiscountMessage *pigeonResult = [[FIASKProductDiscountMessage alloc] init];
   pigeonResult.price = price;
   pigeonResult.priceLocale = priceLocale;
   pigeonResult.numberOfPeriods = numberOfPeriods;
@@ -433,168 +430,223 @@ + (instancetype)makeWithPrice:(NSString *)price
   pigeonResult.type = type;
   return pigeonResult;
 }
-+ (SKProductDiscountMessage *)fromList:(NSArray *)list {
-  SKProductDiscountMessage *pigeonResult = [[SKProductDiscountMessage alloc] init];
++ (FIASKProductDiscountMessage *)fromList:(NSArray *)list {
+  FIASKProductDiscountMessage *pigeonResult = [[FIASKProductDiscountMessage alloc] init];
   pigeonResult.price = GetNullableObjectAtIndex(list, 0);
-  pigeonResult.priceLocale =
-      [SKPriceLocaleMessage nullableFromList:(GetNullableObjectAtIndex(list, 1))];
+  pigeonResult.priceLocale = GetNullableObjectAtIndex(list, 1);
   pigeonResult.numberOfPeriods = [GetNullableObjectAtIndex(list, 2) integerValue];
-  pigeonResult.paymentMode = [GetNullableObjectAtIndex(list, 3) integerValue];
-  pigeonResult.subscriptionPeriod =
-      [SKProductSubscriptionPeriodMessage nullableFromList:(GetNullableObjectAtIndex(list, 4))];
+  FIASKProductDiscountPaymentModeMessageBox *boxedFIASKProductDiscountPaymentModeMessage =
+      GetNullableObjectAtIndex(list, 3);
+  pigeonResult.paymentMode = boxedFIASKProductDiscountPaymentModeMessage.value;
+  pigeonResult.subscriptionPeriod = GetNullableObjectAtIndex(list, 4);
   pigeonResult.identifier = GetNullableObjectAtIndex(list, 5);
-  pigeonResult.type = [GetNullableObjectAtIndex(list, 6) integerValue];
+  FIASKProductDiscountTypeMessageBox *boxedFIASKProductDiscountTypeMessage =
+      GetNullableObjectAtIndex(list, 6);
+  pigeonResult.type = boxedFIASKProductDiscountTypeMessage.value;
   return pigeonResult;
 }
-+ (nullable SKProductDiscountMessage *)nullableFromList:(NSArray *)list {
-  return (list) ? [SKProductDiscountMessage fromList:list] : nil;
++ (nullable FIASKProductDiscountMessage *)nullableFromList:(NSArray *)list {
+  return (list) ? [FIASKProductDiscountMessage fromList:list] : nil;
 }
-- (NSArray *)toList {
+- (NSArray *)toList {
   return @[
     self.price ?: [NSNull null],
-    (self.priceLocale ? [self.priceLocale toList] : [NSNull null]),
+    self.priceLocale ?: [NSNull null],
     @(self.numberOfPeriods),
-    @(self.paymentMode),
-    (self.subscriptionPeriod ? [self.subscriptionPeriod toList] : [NSNull null]),
+    [[FIASKProductDiscountPaymentModeMessageBox alloc] initWithValue:self.paymentMode],
+    self.subscriptionPeriod ?: [NSNull null],
     self.identifier ?: [NSNull null],
-    @(self.type),
+    [[FIASKProductDiscountTypeMessageBox alloc] initWithValue:self.type],
   ];
 }
 @end
 
-@implementation SKProductSubscriptionPeriodMessage
+@implementation FIASKProductSubscriptionPeriodMessage
 + (instancetype)makeWithNumberOfUnits:(NSInteger)numberOfUnits
-                                 unit:(SKSubscriptionPeriodUnitMessage)unit {
-  SKProductSubscriptionPeriodMessage *pigeonResult =
-      [[SKProductSubscriptionPeriodMessage alloc] init];
+                                 unit:(FIASKSubscriptionPeriodUnitMessage)unit {
+  FIASKProductSubscriptionPeriodMessage *pigeonResult =
+      [[FIASKProductSubscriptionPeriodMessage alloc] init];
   pigeonResult.numberOfUnits = numberOfUnits;
   pigeonResult.unit = unit;
   return pigeonResult;
 }
-+ (SKProductSubscriptionPeriodMessage *)fromList:(NSArray *)list {
-  SKProductSubscriptionPeriodMessage *pigeonResult =
-      [[SKProductSubscriptionPeriodMessage alloc] init];
++ (FIASKProductSubscriptionPeriodMessage *)fromList:(NSArray *)list {
+  FIASKProductSubscriptionPeriodMessage *pigeonResult =
+      [[FIASKProductSubscriptionPeriodMessage alloc] init];
   pigeonResult.numberOfUnits = [GetNullableObjectAtIndex(list, 0) integerValue];
-  pigeonResult.unit = [GetNullableObjectAtIndex(list, 1) integerValue];
+  FIASKSubscriptionPeriodUnitMessageBox *boxedFIASKSubscriptionPeriodUnitMessage =
+      GetNullableObjectAtIndex(list, 1);
+  pigeonResult.unit = boxedFIASKSubscriptionPeriodUnitMessage.value;
   return pigeonResult;
 }
-+ (nullable SKProductSubscriptionPeriodMessage *)nullableFromList:(NSArray *)list {
-  return (list) ? [SKProductSubscriptionPeriodMessage fromList:list] : nil;
++ (nullable FIASKProductSubscriptionPeriodMessage *)nullableFromList:(NSArray *)list {
+  return (list) ? [FIASKProductSubscriptionPeriodMessage fromList:list] : nil;
 }
-- (NSArray *)toList {
+- (NSArray *)toList {
   return @[
     @(self.numberOfUnits),
-    @(self.unit),
+    [[FIASKSubscriptionPeriodUnitMessageBox alloc] initWithValue:self.unit],
   ];
 }
 @end
 
-@interface InAppPurchaseAPICodecReader : FlutterStandardReader
+@interface FIAMessagesPigeonCodecReader : FlutterStandardReader
 @end
-@implementation InAppPurchaseAPICodecReader
+@implementation FIAMessagesPigeonCodecReader
 - (nullable id)readValueOfType:(UInt8)type {
   switch (type) {
-    case 128:
-      return [SKErrorMessage fromList:[self readValue]];
-    case 129:
-      return [SKPaymentDiscountMessage fromList:[self readValue]];
-    case 130:
-      return [SKPaymentMessage fromList:[self readValue]];
-    case 131:
-      return [SKPaymentTransactionMessage fromList:[self readValue]];
-    case 132:
-      return [SKPriceLocaleMessage fromList:[self readValue]];
+    case 129: {
+      NSNumber *enumAsNumber = [self readValue];
+      return enumAsNumber == nil ? nil
+                                 : [[FIASKPaymentTransactionStateMessageBox alloc]
+                                       initWithValue:[enumAsNumber integerValue]];
+    }
+    case 130: {
+      NSNumber *enumAsNumber = [self readValue];
+      return enumAsNumber == nil ? nil
+                                 : [[FIASKProductDiscountTypeMessageBox alloc]
+                                       initWithValue:[enumAsNumber integerValue]];
+    }
+    case 131: {
+      NSNumber *enumAsNumber = [self readValue];
+      return enumAsNumber == nil ? nil
+                                 : [[FIASKProductDiscountPaymentModeMessageBox alloc]
+                                       initWithValue:[enumAsNumber integerValue]];
+    }
+    case 132: {
+      NSNumber *enumAsNumber = [self readValue];
+      return enumAsNumber == nil ? nil
+                                 : [[FIASKSubscriptionPeriodUnitMessageBox alloc]
+                                       initWithValue:[enumAsNumber integerValue]];
+    }
     case 133:
-      return [SKProductDiscountMessage fromList:[self readValue]];
+      return [FIASKPaymentTransactionMessage fromList:[self readValue]];
     case 134:
-      return [SKProductMessage fromList:[self readValue]];
+      return [FIASKPaymentMessage fromList:[self readValue]];
     case 135:
-      return [SKProductSubscriptionPeriodMessage fromList:[self readValue]];
+      return [FIASKErrorMessage fromList:[self readValue]];
     case 136:
-      return [SKProductsResponseMessage fromList:[self readValue]];
+      return [FIASKPaymentDiscountMessage fromList:[self readValue]];
     case 137:
-      return [SKStorefrontMessage fromList:[self readValue]];
+      return [FIASKStorefrontMessage fromList:[self readValue]];
+    case 138:
+      return [FIASKProductsResponseMessage fromList:[self readValue]];
+    case 139:
+      return [FIASKProductMessage fromList:[self readValue]];
+    case 140:
+      return [FIASKPriceLocaleMessage fromList:[self readValue]];
+    case 141:
+      return [FIASKProductDiscountMessage fromList:[self readValue]];
+    case 142:
+      return [FIASKProductSubscriptionPeriodMessage fromList:[self readValue]];
     default:
       return [super readValueOfType:type];
   }
 }
 @end
 
-@interface InAppPurchaseAPICodecWriter : FlutterStandardWriter
+@interface FIAMessagesPigeonCodecWriter : FlutterStandardWriter
 @end
-@implementation InAppPurchaseAPICodecWriter
+@implementation FIAMessagesPigeonCodecWriter
 - (void)writeValue:(id)value {
-  if ([value isKindOfClass:[SKErrorMessage class]]) {
-    [self writeByte:128];
-    [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[SKPaymentDiscountMessage class]]) {
+  if ([value isKindOfClass:[FIASKPaymentTransactionStateMessageBox class]]) {
+    FIASKPaymentTransactionStateMessageBox *box = (FIASKPaymentTransactionStateMessageBox *)value;
     [self writeByte:129];
-    [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[SKPaymentMessage class]]) {
+    [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])];
+  } else if ([value isKindOfClass:[FIASKProductDiscountTypeMessageBox class]]) {
+    FIASKProductDiscountTypeMessageBox *box = (FIASKProductDiscountTypeMessageBox *)value;
     [self writeByte:130];
-    [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[SKPaymentTransactionMessage class]]) {
+    [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])];
+  } else if ([value isKindOfClass:[FIASKProductDiscountPaymentModeMessageBox class]]) {
+    FIASKProductDiscountPaymentModeMessageBox *box =
+        (FIASKProductDiscountPaymentModeMessageBox *)value;
     [self writeByte:131];
-    [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[SKPriceLocaleMessage class]]) {
+    [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])];
+  } else if ([value isKindOfClass:[FIASKSubscriptionPeriodUnitMessageBox class]]) {
+    FIASKSubscriptionPeriodUnitMessageBox *box = (FIASKSubscriptionPeriodUnitMessageBox *)value;
     [self writeByte:132];
-    [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[SKProductDiscountMessage class]]) {
+    [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])];
+  } else if ([value isKindOfClass:[FIASKPaymentTransactionMessage class]]) {
     [self writeByte:133];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[SKProductMessage class]]) {
+  } else if ([value isKindOfClass:[FIASKPaymentMessage class]]) {
     [self writeByte:134];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[SKProductSubscriptionPeriodMessage class]]) {
+  } else if ([value isKindOfClass:[FIASKErrorMessage class]]) {
     [self writeByte:135];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[SKProductsResponseMessage class]]) {
+  } else if ([value isKindOfClass:[FIASKPaymentDiscountMessage class]]) {
     [self writeByte:136];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[SKStorefrontMessage class]]) {
+  } else if ([value isKindOfClass:[FIASKStorefrontMessage class]]) {
     [self writeByte:137];
     [self writeValue:[value toList]];
+  } else if ([value isKindOfClass:[FIASKProductsResponseMessage class]]) {
+    [self writeByte:138];
+    [self writeValue:[value toList]];
+  } else if ([value isKindOfClass:[FIASKProductMessage class]]) {
+    [self writeByte:139];
+    [self writeValue:[value toList]];
+  } else if ([value isKindOfClass:[FIASKPriceLocaleMessage class]]) {
+    [self writeByte:140];
+    [self writeValue:[value toList]];
+  } else if ([value isKindOfClass:[FIASKProductDiscountMessage class]]) {
+    [self writeByte:141];
+    [self writeValue:[value toList]];
+  } else if ([value isKindOfClass:[FIASKProductSubscriptionPeriodMessage class]]) {
+    [self writeByte:142];
+    [self writeValue:[value toList]];
   } else {
     [super writeValue:value];
   }
 }
 @end
 
-@interface InAppPurchaseAPICodecReaderWriter : FlutterStandardReaderWriter
+@interface FIAMessagesPigeonCodecReaderWriter : FlutterStandardReaderWriter
 @end
-@implementation InAppPurchaseAPICodecReaderWriter
+@implementation FIAMessagesPigeonCodecReaderWriter
 - (FlutterStandardWriter *)writerWithData:(NSMutableData *)data {
-  return [[InAppPurchaseAPICodecWriter alloc] initWithData:data];
+  return [[FIAMessagesPigeonCodecWriter alloc] initWithData:data];
 }
 - (FlutterStandardReader *)readerWithData:(NSData *)data {
-  return [[InAppPurchaseAPICodecReader alloc] initWithData:data];
+  return [[FIAMessagesPigeonCodecReader alloc] initWithData:data];
 }
 @end
 
-NSObject *InAppPurchaseAPIGetCodec(void) {
+NSObject *FIAGetMessagesCodec(void) {
   static FlutterStandardMessageCodec *sSharedObject = nil;
   static dispatch_once_t sPred = 0;
   dispatch_once(&sPred, ^{
-    InAppPurchaseAPICodecReaderWriter *readerWriter =
-        [[InAppPurchaseAPICodecReaderWriter alloc] init];
+    FIAMessagesPigeonCodecReaderWriter *readerWriter =
+        [[FIAMessagesPigeonCodecReaderWriter alloc] init];
     sSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter];
   });
   return sSharedObject;
 }
+void SetUpFIAInAppPurchaseAPI(id binaryMessenger,
+                              NSObject *api) {
+  SetUpFIAInAppPurchaseAPIWithSuffix(binaryMessenger, api, @"");
+}
 
-void SetUpInAppPurchaseAPI(id binaryMessenger,
-                           NSObject *api) {
+void SetUpFIAInAppPurchaseAPIWithSuffix(id binaryMessenger,
+                                        NSObject *api,
+                                        NSString *messageChannelSuffix) {
+  messageChannelSuffix = messageChannelSuffix.length > 0
+                             ? [NSString stringWithFormat:@".%@", messageChannelSuffix]
+                             : @"";
   /// Returns if the current device is able to make payments
   {
     FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
-           initWithName:
-               @"dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.canMakePayments"
+           initWithName:[NSString stringWithFormat:@"%@%@",
+                                                   @"dev.flutter.pigeon.in_app_purchase_storekit."
+                                                   @"InAppPurchaseAPI.canMakePayments",
+                                                   messageChannelSuffix]
         binaryMessenger:binaryMessenger
-                  codec:InAppPurchaseAPIGetCodec()];
+                  codec:FIAGetMessagesCodec()];
     if (api) {
       NSCAssert(
           [api respondsToSelector:@selector(canMakePaymentsWithError:)],
-          @"InAppPurchaseAPI api (%@) doesn't respond to @selector(canMakePaymentsWithError:)",
+          @"FIAInAppPurchaseAPI api (%@) doesn't respond to @selector(canMakePaymentsWithError:)",
           api);
       [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
         FlutterError *error;
@@ -607,16 +659,20 @@ void SetUpInAppPurchaseAPI(id binaryMessenger,
   }
   {
     FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
-           initWithName:@"dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.transactions"
+           initWithName:[NSString stringWithFormat:@"%@%@",
+                                                   @"dev.flutter.pigeon.in_app_purchase_storekit."
+                                                   @"InAppPurchaseAPI.transactions",
+                                                   messageChannelSuffix]
         binaryMessenger:binaryMessenger
-                  codec:InAppPurchaseAPIGetCodec()];
+                  codec:FIAGetMessagesCodec()];
     if (api) {
-      NSCAssert([api respondsToSelector:@selector(transactionsWithError:)],
-                @"InAppPurchaseAPI api (%@) doesn't respond to @selector(transactionsWithError:)",
-                api);
+      NSCAssert(
+          [api respondsToSelector:@selector(transactionsWithError:)],
+          @"FIAInAppPurchaseAPI api (%@) doesn't respond to @selector(transactionsWithError:)",
+          api);
       [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
         FlutterError *error;
-        NSArray *output = [api transactionsWithError:&error];
+        NSArray *output = [api transactionsWithError:&error];
         callback(wrapResult(output, error));
       }];
     } else {
@@ -625,16 +681,19 @@ void SetUpInAppPurchaseAPI(id binaryMessenger,
   }
   {
     FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
-           initWithName:@"dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.storefront"
+           initWithName:[NSString stringWithFormat:@"%@%@",
+                                                   @"dev.flutter.pigeon.in_app_purchase_storekit."
+                                                   @"InAppPurchaseAPI.storefront",
+                                                   messageChannelSuffix]
         binaryMessenger:binaryMessenger
-                  codec:InAppPurchaseAPIGetCodec()];
+                  codec:FIAGetMessagesCodec()];
     if (api) {
       NSCAssert([api respondsToSelector:@selector(storefrontWithError:)],
-                @"InAppPurchaseAPI api (%@) doesn't respond to @selector(storefrontWithError:)",
+                @"FIAInAppPurchaseAPI api (%@) doesn't respond to @selector(storefrontWithError:)",
                 api);
       [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
         FlutterError *error;
-        SKStorefrontMessage *output = [api storefrontWithError:&error];
+        FIASKStorefrontMessage *output = [api storefrontWithError:&error];
         callback(wrapResult(output, error));
       }];
     } else {
@@ -643,16 +702,19 @@ void SetUpInAppPurchaseAPI(id binaryMessenger,
   }
   {
     FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
-           initWithName:@"dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.addPayment"
+           initWithName:[NSString stringWithFormat:@"%@%@",
+                                                   @"dev.flutter.pigeon.in_app_purchase_storekit."
+                                                   @"InAppPurchaseAPI.addPayment",
+                                                   messageChannelSuffix]
         binaryMessenger:binaryMessenger
-                  codec:InAppPurchaseAPIGetCodec()];
+                  codec:FIAGetMessagesCodec()];
     if (api) {
       NSCAssert(
           [api respondsToSelector:@selector(addPaymentPaymentMap:error:)],
-          @"InAppPurchaseAPI api (%@) doesn't respond to @selector(addPaymentPaymentMap:error:)",
+          @"FIAInAppPurchaseAPI api (%@) doesn't respond to @selector(addPaymentPaymentMap:error:)",
           api);
       [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
-        NSArray *args = message;
+        NSArray *args = message;
         NSDictionary *arg_paymentMap = GetNullableObjectAtIndex(args, 0);
         FlutterError *error;
         [api addPaymentPaymentMap:arg_paymentMap error:&error];
@@ -664,21 +726,23 @@ void SetUpInAppPurchaseAPI(id binaryMessenger,
   }
   {
     FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
-           initWithName:
-               @"dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.startProductRequest"
+           initWithName:[NSString stringWithFormat:@"%@%@",
+                                                   @"dev.flutter.pigeon.in_app_purchase_storekit."
+                                                   @"InAppPurchaseAPI.startProductRequest",
+                                                   messageChannelSuffix]
         binaryMessenger:binaryMessenger
-                  codec:InAppPurchaseAPIGetCodec()];
+                  codec:FIAGetMessagesCodec()];
     if (api) {
       NSCAssert([api respondsToSelector:@selector(startProductRequestProductIdentifiers:
                                                                              completion:)],
-                @"InAppPurchaseAPI api (%@) doesn't respond to "
+                @"FIAInAppPurchaseAPI api (%@) doesn't respond to "
                 @"@selector(startProductRequestProductIdentifiers:completion:)",
                 api);
       [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
-        NSArray *args = message;
+        NSArray *args = message;
         NSArray *arg_productIdentifiers = GetNullableObjectAtIndex(args, 0);
         [api startProductRequestProductIdentifiers:arg_productIdentifiers
-                                        completion:^(SKProductsResponseMessage *_Nullable output,
+                                        completion:^(FIASKProductsResponseMessage *_Nullable output,
                                                      FlutterError *_Nullable error) {
                                           callback(wrapResult(output, error));
                                         }];
@@ -689,17 +753,19 @@ void SetUpInAppPurchaseAPI(id binaryMessenger,
   }
   {
     FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
-           initWithName:
-               @"dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.finishTransaction"
+           initWithName:[NSString stringWithFormat:@"%@%@",
+                                                   @"dev.flutter.pigeon.in_app_purchase_storekit."
+                                                   @"InAppPurchaseAPI.finishTransaction",
+                                                   messageChannelSuffix]
         binaryMessenger:binaryMessenger
-                  codec:InAppPurchaseAPIGetCodec()];
+                  codec:FIAGetMessagesCodec()];
     if (api) {
       NSCAssert([api respondsToSelector:@selector(finishTransactionFinishMap:error:)],
-                @"InAppPurchaseAPI api (%@) doesn't respond to "
+                @"FIAInAppPurchaseAPI api (%@) doesn't respond to "
                 @"@selector(finishTransactionFinishMap:error:)",
                 api);
       [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
-        NSArray *args = message;
+        NSArray *args = message;
         NSDictionary *arg_finishMap = GetNullableObjectAtIndex(args, 0);
         FlutterError *error;
         [api finishTransactionFinishMap:arg_finishMap error:&error];
@@ -711,17 +777,19 @@ void SetUpInAppPurchaseAPI(id binaryMessenger,
   }
   {
     FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
-           initWithName:
-               @"dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.restoreTransactions"
+           initWithName:[NSString stringWithFormat:@"%@%@",
+                                                   @"dev.flutter.pigeon.in_app_purchase_storekit."
+                                                   @"InAppPurchaseAPI.restoreTransactions",
+                                                   messageChannelSuffix]
         binaryMessenger:binaryMessenger
-                  codec:InAppPurchaseAPIGetCodec()];
+                  codec:FIAGetMessagesCodec()];
     if (api) {
       NSCAssert([api respondsToSelector:@selector(restoreTransactionsApplicationUserName:error:)],
-                @"InAppPurchaseAPI api (%@) doesn't respond to "
+                @"FIAInAppPurchaseAPI api (%@) doesn't respond to "
                 @"@selector(restoreTransactionsApplicationUserName:error:)",
                 api);
       [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
-        NSArray *args = message;
+        NSArray *args = message;
         NSString *arg_applicationUserName = GetNullableObjectAtIndex(args, 0);
         FlutterError *error;
         [api restoreTransactionsApplicationUserName:arg_applicationUserName error:&error];
@@ -733,13 +801,15 @@ void SetUpInAppPurchaseAPI(id binaryMessenger,
   }
   {
     FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
-           initWithName:@"dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI."
-                        @"presentCodeRedemptionSheet"
+           initWithName:[NSString stringWithFormat:@"%@%@",
+                                                   @"dev.flutter.pigeon.in_app_purchase_storekit."
+                                                   @"InAppPurchaseAPI.presentCodeRedemptionSheet",
+                                                   messageChannelSuffix]
         binaryMessenger:binaryMessenger
-                  codec:InAppPurchaseAPIGetCodec()];
+                  codec:FIAGetMessagesCodec()];
     if (api) {
       NSCAssert([api respondsToSelector:@selector(presentCodeRedemptionSheetWithError:)],
-                @"InAppPurchaseAPI api (%@) doesn't respond to "
+                @"FIAInAppPurchaseAPI api (%@) doesn't respond to "
                 @"@selector(presentCodeRedemptionSheetWithError:)",
                 api);
       [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
@@ -753,15 +823,17 @@ void SetUpInAppPurchaseAPI(id binaryMessenger,
   }
   {
     FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
-           initWithName:
-               @"dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.retrieveReceiptData"
+           initWithName:[NSString stringWithFormat:@"%@%@",
+                                                   @"dev.flutter.pigeon.in_app_purchase_storekit."
+                                                   @"InAppPurchaseAPI.retrieveReceiptData",
+                                                   messageChannelSuffix]
         binaryMessenger:binaryMessenger
-                  codec:InAppPurchaseAPIGetCodec()];
+                  codec:FIAGetMessagesCodec()];
     if (api) {
-      NSCAssert(
-          [api respondsToSelector:@selector(retrieveReceiptDataWithError:)],
-          @"InAppPurchaseAPI api (%@) doesn't respond to @selector(retrieveReceiptDataWithError:)",
-          api);
+      NSCAssert([api respondsToSelector:@selector(retrieveReceiptDataWithError:)],
+                @"FIAInAppPurchaseAPI api (%@) doesn't respond to "
+                @"@selector(retrieveReceiptDataWithError:)",
+                api);
       [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
         FlutterError *error;
         NSString *output = [api retrieveReceiptDataWithError:&error];
@@ -773,17 +845,19 @@ void SetUpInAppPurchaseAPI(id binaryMessenger,
   }
   {
     FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
-           initWithName:
-               @"dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.refreshReceipt"
+           initWithName:[NSString stringWithFormat:@"%@%@",
+                                                   @"dev.flutter.pigeon.in_app_purchase_storekit."
+                                                   @"InAppPurchaseAPI.refreshReceipt",
+                                                   messageChannelSuffix]
         binaryMessenger:binaryMessenger
-                  codec:InAppPurchaseAPIGetCodec()];
+                  codec:FIAGetMessagesCodec()];
     if (api) {
       NSCAssert([api respondsToSelector:@selector(refreshReceiptReceiptProperties:completion:)],
-                @"InAppPurchaseAPI api (%@) doesn't respond to "
+                @"FIAInAppPurchaseAPI api (%@) doesn't respond to "
                 @"@selector(refreshReceiptReceiptProperties:completion:)",
                 api);
       [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
-        NSArray *args = message;
+        NSArray *args = message;
         NSDictionary *arg_receiptProperties = GetNullableObjectAtIndex(args, 0);
         [api refreshReceiptReceiptProperties:arg_receiptProperties
                                   completion:^(FlutterError *_Nullable error) {
@@ -796,13 +870,15 @@ void SetUpInAppPurchaseAPI(id binaryMessenger,
   }
   {
     FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
-           initWithName:@"dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI."
-                        @"startObservingPaymentQueue"
+           initWithName:[NSString stringWithFormat:@"%@%@",
+                                                   @"dev.flutter.pigeon.in_app_purchase_storekit."
+                                                   @"InAppPurchaseAPI.startObservingPaymentQueue",
+                                                   messageChannelSuffix]
         binaryMessenger:binaryMessenger
-                  codec:InAppPurchaseAPIGetCodec()];
+                  codec:FIAGetMessagesCodec()];
     if (api) {
       NSCAssert([api respondsToSelector:@selector(startObservingPaymentQueueWithError:)],
-                @"InAppPurchaseAPI api (%@) doesn't respond to "
+                @"FIAInAppPurchaseAPI api (%@) doesn't respond to "
                 @"@selector(startObservingPaymentQueueWithError:)",
                 api);
       [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
@@ -816,13 +892,15 @@ void SetUpInAppPurchaseAPI(id binaryMessenger,
   }
   {
     FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
-           initWithName:@"dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI."
-                        @"stopObservingPaymentQueue"
+           initWithName:[NSString stringWithFormat:@"%@%@",
+                                                   @"dev.flutter.pigeon.in_app_purchase_storekit."
+                                                   @"InAppPurchaseAPI.stopObservingPaymentQueue",
+                                                   messageChannelSuffix]
         binaryMessenger:binaryMessenger
-                  codec:InAppPurchaseAPIGetCodec()];
+                  codec:FIAGetMessagesCodec()];
     if (api) {
       NSCAssert([api respondsToSelector:@selector(stopObservingPaymentQueueWithError:)],
-                @"InAppPurchaseAPI api (%@) doesn't respond to "
+                @"FIAInAppPurchaseAPI api (%@) doesn't respond to "
                 @"@selector(stopObservingPaymentQueueWithError:)",
                 api);
       [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
@@ -836,13 +914,15 @@ void SetUpInAppPurchaseAPI(id binaryMessenger,
   }
   {
     FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
-           initWithName:@"dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI."
-                        @"registerPaymentQueueDelegate"
+           initWithName:[NSString stringWithFormat:@"%@%@",
+                                                   @"dev.flutter.pigeon.in_app_purchase_storekit."
+                                                   @"InAppPurchaseAPI.registerPaymentQueueDelegate",
+                                                   messageChannelSuffix]
         binaryMessenger:binaryMessenger
-                  codec:InAppPurchaseAPIGetCodec()];
+                  codec:FIAGetMessagesCodec()];
     if (api) {
       NSCAssert([api respondsToSelector:@selector(registerPaymentQueueDelegateWithError:)],
-                @"InAppPurchaseAPI api (%@) doesn't respond to "
+                @"FIAInAppPurchaseAPI api (%@) doesn't respond to "
                 @"@selector(registerPaymentQueueDelegateWithError:)",
                 api);
       [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
@@ -856,13 +936,15 @@ void SetUpInAppPurchaseAPI(id binaryMessenger,
   }
   {
     FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
-           initWithName:@"dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI."
-                        @"removePaymentQueueDelegate"
+           initWithName:[NSString stringWithFormat:@"%@%@",
+                                                   @"dev.flutter.pigeon.in_app_purchase_storekit."
+                                                   @"InAppPurchaseAPI.removePaymentQueueDelegate",
+                                                   messageChannelSuffix]
         binaryMessenger:binaryMessenger
-                  codec:InAppPurchaseAPIGetCodec()];
+                  codec:FIAGetMessagesCodec()];
     if (api) {
       NSCAssert([api respondsToSelector:@selector(removePaymentQueueDelegateWithError:)],
-                @"InAppPurchaseAPI api (%@) doesn't respond to "
+                @"FIAInAppPurchaseAPI api (%@) doesn't respond to "
                 @"@selector(removePaymentQueueDelegateWithError:)",
                 api);
       [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
@@ -876,13 +958,15 @@ void SetUpInAppPurchaseAPI(id binaryMessenger,
   }
   {
     FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
-           initWithName:@"dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI."
-                        @"showPriceConsentIfNeeded"
+           initWithName:[NSString stringWithFormat:@"%@%@",
+                                                   @"dev.flutter.pigeon.in_app_purchase_storekit."
+                                                   @"InAppPurchaseAPI.showPriceConsentIfNeeded",
+                                                   messageChannelSuffix]
         binaryMessenger:binaryMessenger
-                  codec:InAppPurchaseAPIGetCodec()];
+                  codec:FIAGetMessagesCodec()];
     if (api) {
       NSCAssert([api respondsToSelector:@selector(showPriceConsentIfNeededWithError:)],
-                @"InAppPurchaseAPI api (%@) doesn't respond to "
+                @"FIAInAppPurchaseAPI api (%@) doesn't respond to "
                 @"@selector(showPriceConsentIfNeededWithError:)",
                 api);
       [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/TranslatorTests.swift b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/TranslatorTests.swift
index 204b2f2dbfce..f7e384804033 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/TranslatorTests.swift
+++ b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/TranslatorTests.swift
@@ -473,7 +473,7 @@ final class ObjectTranslatorTest: XCTestCase {
 
   func testSKErrorConvertToPigeon() throws {
     let error = NSError(domain: SKErrorDomain, code: 3, userInfo: ["key": 42])
-    let msg = SKErrorMessage.make(
+    let msg = FIASKErrorMessage.make(
       withCode: 3, domain: SKErrorDomain, userInfo: ["key": 42] as [String: Any])
     let skerror = try XCTUnwrap(FIAObjectTranslator.convertSKError(toPigeon: error))
 
@@ -507,7 +507,7 @@ final class ObjectTranslatorTest: XCTestCase {
     let unwrappedMsg = try XCTUnwrap(msg)
     let unwrappedTimeStamp = try XCTUnwrap(unwrappedMsg.transactionTimeStamp)
 
-    XCTAssertEqual(unwrappedMsg.transactionState, SKPaymentTransactionStateMessage.purchasing)
+    XCTAssertEqual(unwrappedMsg.transactionState, FIASKPaymentTransactionStateMessage.purchasing)
     XCTAssertEqual(
       paymentTransaction.transactionDate,
       Date(timeIntervalSince1970: TimeInterval(truncating: unwrappedTimeStamp)))
@@ -537,13 +537,13 @@ final class ObjectTranslatorTest: XCTestCase {
     XCTAssertEqual(localeMsg.currencySymbol, "\u{00a4}")
 
     let subPeriod = try XCTUnwrap(productMsg.subscriptionPeriod)
-    XCTAssertEqual(subPeriod.unit, SKSubscriptionPeriodUnitMessage.day)
+    XCTAssertEqual(subPeriod.unit, FIASKSubscriptionPeriodUnitMessage.day)
     XCTAssertEqual(subPeriod.numberOfUnits, 0)
 
     let introDiscount = try XCTUnwrap(productMsg.introductoryPrice)
     XCTAssertEqual(introDiscount.price, "1")
     XCTAssertEqual(introDiscount.numberOfPeriods, 1)
-    XCTAssertEqual(introDiscount.paymentMode, SKProductDiscountPaymentModeMessage.payUpFront)
+    XCTAssertEqual(introDiscount.paymentMode, FIASKProductDiscountPaymentModeMessage.payUpFront)
 
     let discounts = try XCTUnwrap(productMsg.discounts)
     XCTAssertEqual(discounts.count, 1)
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/messages.g.dart b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/messages.g.dart
index a53187575e1d..8679df86f749 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/messages.g.dart
+++ b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/messages.g.dart
@@ -1,7 +1,7 @@
 // Copyright 2013 The Flutter Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-// Autogenerated from Pigeon (v16.0.5), do not edit directly.
+// Autogenerated from Pigeon (v22.4.2), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers
 
@@ -119,29 +119,24 @@ class SKPaymentTransactionMessage {
 
   Object encode() {
     return [
-      payment.encode(),
-      transactionState.index,
-      originalTransaction?.encode(),
+      payment,
+      transactionState,
+      originalTransaction,
       transactionTimeStamp,
       transactionIdentifier,
-      error?.encode(),
+      error,
     ];
   }
 
   static SKPaymentTransactionMessage decode(Object result) {
     result as List;
     return SKPaymentTransactionMessage(
-      payment: SKPaymentMessage.decode(result[0]! as List),
-      transactionState:
-          SKPaymentTransactionStateMessage.values[result[1]! as int],
-      originalTransaction: result[2] != null
-          ? SKPaymentTransactionMessage.decode(result[2]! as List)
-          : null,
+      payment: result[0]! as SKPaymentMessage,
+      transactionState: result[1]! as SKPaymentTransactionStateMessage,
+      originalTransaction: result[2] as SKPaymentTransactionMessage?,
       transactionTimeStamp: result[3] as double?,
       transactionIdentifier: result[4] as String?,
-      error: result[5] != null
-          ? SKErrorMessage.decode(result[5]! as List)
-          : null,
+      error: result[5] as SKErrorMessage?,
     );
   }
 }
@@ -175,7 +170,7 @@ class SKPaymentMessage {
       requestData,
       quantity,
       simulatesAskToBuyInSandbox,
-      paymentDiscount?.encode(),
+      paymentDiscount,
     ];
   }
 
@@ -187,9 +182,7 @@ class SKPaymentMessage {
       requestData: result[2] as String?,
       quantity: result[3]! as int,
       simulatesAskToBuyInSandbox: result[4]! as bool,
-      paymentDiscount: result[5] != null
-          ? SKPaymentDiscountMessage.decode(result[5]! as List)
-          : null,
+      paymentDiscount: result[5] as SKPaymentDiscountMessage?,
     );
   }
 }
@@ -205,7 +198,7 @@ class SKErrorMessage {
 
   String domain;
 
-  Map? userInfo;
+  Map? userInfo;
 
   Object encode() {
     return [
@@ -220,7 +213,7 @@ class SKErrorMessage {
     return SKErrorMessage(
       code: result[0]! as int,
       domain: result[1]! as String,
-      userInfo: (result[2] as Map?)?.cast(),
+      userInfo: (result[2] as Map?)?.cast(),
     );
   }
 }
@@ -298,9 +291,9 @@ class SKProductsResponseMessage {
     this.invalidProductIdentifiers,
   });
 
-  List? products;
+  List? products;
 
-  List? invalidProductIdentifiers;
+  List? invalidProductIdentifiers;
 
   Object encode() {
     return [
@@ -312,8 +305,8 @@ class SKProductsResponseMessage {
   static SKProductsResponseMessage decode(Object result) {
     result as List;
     return SKProductsResponseMessage(
-      products: (result[0] as List?)?.cast(),
-      invalidProductIdentifiers: (result[1] as List?)?.cast(),
+      products: (result[0] as List?)?.cast(),
+      invalidProductIdentifiers: (result[1] as List?)?.cast(),
     );
   }
 }
@@ -347,18 +340,18 @@ class SKProductMessage {
 
   SKProductDiscountMessage? introductoryPrice;
 
-  List? discounts;
+  List? discounts;
 
   Object encode() {
     return [
       productIdentifier,
       localizedTitle,
       localizedDescription,
-      priceLocale.encode(),
+      priceLocale,
       subscriptionGroupIdentifier,
       price,
-      subscriptionPeriod?.encode(),
-      introductoryPrice?.encode(),
+      subscriptionPeriod,
+      introductoryPrice,
       discounts,
     ];
   }
@@ -369,18 +362,13 @@ class SKProductMessage {
       productIdentifier: result[0]! as String,
       localizedTitle: result[1]! as String,
       localizedDescription: result[2] as String?,
-      priceLocale: SKPriceLocaleMessage.decode(result[3]! as List),
+      priceLocale: result[3]! as SKPriceLocaleMessage,
       subscriptionGroupIdentifier: result[4] as String?,
       price: result[5]! as String,
-      subscriptionPeriod: result[6] != null
-          ? SKProductSubscriptionPeriodMessage.decode(
-              result[6]! as List)
-          : null,
-      introductoryPrice: result[7] != null
-          ? SKProductDiscountMessage.decode(result[7]! as List)
-          : null,
+      subscriptionPeriod: result[6] as SKProductSubscriptionPeriodMessage?,
+      introductoryPrice: result[7] as SKProductDiscountMessage?,
       discounts:
-          (result[8] as List?)?.cast(),
+          (result[8] as List?)?.cast(),
     );
   }
 }
@@ -447,12 +435,12 @@ class SKProductDiscountMessage {
   Object encode() {
     return [
       price,
-      priceLocale.encode(),
+      priceLocale,
       numberOfPeriods,
-      paymentMode.index,
-      subscriptionPeriod.encode(),
+      paymentMode,
+      subscriptionPeriod,
       identifier,
-      type.index,
+      type,
     ];
   }
 
@@ -460,14 +448,12 @@ class SKProductDiscountMessage {
     result as List;
     return SKProductDiscountMessage(
       price: result[0]! as String,
-      priceLocale: SKPriceLocaleMessage.decode(result[1]! as List),
+      priceLocale: result[1]! as SKPriceLocaleMessage,
       numberOfPeriods: result[2]! as int,
-      paymentMode:
-          SKProductDiscountPaymentModeMessage.values[result[3]! as int],
-      subscriptionPeriod: SKProductSubscriptionPeriodMessage.decode(
-          result[4]! as List),
+      paymentMode: result[3]! as SKProductDiscountPaymentModeMessage,
+      subscriptionPeriod: result[4]! as SKProductSubscriptionPeriodMessage,
       identifier: result[5] as String?,
-      type: SKProductDiscountTypeMessage.values[result[6]! as int],
+      type: result[6]! as SKProductDiscountTypeMessage,
     );
   }
 }
@@ -485,7 +471,7 @@ class SKProductSubscriptionPeriodMessage {
   Object encode() {
     return [
       numberOfUnits,
-      unit.index,
+      unit,
     ];
   }
 
@@ -493,45 +479,60 @@ class SKProductSubscriptionPeriodMessage {
     result as List;
     return SKProductSubscriptionPeriodMessage(
       numberOfUnits: result[0]! as int,
-      unit: SKSubscriptionPeriodUnitMessage.values[result[1]! as int],
+      unit: result[1]! as SKSubscriptionPeriodUnitMessage,
     );
   }
 }
 
-class _InAppPurchaseAPICodec extends StandardMessageCodec {
-  const _InAppPurchaseAPICodec();
+class _PigeonCodec extends StandardMessageCodec {
+  const _PigeonCodec();
   @override
   void writeValue(WriteBuffer buffer, Object? value) {
-    if (value is SKErrorMessage) {
-      buffer.putUint8(128);
-      writeValue(buffer, value.encode());
-    } else if (value is SKPaymentDiscountMessage) {
+    if (value is int) {
+      buffer.putUint8(4);
+      buffer.putInt64(value);
+    } else if (value is SKPaymentTransactionStateMessage) {
       buffer.putUint8(129);
-      writeValue(buffer, value.encode());
-    } else if (value is SKPaymentMessage) {
+      writeValue(buffer, value.index);
+    } else if (value is SKProductDiscountTypeMessage) {
       buffer.putUint8(130);
-      writeValue(buffer, value.encode());
-    } else if (value is SKPaymentTransactionMessage) {
+      writeValue(buffer, value.index);
+    } else if (value is SKProductDiscountPaymentModeMessage) {
       buffer.putUint8(131);
-      writeValue(buffer, value.encode());
-    } else if (value is SKPriceLocaleMessage) {
+      writeValue(buffer, value.index);
+    } else if (value is SKSubscriptionPeriodUnitMessage) {
       buffer.putUint8(132);
-      writeValue(buffer, value.encode());
-    } else if (value is SKProductDiscountMessage) {
+      writeValue(buffer, value.index);
+    } else if (value is SKPaymentTransactionMessage) {
       buffer.putUint8(133);
       writeValue(buffer, value.encode());
-    } else if (value is SKProductMessage) {
+    } else if (value is SKPaymentMessage) {
       buffer.putUint8(134);
       writeValue(buffer, value.encode());
-    } else if (value is SKProductSubscriptionPeriodMessage) {
+    } else if (value is SKErrorMessage) {
       buffer.putUint8(135);
       writeValue(buffer, value.encode());
-    } else if (value is SKProductsResponseMessage) {
+    } else if (value is SKPaymentDiscountMessage) {
       buffer.putUint8(136);
       writeValue(buffer, value.encode());
     } else if (value is SKStorefrontMessage) {
       buffer.putUint8(137);
       writeValue(buffer, value.encode());
+    } else if (value is SKProductsResponseMessage) {
+      buffer.putUint8(138);
+      writeValue(buffer, value.encode());
+    } else if (value is SKProductMessage) {
+      buffer.putUint8(139);
+      writeValue(buffer, value.encode());
+    } else if (value is SKPriceLocaleMessage) {
+      buffer.putUint8(140);
+      writeValue(buffer, value.encode());
+    } else if (value is SKProductDiscountMessage) {
+      buffer.putUint8(141);
+      writeValue(buffer, value.encode());
+    } else if (value is SKProductSubscriptionPeriodMessage) {
+      buffer.putUint8(142);
+      writeValue(buffer, value.encode());
     } else {
       super.writeValue(buffer, value);
     }
@@ -540,26 +541,46 @@ class _InAppPurchaseAPICodec extends StandardMessageCodec {
   @override
   Object? readValueOfType(int type, ReadBuffer buffer) {
     switch (type) {
-      case 128:
-        return SKErrorMessage.decode(readValue(buffer)!);
       case 129:
-        return SKPaymentDiscountMessage.decode(readValue(buffer)!);
+        final int? value = readValue(buffer) as int?;
+        return value == null
+            ? null
+            : SKPaymentTransactionStateMessage.values[value];
       case 130:
-        return SKPaymentMessage.decode(readValue(buffer)!);
+        final int? value = readValue(buffer) as int?;
+        return value == null
+            ? null
+            : SKProductDiscountTypeMessage.values[value];
       case 131:
-        return SKPaymentTransactionMessage.decode(readValue(buffer)!);
+        final int? value = readValue(buffer) as int?;
+        return value == null
+            ? null
+            : SKProductDiscountPaymentModeMessage.values[value];
       case 132:
-        return SKPriceLocaleMessage.decode(readValue(buffer)!);
+        final int? value = readValue(buffer) as int?;
+        return value == null
+            ? null
+            : SKSubscriptionPeriodUnitMessage.values[value];
       case 133:
-        return SKProductDiscountMessage.decode(readValue(buffer)!);
+        return SKPaymentTransactionMessage.decode(readValue(buffer)!);
       case 134:
-        return SKProductMessage.decode(readValue(buffer)!);
+        return SKPaymentMessage.decode(readValue(buffer)!);
       case 135:
-        return SKProductSubscriptionPeriodMessage.decode(readValue(buffer)!);
+        return SKErrorMessage.decode(readValue(buffer)!);
       case 136:
-        return SKProductsResponseMessage.decode(readValue(buffer)!);
+        return SKPaymentDiscountMessage.decode(readValue(buffer)!);
       case 137:
         return SKStorefrontMessage.decode(readValue(buffer)!);
+      case 138:
+        return SKProductsResponseMessage.decode(readValue(buffer)!);
+      case 139:
+        return SKProductMessage.decode(readValue(buffer)!);
+      case 140:
+        return SKPriceLocaleMessage.decode(readValue(buffer)!);
+      case 141:
+        return SKProductDiscountMessage.decode(readValue(buffer)!);
+      case 142:
+        return SKProductSubscriptionPeriodMessage.decode(readValue(buffer)!);
       default:
         return super.readValueOfType(type, buffer);
     }
@@ -570,120 +591,124 @@ class InAppPurchaseAPI {
   /// Constructor for [InAppPurchaseAPI].  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.
-  InAppPurchaseAPI({BinaryMessenger? binaryMessenger})
-      : __pigeon_binaryMessenger = binaryMessenger;
-  final BinaryMessenger? __pigeon_binaryMessenger;
+  InAppPurchaseAPI(
+      {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''})
+      : pigeonVar_binaryMessenger = binaryMessenger,
+        pigeonVar_messageChannelSuffix =
+            messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
+  final BinaryMessenger? pigeonVar_binaryMessenger;
+
+  static const MessageCodec pigeonChannelCodec = _PigeonCodec();
 
-  static const MessageCodec pigeonChannelCodec =
-      _InAppPurchaseAPICodec();
+  final String pigeonVar_messageChannelSuffix;
 
   /// Returns if the current device is able to make payments
   Future canMakePayments() async {
-    const String __pigeon_channelName =
-        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.canMakePayments';
-    final BasicMessageChannel __pigeon_channel =
+    final String pigeonVar_channelName =
+        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.canMakePayments$pigeonVar_messageChannelSuffix';
+    final BasicMessageChannel pigeonVar_channel =
         BasicMessageChannel(
-      __pigeon_channelName,
+      pigeonVar_channelName,
       pigeonChannelCodec,
-      binaryMessenger: __pigeon_binaryMessenger,
+      binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? __pigeon_replyList =
-        await __pigeon_channel.send(null) as List?;
-    if (__pigeon_replyList == null) {
-      throw _createConnectionError(__pigeon_channelName);
-    } else if (__pigeon_replyList.length > 1) {
+    final List? pigeonVar_replyList =
+        await pigeonVar_channel.send(null) as List?;
+    if (pigeonVar_replyList == null) {
+      throw _createConnectionError(pigeonVar_channelName);
+    } else if (pigeonVar_replyList.length > 1) {
       throw PlatformException(
-        code: __pigeon_replyList[0]! as String,
-        message: __pigeon_replyList[1] as String?,
-        details: __pigeon_replyList[2],
+        code: pigeonVar_replyList[0]! as String,
+        message: pigeonVar_replyList[1] as String?,
+        details: pigeonVar_replyList[2],
       );
-    } else if (__pigeon_replyList[0] == null) {
+    } else if (pigeonVar_replyList[0] == null) {
       throw PlatformException(
         code: 'null-error',
         message: 'Host platform returned null value for non-null return value.',
       );
     } else {
-      return (__pigeon_replyList[0] as bool?)!;
+      return (pigeonVar_replyList[0] as bool?)!;
     }
   }
 
-  Future> transactions() async {
-    const String __pigeon_channelName =
-        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.transactions';
-    final BasicMessageChannel __pigeon_channel =
+  Future> transactions() async {
+    final String pigeonVar_channelName =
+        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.transactions$pigeonVar_messageChannelSuffix';
+    final BasicMessageChannel pigeonVar_channel =
         BasicMessageChannel(
-      __pigeon_channelName,
+      pigeonVar_channelName,
       pigeonChannelCodec,
-      binaryMessenger: __pigeon_binaryMessenger,
+      binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? __pigeon_replyList =
-        await __pigeon_channel.send(null) as List?;
-    if (__pigeon_replyList == null) {
-      throw _createConnectionError(__pigeon_channelName);
-    } else if (__pigeon_replyList.length > 1) {
+    final List? pigeonVar_replyList =
+        await pigeonVar_channel.send(null) as List?;
+    if (pigeonVar_replyList == null) {
+      throw _createConnectionError(pigeonVar_channelName);
+    } else if (pigeonVar_replyList.length > 1) {
       throw PlatformException(
-        code: __pigeon_replyList[0]! as String,
-        message: __pigeon_replyList[1] as String?,
-        details: __pigeon_replyList[2],
+        code: pigeonVar_replyList[0]! as String,
+        message: pigeonVar_replyList[1] as String?,
+        details: pigeonVar_replyList[2],
       );
-    } else if (__pigeon_replyList[0] == null) {
+    } else if (pigeonVar_replyList[0] == null) {
       throw PlatformException(
         code: 'null-error',
         message: 'Host platform returned null value for non-null return value.',
       );
     } else {
-      return (__pigeon_replyList[0] as List?)!
-          .cast();
+      return (pigeonVar_replyList[0] as List?)!
+          .cast();
     }
   }
 
   Future storefront() async {
-    const String __pigeon_channelName =
-        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.storefront';
-    final BasicMessageChannel __pigeon_channel =
+    final String pigeonVar_channelName =
+        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.storefront$pigeonVar_messageChannelSuffix';
+    final BasicMessageChannel pigeonVar_channel =
         BasicMessageChannel(
-      __pigeon_channelName,
+      pigeonVar_channelName,
       pigeonChannelCodec,
-      binaryMessenger: __pigeon_binaryMessenger,
+      binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? __pigeon_replyList =
-        await __pigeon_channel.send(null) as List?;
-    if (__pigeon_replyList == null) {
-      throw _createConnectionError(__pigeon_channelName);
-    } else if (__pigeon_replyList.length > 1) {
+    final List? pigeonVar_replyList =
+        await pigeonVar_channel.send(null) as List?;
+    if (pigeonVar_replyList == null) {
+      throw _createConnectionError(pigeonVar_channelName);
+    } else if (pigeonVar_replyList.length > 1) {
       throw PlatformException(
-        code: __pigeon_replyList[0]! as String,
-        message: __pigeon_replyList[1] as String?,
-        details: __pigeon_replyList[2],
+        code: pigeonVar_replyList[0]! as String,
+        message: pigeonVar_replyList[1] as String?,
+        details: pigeonVar_replyList[2],
       );
-    } else if (__pigeon_replyList[0] == null) {
+    } else if (pigeonVar_replyList[0] == null) {
       throw PlatformException(
         code: 'null-error',
         message: 'Host platform returned null value for non-null return value.',
       );
     } else {
-      return (__pigeon_replyList[0] as SKStorefrontMessage?)!;
+      return (pigeonVar_replyList[0] as SKStorefrontMessage?)!;
     }
   }
 
-  Future addPayment(Map paymentMap) async {
-    const String __pigeon_channelName =
-        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.addPayment';
-    final BasicMessageChannel __pigeon_channel =
+  Future addPayment(Map paymentMap) async {
+    final String pigeonVar_channelName =
+        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.addPayment$pigeonVar_messageChannelSuffix';
+    final BasicMessageChannel pigeonVar_channel =
         BasicMessageChannel(
-      __pigeon_channelName,
+      pigeonVar_channelName,
       pigeonChannelCodec,
-      binaryMessenger: __pigeon_binaryMessenger,
+      binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? __pigeon_replyList =
-        await __pigeon_channel.send([paymentMap]) as List?;
-    if (__pigeon_replyList == null) {
-      throw _createConnectionError(__pigeon_channelName);
-    } else if (__pigeon_replyList.length > 1) {
+    final List? pigeonVar_replyList =
+        await pigeonVar_channel.send([paymentMap]) as List?;
+    if (pigeonVar_replyList == null) {
+      throw _createConnectionError(pigeonVar_channelName);
+    } else if (pigeonVar_replyList.length > 1) {
       throw PlatformException(
-        code: __pigeon_replyList[0]! as String,
-        message: __pigeon_replyList[1] as String?,
-        details: __pigeon_replyList[2],
+        code: pigeonVar_replyList[0]! as String,
+        message: pigeonVar_replyList[1] as String?,
+        details: pigeonVar_replyList[2],
       );
     } else {
       return;
@@ -691,53 +716,53 @@ class InAppPurchaseAPI {
   }
 
   Future startProductRequest(
-      List productIdentifiers) async {
-    const String __pigeon_channelName =
-        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.startProductRequest';
-    final BasicMessageChannel __pigeon_channel =
+      List productIdentifiers) async {
+    final String pigeonVar_channelName =
+        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.startProductRequest$pigeonVar_messageChannelSuffix';
+    final BasicMessageChannel pigeonVar_channel =
         BasicMessageChannel(
-      __pigeon_channelName,
+      pigeonVar_channelName,
       pigeonChannelCodec,
-      binaryMessenger: __pigeon_binaryMessenger,
+      binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? __pigeon_replyList = await __pigeon_channel
+    final List? pigeonVar_replyList = await pigeonVar_channel
         .send([productIdentifiers]) as List?;
-    if (__pigeon_replyList == null) {
-      throw _createConnectionError(__pigeon_channelName);
-    } else if (__pigeon_replyList.length > 1) {
+    if (pigeonVar_replyList == null) {
+      throw _createConnectionError(pigeonVar_channelName);
+    } else if (pigeonVar_replyList.length > 1) {
       throw PlatformException(
-        code: __pigeon_replyList[0]! as String,
-        message: __pigeon_replyList[1] as String?,
-        details: __pigeon_replyList[2],
+        code: pigeonVar_replyList[0]! as String,
+        message: pigeonVar_replyList[1] as String?,
+        details: pigeonVar_replyList[2],
       );
-    } else if (__pigeon_replyList[0] == null) {
+    } else if (pigeonVar_replyList[0] == null) {
       throw PlatformException(
         code: 'null-error',
         message: 'Host platform returned null value for non-null return value.',
       );
     } else {
-      return (__pigeon_replyList[0] as SKProductsResponseMessage?)!;
+      return (pigeonVar_replyList[0] as SKProductsResponseMessage?)!;
     }
   }
 
-  Future finishTransaction(Map finishMap) async {
-    const String __pigeon_channelName =
-        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.finishTransaction';
-    final BasicMessageChannel __pigeon_channel =
+  Future finishTransaction(Map finishMap) async {
+    final String pigeonVar_channelName =
+        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.finishTransaction$pigeonVar_messageChannelSuffix';
+    final BasicMessageChannel pigeonVar_channel =
         BasicMessageChannel(
-      __pigeon_channelName,
+      pigeonVar_channelName,
       pigeonChannelCodec,
-      binaryMessenger: __pigeon_binaryMessenger,
+      binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? __pigeon_replyList =
-        await __pigeon_channel.send([finishMap]) as List?;
-    if (__pigeon_replyList == null) {
-      throw _createConnectionError(__pigeon_channelName);
-    } else if (__pigeon_replyList.length > 1) {
+    final List? pigeonVar_replyList =
+        await pigeonVar_channel.send([finishMap]) as List?;
+    if (pigeonVar_replyList == null) {
+      throw _createConnectionError(pigeonVar_channelName);
+    } else if (pigeonVar_replyList.length > 1) {
       throw PlatformException(
-        code: __pigeon_replyList[0]! as String,
-        message: __pigeon_replyList[1] as String?,
-        details: __pigeon_replyList[2],
+        code: pigeonVar_replyList[0]! as String,
+        message: pigeonVar_replyList[1] as String?,
+        details: pigeonVar_replyList[2],
       );
     } else {
       return;
@@ -745,23 +770,23 @@ class InAppPurchaseAPI {
   }
 
   Future restoreTransactions(String? applicationUserName) async {
-    const String __pigeon_channelName =
-        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.restoreTransactions';
-    final BasicMessageChannel __pigeon_channel =
+    final String pigeonVar_channelName =
+        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.restoreTransactions$pigeonVar_messageChannelSuffix';
+    final BasicMessageChannel pigeonVar_channel =
         BasicMessageChannel(
-      __pigeon_channelName,
+      pigeonVar_channelName,
       pigeonChannelCodec,
-      binaryMessenger: __pigeon_binaryMessenger,
+      binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? __pigeon_replyList = await __pigeon_channel
+    final List? pigeonVar_replyList = await pigeonVar_channel
         .send([applicationUserName]) as List?;
-    if (__pigeon_replyList == null) {
-      throw _createConnectionError(__pigeon_channelName);
-    } else if (__pigeon_replyList.length > 1) {
+    if (pigeonVar_replyList == null) {
+      throw _createConnectionError(pigeonVar_channelName);
+    } else if (pigeonVar_replyList.length > 1) {
       throw PlatformException(
-        code: __pigeon_replyList[0]! as String,
-        message: __pigeon_replyList[1] as String?,
-        details: __pigeon_replyList[2],
+        code: pigeonVar_replyList[0]! as String,
+        message: pigeonVar_replyList[1] as String?,
+        details: pigeonVar_replyList[2],
       );
     } else {
       return;
@@ -769,23 +794,23 @@ class InAppPurchaseAPI {
   }
 
   Future presentCodeRedemptionSheet() async {
-    const String __pigeon_channelName =
-        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.presentCodeRedemptionSheet';
-    final BasicMessageChannel __pigeon_channel =
+    final String pigeonVar_channelName =
+        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.presentCodeRedemptionSheet$pigeonVar_messageChannelSuffix';
+    final BasicMessageChannel pigeonVar_channel =
         BasicMessageChannel(
-      __pigeon_channelName,
+      pigeonVar_channelName,
       pigeonChannelCodec,
-      binaryMessenger: __pigeon_binaryMessenger,
+      binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? __pigeon_replyList =
-        await __pigeon_channel.send(null) as List?;
-    if (__pigeon_replyList == null) {
-      throw _createConnectionError(__pigeon_channelName);
-    } else if (__pigeon_replyList.length > 1) {
+    final List? pigeonVar_replyList =
+        await pigeonVar_channel.send(null) as List?;
+    if (pigeonVar_replyList == null) {
+      throw _createConnectionError(pigeonVar_channelName);
+    } else if (pigeonVar_replyList.length > 1) {
       throw PlatformException(
-        code: __pigeon_replyList[0]! as String,
-        message: __pigeon_replyList[1] as String?,
-        details: __pigeon_replyList[2],
+        code: pigeonVar_replyList[0]! as String,
+        message: pigeonVar_replyList[1] as String?,
+        details: pigeonVar_replyList[2],
       );
     } else {
       return;
@@ -793,48 +818,47 @@ class InAppPurchaseAPI {
   }
 
   Future retrieveReceiptData() async {
-    const String __pigeon_channelName =
-        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.retrieveReceiptData';
-    final BasicMessageChannel __pigeon_channel =
+    final String pigeonVar_channelName =
+        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.retrieveReceiptData$pigeonVar_messageChannelSuffix';
+    final BasicMessageChannel pigeonVar_channel =
         BasicMessageChannel(
-      __pigeon_channelName,
+      pigeonVar_channelName,
       pigeonChannelCodec,
-      binaryMessenger: __pigeon_binaryMessenger,
+      binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? __pigeon_replyList =
-        await __pigeon_channel.send(null) as List?;
-    if (__pigeon_replyList == null) {
-      throw _createConnectionError(__pigeon_channelName);
-    } else if (__pigeon_replyList.length > 1) {
+    final List? pigeonVar_replyList =
+        await pigeonVar_channel.send(null) as List?;
+    if (pigeonVar_replyList == null) {
+      throw _createConnectionError(pigeonVar_channelName);
+    } else if (pigeonVar_replyList.length > 1) {
       throw PlatformException(
-        code: __pigeon_replyList[0]! as String,
-        message: __pigeon_replyList[1] as String?,
-        details: __pigeon_replyList[2],
+        code: pigeonVar_replyList[0]! as String,
+        message: pigeonVar_replyList[1] as String?,
+        details: pigeonVar_replyList[2],
       );
     } else {
-      return (__pigeon_replyList[0] as String?);
+      return (pigeonVar_replyList[0] as String?);
     }
   }
 
-  Future refreshReceipt(
-      {Map? receiptProperties}) async {
-    const String __pigeon_channelName =
-        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.refreshReceipt';
-    final BasicMessageChannel __pigeon_channel =
+  Future refreshReceipt({Map? receiptProperties}) async {
+    final String pigeonVar_channelName =
+        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.refreshReceipt$pigeonVar_messageChannelSuffix';
+    final BasicMessageChannel pigeonVar_channel =
         BasicMessageChannel(
-      __pigeon_channelName,
+      pigeonVar_channelName,
       pigeonChannelCodec,
-      binaryMessenger: __pigeon_binaryMessenger,
+      binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? __pigeon_replyList = await __pigeon_channel
+    final List? pigeonVar_replyList = await pigeonVar_channel
         .send([receiptProperties]) as List?;
-    if (__pigeon_replyList == null) {
-      throw _createConnectionError(__pigeon_channelName);
-    } else if (__pigeon_replyList.length > 1) {
+    if (pigeonVar_replyList == null) {
+      throw _createConnectionError(pigeonVar_channelName);
+    } else if (pigeonVar_replyList.length > 1) {
       throw PlatformException(
-        code: __pigeon_replyList[0]! as String,
-        message: __pigeon_replyList[1] as String?,
-        details: __pigeon_replyList[2],
+        code: pigeonVar_replyList[0]! as String,
+        message: pigeonVar_replyList[1] as String?,
+        details: pigeonVar_replyList[2],
       );
     } else {
       return;
@@ -842,23 +866,23 @@ class InAppPurchaseAPI {
   }
 
   Future startObservingPaymentQueue() async {
-    const String __pigeon_channelName =
-        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.startObservingPaymentQueue';
-    final BasicMessageChannel __pigeon_channel =
+    final String pigeonVar_channelName =
+        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.startObservingPaymentQueue$pigeonVar_messageChannelSuffix';
+    final BasicMessageChannel pigeonVar_channel =
         BasicMessageChannel(
-      __pigeon_channelName,
+      pigeonVar_channelName,
       pigeonChannelCodec,
-      binaryMessenger: __pigeon_binaryMessenger,
+      binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? __pigeon_replyList =
-        await __pigeon_channel.send(null) as List?;
-    if (__pigeon_replyList == null) {
-      throw _createConnectionError(__pigeon_channelName);
-    } else if (__pigeon_replyList.length > 1) {
+    final List? pigeonVar_replyList =
+        await pigeonVar_channel.send(null) as List?;
+    if (pigeonVar_replyList == null) {
+      throw _createConnectionError(pigeonVar_channelName);
+    } else if (pigeonVar_replyList.length > 1) {
       throw PlatformException(
-        code: __pigeon_replyList[0]! as String,
-        message: __pigeon_replyList[1] as String?,
-        details: __pigeon_replyList[2],
+        code: pigeonVar_replyList[0]! as String,
+        message: pigeonVar_replyList[1] as String?,
+        details: pigeonVar_replyList[2],
       );
     } else {
       return;
@@ -866,23 +890,23 @@ class InAppPurchaseAPI {
   }
 
   Future stopObservingPaymentQueue() async {
-    const String __pigeon_channelName =
-        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.stopObservingPaymentQueue';
-    final BasicMessageChannel __pigeon_channel =
+    final String pigeonVar_channelName =
+        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.stopObservingPaymentQueue$pigeonVar_messageChannelSuffix';
+    final BasicMessageChannel pigeonVar_channel =
         BasicMessageChannel(
-      __pigeon_channelName,
+      pigeonVar_channelName,
       pigeonChannelCodec,
-      binaryMessenger: __pigeon_binaryMessenger,
+      binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? __pigeon_replyList =
-        await __pigeon_channel.send(null) as List?;
-    if (__pigeon_replyList == null) {
-      throw _createConnectionError(__pigeon_channelName);
-    } else if (__pigeon_replyList.length > 1) {
+    final List? pigeonVar_replyList =
+        await pigeonVar_channel.send(null) as List?;
+    if (pigeonVar_replyList == null) {
+      throw _createConnectionError(pigeonVar_channelName);
+    } else if (pigeonVar_replyList.length > 1) {
       throw PlatformException(
-        code: __pigeon_replyList[0]! as String,
-        message: __pigeon_replyList[1] as String?,
-        details: __pigeon_replyList[2],
+        code: pigeonVar_replyList[0]! as String,
+        message: pigeonVar_replyList[1] as String?,
+        details: pigeonVar_replyList[2],
       );
     } else {
       return;
@@ -890,23 +914,23 @@ class InAppPurchaseAPI {
   }
 
   Future registerPaymentQueueDelegate() async {
-    const String __pigeon_channelName =
-        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.registerPaymentQueueDelegate';
-    final BasicMessageChannel __pigeon_channel =
+    final String pigeonVar_channelName =
+        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.registerPaymentQueueDelegate$pigeonVar_messageChannelSuffix';
+    final BasicMessageChannel pigeonVar_channel =
         BasicMessageChannel(
-      __pigeon_channelName,
+      pigeonVar_channelName,
       pigeonChannelCodec,
-      binaryMessenger: __pigeon_binaryMessenger,
+      binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? __pigeon_replyList =
-        await __pigeon_channel.send(null) as List?;
-    if (__pigeon_replyList == null) {
-      throw _createConnectionError(__pigeon_channelName);
-    } else if (__pigeon_replyList.length > 1) {
+    final List? pigeonVar_replyList =
+        await pigeonVar_channel.send(null) as List?;
+    if (pigeonVar_replyList == null) {
+      throw _createConnectionError(pigeonVar_channelName);
+    } else if (pigeonVar_replyList.length > 1) {
       throw PlatformException(
-        code: __pigeon_replyList[0]! as String,
-        message: __pigeon_replyList[1] as String?,
-        details: __pigeon_replyList[2],
+        code: pigeonVar_replyList[0]! as String,
+        message: pigeonVar_replyList[1] as String?,
+        details: pigeonVar_replyList[2],
       );
     } else {
       return;
@@ -914,23 +938,23 @@ class InAppPurchaseAPI {
   }
 
   Future removePaymentQueueDelegate() async {
-    const String __pigeon_channelName =
-        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.removePaymentQueueDelegate';
-    final BasicMessageChannel __pigeon_channel =
+    final String pigeonVar_channelName =
+        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.removePaymentQueueDelegate$pigeonVar_messageChannelSuffix';
+    final BasicMessageChannel pigeonVar_channel =
         BasicMessageChannel(
-      __pigeon_channelName,
+      pigeonVar_channelName,
       pigeonChannelCodec,
-      binaryMessenger: __pigeon_binaryMessenger,
+      binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? __pigeon_replyList =
-        await __pigeon_channel.send(null) as List?;
-    if (__pigeon_replyList == null) {
-      throw _createConnectionError(__pigeon_channelName);
-    } else if (__pigeon_replyList.length > 1) {
+    final List? pigeonVar_replyList =
+        await pigeonVar_channel.send(null) as List?;
+    if (pigeonVar_replyList == null) {
+      throw _createConnectionError(pigeonVar_channelName);
+    } else if (pigeonVar_replyList.length > 1) {
       throw PlatformException(
-        code: __pigeon_replyList[0]! as String,
-        message: __pigeon_replyList[1] as String?,
-        details: __pigeon_replyList[2],
+        code: pigeonVar_replyList[0]! as String,
+        message: pigeonVar_replyList[1] as String?,
+        details: pigeonVar_replyList[2],
       );
     } else {
       return;
@@ -938,23 +962,23 @@ class InAppPurchaseAPI {
   }
 
   Future showPriceConsentIfNeeded() async {
-    const String __pigeon_channelName =
-        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.showPriceConsentIfNeeded';
-    final BasicMessageChannel __pigeon_channel =
+    final String pigeonVar_channelName =
+        'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.showPriceConsentIfNeeded$pigeonVar_messageChannelSuffix';
+    final BasicMessageChannel pigeonVar_channel =
         BasicMessageChannel(
-      __pigeon_channelName,
+      pigeonVar_channelName,
       pigeonChannelCodec,
-      binaryMessenger: __pigeon_binaryMessenger,
+      binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? __pigeon_replyList =
-        await __pigeon_channel.send(null) as List?;
-    if (__pigeon_replyList == null) {
-      throw _createConnectionError(__pigeon_channelName);
-    } else if (__pigeon_replyList.length > 1) {
+    final List? pigeonVar_replyList =
+        await pigeonVar_channel.send(null) as List?;
+    if (pigeonVar_replyList == null) {
+      throw _createConnectionError(pigeonVar_channelName);
+    } else if (pigeonVar_replyList.length > 1) {
       throw PlatformException(
-        code: __pigeon_replyList[0]! as String,
-        message: __pigeon_replyList[1] as String?,
-        details: __pigeon_replyList[2],
+        code: pigeonVar_replyList[0]! as String,
+        message: pigeonVar_replyList[1] as String?,
+        details: pigeonVar_replyList[2],
       );
     } else {
       return;
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/sk2_pigeon.g.dart b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/sk2_pigeon.g.dart
index 1dcc2cad7717..8c6753fdf205 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/sk2_pigeon.g.dart
+++ b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/sk2_pigeon.g.dart
@@ -1,7 +1,7 @@
 // Copyright 2013 The Flutter Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-// Autogenerated from Pigeon (v22.0.0), do not edit directly.
+// Autogenerated from Pigeon (v22.4.2), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers
 
@@ -149,9 +149,7 @@ class SK2SubscriptionInfoMessage {
   });
 
   /// An array of all the promotional offers configured for this subscription.
-  /// This should be List but pigeon doesnt support
-  /// null-safe generics. https://github.com/flutter/flutter/issues/97848
-  List promotionalOffers;
+  List promotionalOffers;
 
   /// The group identifier for this subscription.
   String subscriptionGroupID;
@@ -171,7 +169,7 @@ class SK2SubscriptionInfoMessage {
     result as List;
     return SK2SubscriptionInfoMessage(
       promotionalOffers:
-          (result[0] as List?)!.cast(),
+          (result[0] as List?)!.cast(),
       subscriptionGroupID: result[1]! as String,
       subscriptionPeriod: result[2]! as SK2SubscriptionPeriodMessage,
     );
@@ -363,7 +361,7 @@ class SK2ErrorMessage {
 
   String domain;
 
-  Map? userInfo;
+  Map? userInfo;
 
   Object encode() {
     return [
@@ -378,7 +376,7 @@ class SK2ErrorMessage {
     return SK2ErrorMessage(
       code: result[0]! as int,
       domain: result[1]! as String,
-      userInfo: (result[2] as Map?)?.cast(),
+      userInfo: (result[2] as Map?)?.cast(),
     );
   }
 }
@@ -526,7 +524,7 @@ class InAppPurchase2API {
     }
   }
 
-  Future> products(List identifiers) async {
+  Future> products(List identifiers) async {
     final String pigeonVar_channelName =
         'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchase2API.products$pigeonVar_messageChannelSuffix';
     final BasicMessageChannel pigeonVar_channel =
@@ -552,7 +550,7 @@ class InAppPurchase2API {
       );
     } else {
       return (pigeonVar_replyList[0] as List?)!
-          .cast();
+          .cast();
     }
   }
 
@@ -586,7 +584,7 @@ class InAppPurchase2API {
     }
   }
 
-  Future> transactions() async {
+  Future> transactions() async {
     final String pigeonVar_channelName =
         'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchase2API.transactions$pigeonVar_messageChannelSuffix';
     final BasicMessageChannel pigeonVar_channel =
@@ -612,7 +610,7 @@ class InAppPurchase2API {
       );
     } else {
       return (pigeonVar_replyList[0] as List?)!
-          .cast();
+          .cast();
     }
   }
 
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_2_wrappers/sk2_product_wrapper.dart b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_2_wrappers/sk2_product_wrapper.dart
index 820ea211d7b2..ad5de9c5c77a 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_2_wrappers/sk2_product_wrapper.dart
+++ b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_2_wrappers/sk2_product_wrapper.dart
@@ -148,11 +148,7 @@ extension on SK2SubscriptionInfoMessage {
   SK2SubscriptionInfo convertFromPigeon() {
     return SK2SubscriptionInfo(
         subscriptionGroupID: subscriptionGroupID,
-        // Note that promotionalOffers should NOT be nullable, but is only declared
-        // so because of pigeon cannot handle non null lists.
-        // There should be NO NULLS.
         promotionalOffers: promotionalOffers
-            .whereType()
             .map((SK2SubscriptionOfferMessage offer) =>
                 offer.convertFromPigeon())
             .toList(),
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_2_wrappers/sk2_transaction_wrapper.dart b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_2_wrappers/sk2_transaction_wrapper.dart
index c6ec3bf0d5ac..5afefddba7af 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_2_wrappers/sk2_transaction_wrapper.dart
+++ b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_2_wrappers/sk2_transaction_wrapper.dart
@@ -70,11 +70,9 @@ class SK2Transaction {
   /// https://developer.apple.com/documentation/storekit/transaction/3851203-all
   /// A sequence that emits all the customer’s transactions for your app.
   static Future> transactions() async {
-    final List msgs = await _hostApi.transactions();
-    final List transactions = msgs
-        .map((SK2TransactionMessage? e) => e?.convertFromPigeon())
-        .cast()
-        .toList();
+    final List msgs = await _hostApi.transactions();
+    final List transactions =
+        msgs.map((SK2TransactionMessage e) => e.convertFromPigeon()).toList();
     return transactions;
   }
 
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart
index 8f1af1c64049..138ecc8b7472 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart
+++ b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart
@@ -416,8 +416,8 @@ class SKPaymentWrapper {
   }
 
   /// Creates a Map object describes the payment object.
-  Map toMap() {
-    return {
+  Map toMap() {
+    return {
       'productIdentifier': productIdentifier,
       'applicationUsername': applicationUsername,
       'requestData': requestData,
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_wrappers/sk_product_wrapper.dart b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_wrappers/sk_product_wrapper.dart
index ff49758107dc..95698271c3ff 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_wrappers/sk_product_wrapper.dart
+++ b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_wrappers/sk_product_wrapper.dart
@@ -72,11 +72,9 @@ class SkProductResponseWrapper {
       SKProductsResponseMessage msg) {
     return SkProductResponseWrapper(
       products: msg.products!
-          .map((SKProductMessage? e) => SKProductWrapper.convertFromPigeon(e!))
+          .map((SKProductMessage e) => SKProductWrapper.convertFromPigeon(e))
           .toList(),
-      invalidProductIdentifiers: msg.invalidProductIdentifiers != null
-          ? msg.invalidProductIdentifiers!.cast()
-          : [],
+      invalidProductIdentifiers: msg.invalidProductIdentifiers ?? [],
     );
   }
 
@@ -86,10 +84,9 @@ class SkProductResponseWrapper {
       SkProductResponseWrapper wrapper) {
     return SKProductsResponseMessage(
         products: wrapper.products
-            .map((SKProductWrapper? e) => SKProductWrapper.convertToPigeon(e!))
+            .map((SKProductWrapper e) => SKProductWrapper.convertToPigeon(e))
             .toList(),
-        invalidProductIdentifiers:
-            wrapper.invalidProductIdentifiers.cast());
+        invalidProductIdentifiers: wrapper.invalidProductIdentifiers);
   }
 }
 
@@ -563,8 +560,8 @@ class SKProductWrapper {
             : null,
         discounts: msg.discounts != null
             ? msg.discounts!
-                .map((SKProductDiscountMessage? e) =>
-                    SKProductDiscountWrapper.convertFromPigeon(e!))
+                .map((SKProductDiscountMessage e) =>
+                    SKProductDiscountWrapper.convertFromPigeon(e))
                 .toList()
             : []);
   }
@@ -587,8 +584,8 @@ class SKProductWrapper {
                 wrapper.introductoryPrice!)
             : null,
         discounts: wrapper.discounts
-            .map((SKProductDiscountWrapper? e) =>
-                SKProductDiscountWrapper.convertToPigeon(e!))
+            .map((SKProductDiscountWrapper e) =>
+                SKProductDiscountWrapper.convertToPigeon(e))
             .toList());
   }
 }
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_wrappers/sk_request_maker.dart b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_wrappers/sk_request_maker.dart
index 5a16f261cdd7..9075db9157ab 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_wrappers/sk_request_maker.dart
+++ b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_wrappers/sk_request_maker.dart
@@ -52,7 +52,7 @@ class SKRequestMaker {
   /// * isRevoked: whether the receipt has been revoked.
   /// * isVolumePurchase: whether the receipt is a Volume Purchase Plan receipt.
   Future startRefreshReceiptRequest(
-      {Map? receiptProperties}) {
+      {Map? receiptProperties}) {
     return _hostApi.refreshReceipt(receiptProperties: receiptProperties);
   }
 }
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/pigeons/messages.dart b/packages/in_app_purchase/in_app_purchase_storekit/pigeons/messages.dart
index 07c1c3d2d3b6..cd7b6b70a57a 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/pigeons/messages.dart
+++ b/packages/in_app_purchase/in_app_purchase_storekit/pigeons/messages.dart
@@ -9,6 +9,9 @@ import 'package:pigeon/pigeon.dart';
   dartTestOut: 'test/test_api.g.dart',
   objcHeaderOut: 'darwin/Classes/messages.g.h',
   objcSourceOut: 'darwin/Classes/messages.g.m',
+  objcOptions: ObjcOptions(
+    prefix: 'FIA',
+  ),
   copyrightHeader: 'pigeons/copyright.txt',
 ))
 class SKPaymentTransactionMessage {
@@ -91,7 +94,7 @@ class SKErrorMessage {
 
   final int code;
   final String domain;
-  final Map? userInfo;
+  final Map? userInfo;
 }
 
 class SKPaymentDiscountMessage {
@@ -123,8 +126,8 @@ class SKStorefrontMessage {
 class SKProductsResponseMessage {
   const SKProductsResponseMessage(
       {required this.products, required this.invalidProductIdentifiers});
-  final List? products;
-  final List? invalidProductIdentifiers;
+  final List? products;
+  final List? invalidProductIdentifiers;
 }
 
 class SKProductMessage {
@@ -150,7 +153,7 @@ class SKProductMessage {
   final String price;
   final SKProductSubscriptionPeriodMessage? subscriptionPeriod;
   final SKProductDiscountMessage? introductoryPrice;
-  final List? discounts;
+  final List? discounts;
 }
 
 class SKPriceLocaleMessage {
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/pigeons/sk2_pigeon.dart b/packages/in_app_purchase/in_app_purchase_storekit/pigeons/sk2_pigeon.dart
index b276524a5877..fbf4c421ac1b 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/pigeons/sk2_pigeon.dart
+++ b/packages/in_app_purchase/in_app_purchase_storekit/pigeons/sk2_pigeon.dart
@@ -69,9 +69,7 @@ class SK2SubscriptionInfoMessage {
   });
 
   /// An array of all the promotional offers configured for this subscription.
-  /// This should be List but pigeon doesnt support
-  /// null-safe generics. https://github.com/flutter/flutter/issues/97848
-  final List promotionalOffers;
+  final List promotionalOffers;
 
   /// The group identifier for this subscription.
   final String subscriptionGroupID;
@@ -163,7 +161,7 @@ class SK2ErrorMessage {
 
   final int code;
   final String domain;
-  final Map? userInfo;
+  final Map? userInfo;
 }
 
 enum SK2ProductPurchaseResultMessage { success, userCancelled, pending }
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/pubspec.yaml b/packages/in_app_purchase/in_app_purchase_storekit/pubspec.yaml
index fe60dcda583e..4c6da54a5a8a 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/pubspec.yaml
+++ b/packages/in_app_purchase/in_app_purchase_storekit/pubspec.yaml
@@ -2,7 +2,7 @@ name: in_app_purchase_storekit
 description: An implementation for the iOS and macOS platforms of the Flutter `in_app_purchase` plugin. This uses the StoreKit Framework.
 repository: https://github.com/flutter/packages/tree/main/packages/in_app_purchase/in_app_purchase_storekit
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22
-version: 0.3.18+2
+version: 0.3.18+3
 
 environment:
   sdk: ^3.3.0
@@ -31,7 +31,7 @@ dev_dependencies:
   flutter_test:
     sdk: flutter
   json_serializable: ^6.0.0
-  pigeon: ^22.0.0
+  pigeon: ^22.4.2
   test: ^1.16.0
 
 topics:
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/test/fakes/fake_storekit_platform.dart b/packages/in_app_purchase/in_app_purchase_storekit/test/fakes/fake_storekit_platform.dart
index 98e96e26d673..29932a9f8180 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/test/fakes/fake_storekit_platform.dart
+++ b/packages/in_app_purchase/in_app_purchase_storekit/test/fakes/fake_storekit_platform.dart
@@ -187,7 +187,7 @@ class FakeStoreKitPlatform implements TestInAppPurchaseApi {
   }
 
   @override
-  List transactions() {
+  List transactions() {
     throw UnimplementedError();
   }
 
@@ -316,7 +316,7 @@ class FakeStoreKit2Platform implements TestInAppPurchase2Api {
   }
 
   @override
-  Future> products(List identifiers) {
+  Future> products(List identifiers) {
     if (queryProductException != null) {
       throw queryProductException!;
     }
@@ -327,12 +327,12 @@ class FakeStoreKit2Platform implements TestInAppPurchase2Api {
         products.add(validProducts[productID]!);
       }
     }
-    final List result = [];
+    final List result = [];
     for (final SK2Product p in products) {
       result.add(p.convertToPigeon());
     }
 
-    return Future>.value(result);
+    return Future>.value(result);
   }
 
   @override
@@ -352,8 +352,8 @@ class FakeStoreKit2Platform implements TestInAppPurchase2Api {
   }
 
   @override
-  Future> transactions() {
-    return Future>.value([
+  Future> transactions() {
+    return Future>.value([
       SK2TransactionMessage(
           id: 123,
           originalId: 123,
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/test/in_app_purchase_storekit_platform_addtion_test.dart b/packages/in_app_purchase/in_app_purchase_storekit/test/in_app_purchase_storekit_platform_addtion_test.dart
index 40068db75a71..dfa3c11ca6bf 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/test/in_app_purchase_storekit_platform_addtion_test.dart
+++ b/packages/in_app_purchase/in_app_purchase_storekit/test/in_app_purchase_storekit_platform_addtion_test.dart
@@ -15,7 +15,7 @@ void main() {
   final FakeStoreKitPlatform fakeStoreKitPlatform = FakeStoreKitPlatform();
 
   setUpAll(() {
-    TestInAppPurchaseApi.setup(fakeStoreKitPlatform);
+    TestInAppPurchaseApi.setUp(fakeStoreKitPlatform);
   });
 
   group('present code redemption sheet', () {
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/test/in_app_purchase_storekit_platform_test.dart b/packages/in_app_purchase/in_app_purchase_storekit/test/in_app_purchase_storekit_platform_test.dart
index 2da0e47070ac..a255b4fa3bd2 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/test/in_app_purchase_storekit_platform_test.dart
+++ b/packages/in_app_purchase/in_app_purchase_storekit/test/in_app_purchase_storekit_platform_test.dart
@@ -22,7 +22,7 @@ void main() {
   late InAppPurchaseStoreKitPlatform iapStoreKitPlatform;
 
   setUpAll(() {
-    TestInAppPurchaseApi.setup(fakeStoreKitPlatform);
+    TestInAppPurchaseApi.setUp(fakeStoreKitPlatform);
   });
 
   setUp(() {
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/test/sk2_test_api.g.dart b/packages/in_app_purchase/in_app_purchase_storekit/test/sk2_test_api.g.dart
index 2bd0201d9f4d..58850af3ece4 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/test/sk2_test_api.g.dart
+++ b/packages/in_app_purchase/in_app_purchase_storekit/test/sk2_test_api.g.dart
@@ -1,7 +1,7 @@
 // Copyright 2013 The Flutter Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-// Autogenerated from Pigeon (v22.0.0), do not edit directly.
+// Autogenerated from Pigeon (v22.4.2), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import, no_leading_underscores_for_local_identifiers
 // ignore_for_file: avoid_relative_lib_imports
@@ -119,12 +119,12 @@ abstract class TestInAppPurchase2Api {
 
   bool canMakePayments();
 
-  Future> products(List identifiers);
+  Future> products(List identifiers);
 
   Future purchase(String id,
       {SK2ProductPurchaseOptionsMessage? options});
 
-  Future> transactions();
+  Future> transactions();
 
   Future finish(int id);
 
@@ -182,12 +182,12 @@ abstract class TestInAppPurchase2Api {
           assert(message != null,
               'Argument for dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchase2API.products was null.');
           final List args = (message as List?)!;
-          final List? arg_identifiers =
-              (args[0] as List?)?.cast();
+          final List? arg_identifiers =
+              (args[0] as List?)?.cast();
           assert(arg_identifiers != null,
-              'Argument for dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchase2API.products was null, expected non-null List.');
+              'Argument for dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchase2API.products was null, expected non-null List.');
           try {
-            final List output =
+            final List output =
                 await api.products(arg_identifiers!);
             return [output];
           } on PlatformException catch (e) {
@@ -249,8 +249,7 @@ abstract class TestInAppPurchase2Api {
             .setMockDecodedMessageHandler(pigeonVar_channel,
                 (Object? message) async {
           try {
-            final List output =
-                await api.transactions();
+            final List output = await api.transactions();
             return [output];
           } on PlatformException catch (e) {
             return wrapResponse(error: e);
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/test/store_kit_wrappers/sk_methodchannel_apis_test.dart b/packages/in_app_purchase/in_app_purchase_storekit/test/store_kit_wrappers/sk_methodchannel_apis_test.dart
index f7fe5283d949..b774552f84ba 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/test/store_kit_wrappers/sk_methodchannel_apis_test.dart
+++ b/packages/in_app_purchase/in_app_purchase_storekit/test/store_kit_wrappers/sk_methodchannel_apis_test.dart
@@ -15,7 +15,7 @@ void main() {
   final FakeStoreKitPlatform fakeStoreKitPlatform = FakeStoreKitPlatform();
 
   setUpAll(() {
-    TestInAppPurchaseApi.setup(fakeStoreKitPlatform);
+    TestInAppPurchaseApi.setUp(fakeStoreKitPlatform);
   });
 
   setUp(() {});
@@ -235,7 +235,7 @@ class FakeStoreKitPlatform implements TestInAppPurchaseApi {
   }
 
   @override
-  List transactions() =>
+  List transactions() =>
       [dummyTransactionMessage];
 
   @override
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/test/store_kit_wrappers/sk_payment_queue_delegate_api_test.dart b/packages/in_app_purchase/in_app_purchase_storekit/test/store_kit_wrappers/sk_payment_queue_delegate_api_test.dart
index 03c9fda381cb..f9efd427bfc5 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/test/store_kit_wrappers/sk_payment_queue_delegate_api_test.dart
+++ b/packages/in_app_purchase/in_app_purchase_storekit/test/store_kit_wrappers/sk_payment_queue_delegate_api_test.dart
@@ -15,7 +15,7 @@ void main() {
   final FakeStoreKitPlatform fakeStoreKitPlatform = FakeStoreKitPlatform();
 
   setUpAll(() {
-    TestInAppPurchaseApi.setup(fakeStoreKitPlatform);
+    TestInAppPurchaseApi.setUp(fakeStoreKitPlatform);
   });
 
   test(
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/test/test_api.g.dart b/packages/in_app_purchase/in_app_purchase_storekit/test/test_api.g.dart
index 6b0c9a77ab46..2092930d208d 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/test/test_api.g.dart
+++ b/packages/in_app_purchase/in_app_purchase_storekit/test/test_api.g.dart
@@ -1,7 +1,7 @@
 // Copyright 2013 The Flutter Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-// Autogenerated from Pigeon (v16.0.5), do not edit directly.
+// Autogenerated from Pigeon (v22.4.2), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import, no_leading_underscores_for_local_identifiers
 // ignore_for_file: avoid_relative_lib_imports
@@ -13,40 +13,55 @@ import 'package:flutter_test/flutter_test.dart';
 
 import 'package:in_app_purchase_storekit/src/messages.g.dart';
 
-class _TestInAppPurchaseApiCodec extends StandardMessageCodec {
-  const _TestInAppPurchaseApiCodec();
+class _PigeonCodec extends StandardMessageCodec {
+  const _PigeonCodec();
   @override
   void writeValue(WriteBuffer buffer, Object? value) {
-    if (value is SKErrorMessage) {
-      buffer.putUint8(128);
-      writeValue(buffer, value.encode());
-    } else if (value is SKPaymentDiscountMessage) {
+    if (value is int) {
+      buffer.putUint8(4);
+      buffer.putInt64(value);
+    } else if (value is SKPaymentTransactionStateMessage) {
       buffer.putUint8(129);
-      writeValue(buffer, value.encode());
-    } else if (value is SKPaymentMessage) {
+      writeValue(buffer, value.index);
+    } else if (value is SKProductDiscountTypeMessage) {
       buffer.putUint8(130);
-      writeValue(buffer, value.encode());
-    } else if (value is SKPaymentTransactionMessage) {
+      writeValue(buffer, value.index);
+    } else if (value is SKProductDiscountPaymentModeMessage) {
       buffer.putUint8(131);
-      writeValue(buffer, value.encode());
-    } else if (value is SKPriceLocaleMessage) {
+      writeValue(buffer, value.index);
+    } else if (value is SKSubscriptionPeriodUnitMessage) {
       buffer.putUint8(132);
-      writeValue(buffer, value.encode());
-    } else if (value is SKProductDiscountMessage) {
+      writeValue(buffer, value.index);
+    } else if (value is SKPaymentTransactionMessage) {
       buffer.putUint8(133);
       writeValue(buffer, value.encode());
-    } else if (value is SKProductMessage) {
+    } else if (value is SKPaymentMessage) {
       buffer.putUint8(134);
       writeValue(buffer, value.encode());
-    } else if (value is SKProductSubscriptionPeriodMessage) {
+    } else if (value is SKErrorMessage) {
       buffer.putUint8(135);
       writeValue(buffer, value.encode());
-    } else if (value is SKProductsResponseMessage) {
+    } else if (value is SKPaymentDiscountMessage) {
       buffer.putUint8(136);
       writeValue(buffer, value.encode());
     } else if (value is SKStorefrontMessage) {
       buffer.putUint8(137);
       writeValue(buffer, value.encode());
+    } else if (value is SKProductsResponseMessage) {
+      buffer.putUint8(138);
+      writeValue(buffer, value.encode());
+    } else if (value is SKProductMessage) {
+      buffer.putUint8(139);
+      writeValue(buffer, value.encode());
+    } else if (value is SKPriceLocaleMessage) {
+      buffer.putUint8(140);
+      writeValue(buffer, value.encode());
+    } else if (value is SKProductDiscountMessage) {
+      buffer.putUint8(141);
+      writeValue(buffer, value.encode());
+    } else if (value is SKProductSubscriptionPeriodMessage) {
+      buffer.putUint8(142);
+      writeValue(buffer, value.encode());
     } else {
       super.writeValue(buffer, value);
     }
@@ -55,26 +70,46 @@ class _TestInAppPurchaseApiCodec extends StandardMessageCodec {
   @override
   Object? readValueOfType(int type, ReadBuffer buffer) {
     switch (type) {
-      case 128:
-        return SKErrorMessage.decode(readValue(buffer)!);
       case 129:
-        return SKPaymentDiscountMessage.decode(readValue(buffer)!);
+        final int? value = readValue(buffer) as int?;
+        return value == null
+            ? null
+            : SKPaymentTransactionStateMessage.values[value];
       case 130:
-        return SKPaymentMessage.decode(readValue(buffer)!);
+        final int? value = readValue(buffer) as int?;
+        return value == null
+            ? null
+            : SKProductDiscountTypeMessage.values[value];
       case 131:
-        return SKPaymentTransactionMessage.decode(readValue(buffer)!);
+        final int? value = readValue(buffer) as int?;
+        return value == null
+            ? null
+            : SKProductDiscountPaymentModeMessage.values[value];
       case 132:
-        return SKPriceLocaleMessage.decode(readValue(buffer)!);
+        final int? value = readValue(buffer) as int?;
+        return value == null
+            ? null
+            : SKSubscriptionPeriodUnitMessage.values[value];
       case 133:
-        return SKProductDiscountMessage.decode(readValue(buffer)!);
+        return SKPaymentTransactionMessage.decode(readValue(buffer)!);
       case 134:
-        return SKProductMessage.decode(readValue(buffer)!);
+        return SKPaymentMessage.decode(readValue(buffer)!);
       case 135:
-        return SKProductSubscriptionPeriodMessage.decode(readValue(buffer)!);
+        return SKErrorMessage.decode(readValue(buffer)!);
       case 136:
-        return SKProductsResponseMessage.decode(readValue(buffer)!);
+        return SKPaymentDiscountMessage.decode(readValue(buffer)!);
       case 137:
         return SKStorefrontMessage.decode(readValue(buffer)!);
+      case 138:
+        return SKProductsResponseMessage.decode(readValue(buffer)!);
+      case 139:
+        return SKProductMessage.decode(readValue(buffer)!);
+      case 140:
+        return SKPriceLocaleMessage.decode(readValue(buffer)!);
+      case 141:
+        return SKProductDiscountMessage.decode(readValue(buffer)!);
+      case 142:
+        return SKProductSubscriptionPeriodMessage.decode(readValue(buffer)!);
       default:
         return super.readValueOfType(type, buffer);
     }
@@ -84,22 +119,21 @@ class _TestInAppPurchaseApiCodec extends StandardMessageCodec {
 abstract class TestInAppPurchaseApi {
   static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
       TestDefaultBinaryMessengerBinding.instance;
-  static const MessageCodec pigeonChannelCodec =
-      _TestInAppPurchaseApiCodec();
+  static const MessageCodec pigeonChannelCodec = _PigeonCodec();
 
   /// Returns if the current device is able to make payments
   bool canMakePayments();
 
-  List transactions();
+  List transactions();
 
   SKStorefrontMessage storefront();
 
-  void addPayment(Map paymentMap);
+  void addPayment(Map paymentMap);
 
   Future startProductRequest(
-      List productIdentifiers);
+      List productIdentifiers);
 
-  void finishTransaction(Map finishMap);
+  void finishTransaction(Map finishMap);
 
   void restoreTransactions(String? applicationUserName);
 
@@ -107,7 +141,7 @@ abstract class TestInAppPurchaseApi {
 
   String? retrieveReceiptData();
 
-  Future refreshReceipt({Map? receiptProperties});
+  Future refreshReceipt({Map? receiptProperties});
 
   void startObservingPaymentQueue();
 
@@ -119,20 +153,26 @@ abstract class TestInAppPurchaseApi {
 
   void showPriceConsentIfNeeded();
 
-  static void setup(TestInAppPurchaseApi? api,
-      {BinaryMessenger? binaryMessenger}) {
+  static void setUp(
+    TestInAppPurchaseApi? api, {
+    BinaryMessenger? binaryMessenger,
+    String messageChannelSuffix = '',
+  }) {
+    messageChannelSuffix =
+        messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
     {
-      final BasicMessageChannel __pigeon_channel = BasicMessageChannel<
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
               Object?>(
-          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.canMakePayments',
+          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.canMakePayments$messageChannelSuffix',
           pigeonChannelCodec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel, null);
+            .setMockDecodedMessageHandler(pigeonVar_channel, null);
       } else {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel,
+            .setMockDecodedMessageHandler(pigeonVar_channel,
                 (Object? message) async {
           try {
             final bool output = api.canMakePayments();
@@ -147,21 +187,21 @@ abstract class TestInAppPurchaseApi {
       }
     }
     {
-      final BasicMessageChannel __pigeon_channel = BasicMessageChannel<
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
               Object?>(
-          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.transactions',
+          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.transactions$messageChannelSuffix',
           pigeonChannelCodec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel, null);
+            .setMockDecodedMessageHandler(pigeonVar_channel, null);
       } else {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel,
+            .setMockDecodedMessageHandler(pigeonVar_channel,
                 (Object? message) async {
           try {
-            final List output =
-                api.transactions();
+            final List output = api.transactions();
             return [output];
           } on PlatformException catch (e) {
             return wrapResponse(error: e);
@@ -173,17 +213,18 @@ abstract class TestInAppPurchaseApi {
       }
     }
     {
-      final BasicMessageChannel __pigeon_channel = BasicMessageChannel<
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
               Object?>(
-          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.storefront',
+          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.storefront$messageChannelSuffix',
           pigeonChannelCodec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel, null);
+            .setMockDecodedMessageHandler(pigeonVar_channel, null);
       } else {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel,
+            .setMockDecodedMessageHandler(pigeonVar_channel,
                 (Object? message) async {
           try {
             final SKStorefrontMessage output = api.storefront();
@@ -198,25 +239,26 @@ abstract class TestInAppPurchaseApi {
       }
     }
     {
-      final BasicMessageChannel __pigeon_channel = BasicMessageChannel<
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
               Object?>(
-          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.addPayment',
+          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.addPayment$messageChannelSuffix',
           pigeonChannelCodec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel, null);
+            .setMockDecodedMessageHandler(pigeonVar_channel, null);
       } else {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel,
+            .setMockDecodedMessageHandler(pigeonVar_channel,
                 (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.addPayment was null.');
           final List args = (message as List?)!;
-          final Map? arg_paymentMap =
-              (args[0] as Map?)?.cast();
+          final Map? arg_paymentMap =
+              (args[0] as Map?)?.cast();
           assert(arg_paymentMap != null,
-              'Argument for dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.addPayment was null, expected non-null Map.');
+              'Argument for dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.addPayment was null, expected non-null Map.');
           try {
             api.addPayment(arg_paymentMap!);
             return wrapResponse(empty: true);
@@ -230,25 +272,26 @@ abstract class TestInAppPurchaseApi {
       }
     }
     {
-      final BasicMessageChannel __pigeon_channel = BasicMessageChannel<
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
               Object?>(
-          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.startProductRequest',
+          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.startProductRequest$messageChannelSuffix',
           pigeonChannelCodec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel, null);
+            .setMockDecodedMessageHandler(pigeonVar_channel, null);
       } else {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel,
+            .setMockDecodedMessageHandler(pigeonVar_channel,
                 (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.startProductRequest was null.');
           final List args = (message as List?)!;
-          final List? arg_productIdentifiers =
-              (args[0] as List?)?.cast();
+          final List? arg_productIdentifiers =
+              (args[0] as List?)?.cast();
           assert(arg_productIdentifiers != null,
-              'Argument for dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.startProductRequest was null, expected non-null List.');
+              'Argument for dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.startProductRequest was null, expected non-null List.');
           try {
             final SKProductsResponseMessage output =
                 await api.startProductRequest(arg_productIdentifiers!);
@@ -263,25 +306,26 @@ abstract class TestInAppPurchaseApi {
       }
     }
     {
-      final BasicMessageChannel __pigeon_channel = BasicMessageChannel<
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
               Object?>(
-          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.finishTransaction',
+          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.finishTransaction$messageChannelSuffix',
           pigeonChannelCodec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel, null);
+            .setMockDecodedMessageHandler(pigeonVar_channel, null);
       } else {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel,
+            .setMockDecodedMessageHandler(pigeonVar_channel,
                 (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.finishTransaction was null.');
           final List args = (message as List?)!;
-          final Map? arg_finishMap =
-              (args[0] as Map?)?.cast();
+          final Map? arg_finishMap =
+              (args[0] as Map?)?.cast();
           assert(arg_finishMap != null,
-              'Argument for dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.finishTransaction was null, expected non-null Map.');
+              'Argument for dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.finishTransaction was null, expected non-null Map.');
           try {
             api.finishTransaction(arg_finishMap!);
             return wrapResponse(empty: true);
@@ -295,17 +339,18 @@ abstract class TestInAppPurchaseApi {
       }
     }
     {
-      final BasicMessageChannel __pigeon_channel = BasicMessageChannel<
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
               Object?>(
-          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.restoreTransactions',
+          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.restoreTransactions$messageChannelSuffix',
           pigeonChannelCodec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel, null);
+            .setMockDecodedMessageHandler(pigeonVar_channel, null);
       } else {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel,
+            .setMockDecodedMessageHandler(pigeonVar_channel,
                 (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.restoreTransactions was null.');
@@ -324,17 +369,18 @@ abstract class TestInAppPurchaseApi {
       }
     }
     {
-      final BasicMessageChannel __pigeon_channel = BasicMessageChannel<
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
               Object?>(
-          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.presentCodeRedemptionSheet',
+          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.presentCodeRedemptionSheet$messageChannelSuffix',
           pigeonChannelCodec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel, null);
+            .setMockDecodedMessageHandler(pigeonVar_channel, null);
       } else {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel,
+            .setMockDecodedMessageHandler(pigeonVar_channel,
                 (Object? message) async {
           try {
             api.presentCodeRedemptionSheet();
@@ -349,17 +395,18 @@ abstract class TestInAppPurchaseApi {
       }
     }
     {
-      final BasicMessageChannel __pigeon_channel = BasicMessageChannel<
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
               Object?>(
-          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.retrieveReceiptData',
+          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.retrieveReceiptData$messageChannelSuffix',
           pigeonChannelCodec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel, null);
+            .setMockDecodedMessageHandler(pigeonVar_channel, null);
       } else {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel,
+            .setMockDecodedMessageHandler(pigeonVar_channel,
                 (Object? message) async {
           try {
             final String? output = api.retrieveReceiptData();
@@ -374,23 +421,24 @@ abstract class TestInAppPurchaseApi {
       }
     }
     {
-      final BasicMessageChannel __pigeon_channel = BasicMessageChannel<
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
               Object?>(
-          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.refreshReceipt',
+          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.refreshReceipt$messageChannelSuffix',
           pigeonChannelCodec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel, null);
+            .setMockDecodedMessageHandler(pigeonVar_channel, null);
       } else {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel,
+            .setMockDecodedMessageHandler(pigeonVar_channel,
                 (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.refreshReceipt was null.');
           final List args = (message as List?)!;
-          final Map? arg_receiptProperties =
-              (args[0] as Map?)?.cast();
+          final Map? arg_receiptProperties =
+              (args[0] as Map?)?.cast();
           try {
             await api.refreshReceipt(receiptProperties: arg_receiptProperties);
             return wrapResponse(empty: true);
@@ -404,17 +452,18 @@ abstract class TestInAppPurchaseApi {
       }
     }
     {
-      final BasicMessageChannel __pigeon_channel = BasicMessageChannel<
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
               Object?>(
-          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.startObservingPaymentQueue',
+          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.startObservingPaymentQueue$messageChannelSuffix',
           pigeonChannelCodec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel, null);
+            .setMockDecodedMessageHandler(pigeonVar_channel, null);
       } else {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel,
+            .setMockDecodedMessageHandler(pigeonVar_channel,
                 (Object? message) async {
           try {
             api.startObservingPaymentQueue();
@@ -429,17 +478,18 @@ abstract class TestInAppPurchaseApi {
       }
     }
     {
-      final BasicMessageChannel __pigeon_channel = BasicMessageChannel<
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
               Object?>(
-          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.stopObservingPaymentQueue',
+          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.stopObservingPaymentQueue$messageChannelSuffix',
           pigeonChannelCodec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel, null);
+            .setMockDecodedMessageHandler(pigeonVar_channel, null);
       } else {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel,
+            .setMockDecodedMessageHandler(pigeonVar_channel,
                 (Object? message) async {
           try {
             api.stopObservingPaymentQueue();
@@ -454,17 +504,18 @@ abstract class TestInAppPurchaseApi {
       }
     }
     {
-      final BasicMessageChannel __pigeon_channel = BasicMessageChannel<
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
               Object?>(
-          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.registerPaymentQueueDelegate',
+          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.registerPaymentQueueDelegate$messageChannelSuffix',
           pigeonChannelCodec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel, null);
+            .setMockDecodedMessageHandler(pigeonVar_channel, null);
       } else {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel,
+            .setMockDecodedMessageHandler(pigeonVar_channel,
                 (Object? message) async {
           try {
             api.registerPaymentQueueDelegate();
@@ -479,17 +530,18 @@ abstract class TestInAppPurchaseApi {
       }
     }
     {
-      final BasicMessageChannel __pigeon_channel = BasicMessageChannel<
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
               Object?>(
-          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.removePaymentQueueDelegate',
+          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.removePaymentQueueDelegate$messageChannelSuffix',
           pigeonChannelCodec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel, null);
+            .setMockDecodedMessageHandler(pigeonVar_channel, null);
       } else {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel,
+            .setMockDecodedMessageHandler(pigeonVar_channel,
                 (Object? message) async {
           try {
             api.removePaymentQueueDelegate();
@@ -504,17 +556,18 @@ abstract class TestInAppPurchaseApi {
       }
     }
     {
-      final BasicMessageChannel __pigeon_channel = BasicMessageChannel<
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
               Object?>(
-          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.showPriceConsentIfNeeded',
+          'dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchaseAPI.showPriceConsentIfNeeded$messageChannelSuffix',
           pigeonChannelCodec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel, null);
+            .setMockDecodedMessageHandler(pigeonVar_channel, null);
       } else {
         _testBinaryMessengerBinding!.defaultBinaryMessenger
-            .setMockDecodedMessageHandler(__pigeon_channel,
+            .setMockDecodedMessageHandler(pigeonVar_channel,
                 (Object? message) async {
           try {
             api.showPriceConsentIfNeeded();
diff --git a/packages/interactive_media_ads/CHANGELOG.md b/packages/interactive_media_ads/CHANGELOG.md
index 7bfcc2e6e164..5ae570839df5 100644
--- a/packages/interactive_media_ads/CHANGELOG.md
+++ b/packages/interactive_media_ads/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.2+14
+
+* Adds internal wrapper for iOS native `IMACompanionAdSlot` and `IMACompanionDelegate`.
+
 ## 0.2.2+13
 
 * Adds internal wrapper for Android native `Ad`.
diff --git a/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt b/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt
index 469848956ca2..a2c2dde0c086 100644
--- a/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt
+++ b/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt
@@ -21,7 +21,7 @@ class AdsRequestProxyApi(override val pigeonRegistrar: ProxyApiRegistrar) :
      *
      * This must match the version in pubspec.yaml.
      */
-    const val pluginVersion = "0.2.2+13"
+    const val pluginVersion = "0.2.2+14"
   }
 
   override fun setAdTagUrl(pigeon_instance: AdsRequest, adTagUrl: String) {
diff --git a/packages/interactive_media_ads/example/android/app/build.gradle b/packages/interactive_media_ads/example/android/app/build.gradle
index 97e8ae9a06dc..5d5473c54690 100644
--- a/packages/interactive_media_ads/example/android/app/build.gradle
+++ b/packages/interactive_media_ads/example/android/app/build.gradle
@@ -44,7 +44,6 @@ android {
         applicationId "dev.flutter.packages.interactive_media_ads_example"
         minSdk flutter.minSdkVersion
         targetSdk flutter.targetSdkVersion
-        multiDexEnabled true
         versionCode flutterVersionCode.toInteger()
         versionName flutterVersionName
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/packages/interactive_media_ads/example/ios/Runner.xcodeproj/project.pbxproj b/packages/interactive_media_ads/example/ios/Runner.xcodeproj/project.pbxproj
index 545e2e91598f..b37fd7b5a413 100644
--- a/packages/interactive_media_ads/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/packages/interactive_media_ads/example/ios/Runner.xcodeproj/project.pbxproj
@@ -28,6 +28,8 @@
 		8F977DD92C2C8C6A00A90D4B /* AdLoadingErrorDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F977DD82C2C8C6A00A90D4B /* AdLoadingErrorDataTests.swift */; };
 		8F977DDB2C2C8D2E00A90D4B /* AdsLoadedDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F977DDA2C2C8D2E00A90D4B /* AdsLoadedDataTests.swift */; };
 		8FC919922CA5D86F00188068 /* FriendlyObstructionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FC919912CA5D86F00188068 /* FriendlyObstructionTests.swift */; };
+		8FFF0C182CC1A7F300A7CB98 /* CompanionAdSlotProxyApiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FFF0C172CC1A7F300A7CB98 /* CompanionAdSlotProxyApiTests.swift */; };
+		8FFF0C1A2CC1A97B00A7CB98 /* CompanionDelegateProxyApiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FFF0C192CC1A97B00A7CB98 /* CompanionDelegateProxyApiTests.swift */; };
 		97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
 		97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
 		97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
@@ -87,6 +89,8 @@
 		8F977DD82C2C8C6A00A90D4B /* AdLoadingErrorDataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdLoadingErrorDataTests.swift; sourceTree = ""; };
 		8F977DDA2C2C8D2E00A90D4B /* AdsLoadedDataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdsLoadedDataTests.swift; sourceTree = ""; };
 		8FC919912CA5D86F00188068 /* FriendlyObstructionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FriendlyObstructionTests.swift; sourceTree = ""; };
+		8FFF0C172CC1A7F300A7CB98 /* CompanionAdSlotProxyApiTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompanionAdSlotProxyApiTests.swift; sourceTree = ""; };
+		8FFF0C192CC1A97B00A7CB98 /* CompanionDelegateProxyApiTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompanionDelegateProxyApiTests.swift; sourceTree = ""; };
 		9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
 		9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
 		97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -136,6 +140,8 @@
 				8F599BBC2C332CFE0090A0DF /* ContentPlayheadTests.swift */,
 				8F599BBE2C3335B40090A0DF /* ViewControllerTests.swift */,
 				8F8382A22CBDB4A4007F28E0 /* CompanionAdProxyApiTests.swift */,
+				8FFF0C172CC1A7F300A7CB98 /* CompanionAdSlotProxyApiTests.swift */,
+				8FFF0C192CC1A97B00A7CB98 /* CompanionDelegateProxyApiTests.swift */,
 			);
 			path = RunnerTests;
 			sourceTree = "";
@@ -423,6 +429,8 @@
 				8F599BBB2C332C010090A0DF /* AdsRequestTests.swift in Sources */,
 				8F599BB72C3327F10090A0DF /* AdsManagerDelegateTests.swift in Sources */,
 				8F599BBD2C332CFE0090A0DF /* ContentPlayheadTests.swift in Sources */,
+				8FFF0C182CC1A7F300A7CB98 /* CompanionAdSlotProxyApiTests.swift in Sources */,
+				8FFF0C1A2CC1A97B00A7CB98 /* CompanionDelegateProxyApiTests.swift in Sources */,
 				8F977DCF2C2B99C600A90D4B /* AdDisplayContainerTests.swift in Sources */,
 				8F599BB52C2DD8EC0090A0DF /* AdsLoaderDelegateTests.swift in Sources */,
 				8F599BB92C332A320090A0DF /* AdsRenderingSettingsTests.swift in Sources */,
diff --git a/packages/interactive_media_ads/example/ios/RunnerTests/CompanionAdSlotProxyApiTests.swift b/packages/interactive_media_ads/example/ios/RunnerTests/CompanionAdSlotProxyApiTests.swift
new file mode 100644
index 000000000000..987389e58226
--- /dev/null
+++ b/packages/interactive_media_ads/example/ios/RunnerTests/CompanionAdSlotProxyApiTests.swift
@@ -0,0 +1,58 @@
+// 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 Flutter
+import GoogleInteractiveMediaAds
+import UIKit
+import XCTest
+
+@testable import interactive_media_ads
+
+class CompanionAdSlotProxyApiTests: XCTestCase {
+  func testPigeonDefaultConstructor() {
+    let registrar = TestProxyApiRegistrar()
+    let api = registrar.apiDelegate.pigeonApiIMACompanionAdSlot(registrar)
+
+    let view = UIView()
+    let instance = try! api.pigeonDelegate.pigeonDefaultConstructor(pigeonApi: api, view: view)
+    XCTAssertEqual(instance.view, view)
+  }
+
+  func testSize() {
+    let registrar = TestProxyApiRegistrar()
+    let api = registrar.apiDelegate.pigeonApiIMACompanionAdSlot(registrar)
+
+    let view = UIView()
+    let width = 0
+    let height = 1
+    let instance = try! api.pigeonDelegate.size(
+      pigeonApi: api, view: view, width: Int64(width), height: Int64(height))
+    XCTAssertEqual(instance.view, view)
+    XCTAssertEqual(instance.width, width)
+    XCTAssertEqual(instance.height, height)
+  }
+
+  func testView() {
+    let registrar = TestProxyApiRegistrar()
+    let api = registrar.apiDelegate.pigeonApiIMACompanionAdSlot(registrar)
+
+    let instance = IMACompanionAdSlot(view: UIView())
+    let value = try? api.pigeonDelegate.view(pigeonApi: api, pigeonInstance: instance)
+
+    XCTAssertEqual(value, instance.view)
+  }
+
+  func testSetDelegate() {
+    let registrar = TestProxyApiRegistrar()
+    let api = registrar.apiDelegate.pigeonApiIMACompanionAdSlot(registrar)
+
+    let instance = IMACompanionAdSlot(view: UIView())
+    let delegate = CompanionDelegateImpl(
+      api: registrar.apiDelegate.pigeonApiIMACompanionDelegate(registrar))
+    try? api.pigeonDelegate.setDelegate(
+      pigeonApi: api, pigeonInstance: instance, delegate: delegate)
+
+    XCTAssertIdentical(instance.delegate, delegate)
+  }
+}
diff --git a/packages/interactive_media_ads/example/ios/RunnerTests/CompanionDelegateProxyApiTests.swift b/packages/interactive_media_ads/example/ios/RunnerTests/CompanionDelegateProxyApiTests.swift
new file mode 100644
index 000000000000..e66f5e2a5f06
--- /dev/null
+++ b/packages/interactive_media_ads/example/ios/RunnerTests/CompanionDelegateProxyApiTests.swift
@@ -0,0 +1,59 @@
+// 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 Flutter
+import GoogleInteractiveMediaAds
+import UIKit
+import XCTest
+
+@testable import interactive_media_ads
+
+class CompanionDelegateProxyApiTests: XCTestCase {
+  func testPigeonDefaultConstructor() {
+    let registrar = TestProxyApiRegistrar()
+    let api = registrar.apiDelegate.pigeonApiIMACompanionDelegate(registrar)
+
+    let instance = try? api.pigeonDelegate.pigeonDefaultConstructor(pigeonApi: api)
+    XCTAssertNotNil(instance)
+  }
+
+  func testCompanionAdSlotFilled() {
+    let api = TestCompanionDelegateApi()
+    let instance = CompanionDelegateImpl(api: api)
+    let slot = IMACompanionAdSlot(view: UIView())
+    let filled = true
+    instance.companionSlot(slot, filled: filled)
+
+    XCTAssertEqual(api.companionAdSlotFilledArgs, [slot, filled])
+  }
+
+  func testCompanionSlotWasClicked() {
+    let api = TestCompanionDelegateApi()
+    let instance = CompanionDelegateImpl(api: api)
+    let slot = IMACompanionAdSlot(view: UIView())
+    instance.companionSlotWasClicked(slot)
+
+    XCTAssertEqual(api.companionSlotWasClickedArgs, [slot])
+  }
+}
+
+class TestCompanionDelegateApi: PigeonApiProtocolIMACompanionDelegate {
+  var companionAdSlotFilledArgs: [AnyHashable?]? = nil
+  var companionSlotWasClickedArgs: [AnyHashable?]? = nil
+
+  func companionAdSlotFilled(
+    pigeonInstance pigeonInstanceArg: IMACompanionDelegate, slot slotArg: IMACompanionAdSlot,
+    filled filledArg: Bool,
+    completion: @escaping (Result) -> Void
+  ) {
+    companionAdSlotFilledArgs = [slotArg, filledArg]
+  }
+
+  func companionSlotWasClicked(
+    pigeonInstance pigeonInstanceArg: IMACompanionDelegate, slot slotArg: IMACompanionAdSlot,
+    completion: @escaping (Result) -> Void
+  ) {
+    companionSlotWasClickedArgs = [slotArg]
+  }
+}
diff --git a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift
index c451d574ab23..f652b7506cd1 100644
--- a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift
+++ b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift
@@ -13,7 +13,7 @@ class AdsRequestProxyAPIDelegate: PigeonApiDelegateIMAAdsRequest {
   /// The current version of the `interactive_media_ads` plugin.
   ///
   /// This must match the version in pubspec.yaml.
-  static let pluginVersion = "0.2.2+13"
+  static let pluginVersion = "0.2.2+14"
 
   func pigeonDefaultConstructor(
     pigeonApi: PigeonApiIMAAdsRequest, adTagUrl: String, adDisplayContainer: IMAAdDisplayContainer,
diff --git a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/CompanionAdSlotProxyAPIDelegate.swift b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/CompanionAdSlotProxyAPIDelegate.swift
new file mode 100644
index 000000000000..263063221a5e
--- /dev/null
+++ b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/CompanionAdSlotProxyAPIDelegate.swift
@@ -0,0 +1,38 @@
+// 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 Foundation
+import GoogleInteractiveMediaAds
+import UIKit
+
+/// ProxyApi implementation for [IMACompanionAdSlot].
+///
+/// This class may handle instantiating native object instances that are attached to a Dart instance
+/// or handle method calls on the associated native class or an instance of that class.
+class CompanionAdSlotProxyAPIDelegate: PigeonApiDelegateIMACompanionAdSlot {
+  func pigeonDefaultConstructor(pigeonApi: PigeonApiIMACompanionAdSlot, view: UIView) throws
+    -> IMACompanionAdSlot
+  {
+    return IMACompanionAdSlot(view: view)
+  }
+
+  func size(pigeonApi: PigeonApiIMACompanionAdSlot, view: UIView, width: Int64, height: Int64)
+    throws -> IMACompanionAdSlot
+  {
+    return IMACompanionAdSlot(view: view, width: Int(width), height: Int(height))
+  }
+
+  func view(pigeonApi: PigeonApiIMACompanionAdSlot, pigeonInstance: IMACompanionAdSlot) throws
+    -> UIView
+  {
+    return pigeonInstance.view
+  }
+
+  func setDelegate(
+    pigeonApi: PigeonApiIMACompanionAdSlot, pigeonInstance: IMACompanionAdSlot,
+    delegate: IMACompanionDelegate?
+  ) throws {
+    pigeonInstance.delegate = delegate
+  }
+}
diff --git a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/CompanionDelegateProxyAPIDelegate.swift b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/CompanionDelegateProxyAPIDelegate.swift
new file mode 100644
index 000000000000..b7e1a5f6d08b
--- /dev/null
+++ b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/CompanionDelegateProxyAPIDelegate.swift
@@ -0,0 +1,35 @@
+// 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 Foundation
+import GoogleInteractiveMediaAds
+
+/// Implementation of `IMACompanionDelegate` that calls to Dart in callback methods.
+class CompanionDelegateImpl: NSObject, IMACompanionDelegate {
+  let api: PigeonApiProtocolIMACompanionDelegate
+
+  init(api: PigeonApiProtocolIMACompanionDelegate) {
+    self.api = api
+  }
+
+  func companionSlot(_ slot: IMACompanionAdSlot, filled: Bool) {
+    api.companionAdSlotFilled(pigeonInstance: self, slot: slot, filled: filled) { _ in }
+  }
+
+  func companionSlotWasClicked(_ slot: IMACompanionAdSlot) {
+    api.companionSlotWasClicked(pigeonInstance: self, slot: slot) { _ in }
+  }
+}
+
+/// ProxyApi implementation for [IMACompanionDelegate].
+///
+/// This class may handle instantiating native object instances that are attached to a Dart instance
+/// or handle method calls on the associated native class or an instance of that class.
+class CompanionDelegateProxyAPIDelegate: PigeonApiDelegateIMACompanionDelegate {
+  func pigeonDefaultConstructor(pigeonApi: PigeonApiIMACompanionDelegate) throws
+    -> IMACompanionDelegate
+  {
+    return CompanionDelegateImpl(api: pigeonApi)
+  }
+}
diff --git a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/InteractiveMediaAdsLibrary.g.swift b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/InteractiveMediaAdsLibrary.g.swift
index 3100f774490d..501b6ac923ff 100644
--- a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/InteractiveMediaAdsLibrary.g.swift
+++ b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/InteractiveMediaAdsLibrary.g.swift
@@ -449,6 +449,14 @@ protocol InteractiveMediaAdsLibraryPigeonProxyApiDelegate {
   /// `IMACompanionAd` to the Dart `InstanceManager` and make calls to Dart.
   func pigeonApiIMACompanionAd(_ registrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar)
     -> PigeonApiIMACompanionAd
+  /// An implementation of [PigeonApiIMACompanionAdSlot] used to add a new Dart instance of
+  /// `IMACompanionAdSlot` to the Dart `InstanceManager` and make calls to Dart.
+  func pigeonApiIMACompanionAdSlot(_ registrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar)
+    -> PigeonApiIMACompanionAdSlot
+  /// An implementation of [PigeonApiIMACompanionDelegate] used to add a new Dart instance of
+  /// `IMACompanionDelegate` to the Dart `InstanceManager` and make calls to Dart.
+  func pigeonApiIMACompanionDelegate(_ registrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar)
+    -> PigeonApiIMACompanionDelegate
 }
 
 extension InteractiveMediaAdsLibraryPigeonProxyApiDelegate {
@@ -536,6 +544,10 @@ open class InteractiveMediaAdsLibraryPigeonProxyApiRegistrar {
       binaryMessenger: binaryMessenger, api: apiDelegate.pigeonApiIMAAdsRenderingSettings(self))
     PigeonApiIMAFriendlyObstruction.setUpMessageHandlers(
       binaryMessenger: binaryMessenger, api: apiDelegate.pigeonApiIMAFriendlyObstruction(self))
+    PigeonApiIMACompanionAdSlot.setUpMessageHandlers(
+      binaryMessenger: binaryMessenger, api: apiDelegate.pigeonApiIMACompanionAdSlot(self))
+    PigeonApiIMACompanionDelegate.setUpMessageHandlers(
+      binaryMessenger: binaryMessenger, api: apiDelegate.pigeonApiIMACompanionDelegate(self))
   }
   func tearDown() {
     InteractiveMediaAdsLibraryPigeonInstanceManagerApi.setUpMessageHandlers(
@@ -551,6 +563,8 @@ open class InteractiveMediaAdsLibraryPigeonProxyApiRegistrar {
     PigeonApiIMAAdsRenderingSettings.setUpMessageHandlers(
       binaryMessenger: binaryMessenger, api: nil)
     PigeonApiIMAFriendlyObstruction.setUpMessageHandlers(binaryMessenger: binaryMessenger, api: nil)
+    PigeonApiIMACompanionAdSlot.setUpMessageHandlers(binaryMessenger: binaryMessenger, api: nil)
+    PigeonApiIMACompanionDelegate.setUpMessageHandlers(binaryMessenger: binaryMessenger, api: nil)
   }
 }
 private class InteractiveMediaAdsLibraryPigeonInternalProxyApiCodecReaderWriter:
@@ -796,6 +810,29 @@ private class InteractiveMediaAdsLibraryPigeonInternalProxyApiCodecReaderWriter:
         return
       }
 
+      if let instance = value as? IMACompanionAdSlot {
+        pigeonRegistrar.apiDelegate.pigeonApiIMACompanionAdSlot(pigeonRegistrar).pigeonNewInstance(
+          pigeonInstance: instance
+        ) { _ in }
+        super.writeByte(128)
+        super.writeValue(
+          pigeonRegistrar.instanceManager.identifierWithStrongReference(
+            forInstance: instance as AnyObject)!)
+        return
+      }
+
+      if let instance = value as? IMACompanionDelegate {
+        pigeonRegistrar.apiDelegate.pigeonApiIMACompanionDelegate(pigeonRegistrar)
+          .pigeonNewInstance(
+            pigeonInstance: instance
+          ) { _ in }
+        super.writeByte(128)
+        super.writeValue(
+          pigeonRegistrar.instanceManager.identifierWithStrongReference(
+            forInstance: instance as AnyObject)!)
+        return
+      }
+
       if let instance = value as? NSObject {
         pigeonRegistrar.apiDelegate.pigeonApiNSObject(pigeonRegistrar).pigeonNewInstance(
           pigeonInstance: instance
@@ -3347,3 +3384,328 @@ final class PigeonApiIMACompanionAd: PigeonApiProtocolIMACompanionAd {
     }
   }
 }
+protocol PigeonApiDelegateIMACompanionAdSlot {
+  /// Initializes an instance of a IMACompanionAdSlot with fluid size.
+  func pigeonDefaultConstructor(pigeonApi: PigeonApiIMACompanionAdSlot, view: UIView) throws
+    -> IMACompanionAdSlot
+  /// Initializes an instance of a IMACompanionAdSlot with design ad width and
+  /// height.
+  ///
+  /// `width` and `height` are in pixels.
+  func size(pigeonApi: PigeonApiIMACompanionAdSlot, view: UIView, width: Int64, height: Int64)
+    throws -> IMACompanionAdSlot
+  /// The view the companion will be rendered in.
+  ///
+  /// Display this view in your application before video ad starts.
+  func view(pigeonApi: PigeonApiIMACompanionAdSlot, pigeonInstance: IMACompanionAdSlot) throws
+    -> UIView
+  /// The IMACompanionDelegate for receiving events from the companion ad slot.
+  ///
+  /// This instance only creates a weak reference to the delegate, so the Dart
+  /// instance should create an explicit reference to receive callbacks.
+  func setDelegate(
+    pigeonApi: PigeonApiIMACompanionAdSlot, pigeonInstance: IMACompanionAdSlot,
+    delegate: IMACompanionDelegate?) throws
+}
+
+protocol PigeonApiProtocolIMACompanionAdSlot {
+}
+
+final class PigeonApiIMACompanionAdSlot: PigeonApiProtocolIMACompanionAdSlot {
+  unowned let pigeonRegistrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar
+  let pigeonDelegate: PigeonApiDelegateIMACompanionAdSlot
+  init(
+    pigeonRegistrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar,
+    delegate: PigeonApiDelegateIMACompanionAdSlot
+  ) {
+    self.pigeonRegistrar = pigeonRegistrar
+    self.pigeonDelegate = delegate
+  }
+  static func setUpMessageHandlers(
+    binaryMessenger: FlutterBinaryMessenger, api: PigeonApiIMACompanionAdSlot?
+  ) {
+    let codec: FlutterStandardMessageCodec =
+      api != nil
+      ? FlutterStandardMessageCodec(
+        readerWriter: InteractiveMediaAdsLibraryPigeonInternalProxyApiCodecReaderWriter(
+          pigeonRegistrar: api!.pigeonRegistrar))
+      : FlutterStandardMessageCodec.sharedInstance()
+    let pigeonDefaultConstructorChannel = FlutterBasicMessageChannel(
+      name: "dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.pigeon_defaultConstructor",
+      binaryMessenger: binaryMessenger, codec: codec)
+    if let api = api {
+      pigeonDefaultConstructorChannel.setMessageHandler { message, reply in
+        let args = message as! [Any?]
+        let pigeonIdentifierArg = args[0] as! Int64
+        let viewArg = args[1] as! UIView
+        do {
+          api.pigeonRegistrar.instanceManager.addDartCreatedInstance(
+            try api.pigeonDelegate.pigeonDefaultConstructor(pigeonApi: api, view: viewArg),
+            withIdentifier: pigeonIdentifierArg)
+          reply(wrapResult(nil))
+        } catch {
+          reply(wrapError(error))
+        }
+      }
+    } else {
+      pigeonDefaultConstructorChannel.setMessageHandler(nil)
+    }
+    let sizeChannel = FlutterBasicMessageChannel(
+      name: "dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.pigeon_defaultConstructor",
+      binaryMessenger: binaryMessenger, codec: codec)
+    if let api = api {
+      sizeChannel.setMessageHandler { message, reply in
+        let args = message as! [Any?]
+        let pigeonIdentifierArg = args[0] as! Int64
+        let viewArg = args[1] as! UIView
+        let widthArg = args[2] as! Int64
+        let heightArg = args[3] as! Int64
+        do {
+          api.pigeonRegistrar.instanceManager.addDartCreatedInstance(
+            try api.pigeonDelegate.size(
+              pigeonApi: api, view: viewArg, width: widthArg, height: heightArg),
+            withIdentifier: pigeonIdentifierArg)
+          reply(wrapResult(nil))
+        } catch {
+          reply(wrapError(error))
+        }
+      }
+    } else {
+      sizeChannel.setMessageHandler(nil)
+    }
+    let setDelegateChannel = FlutterBasicMessageChannel(
+      name: "dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.setDelegate",
+      binaryMessenger: binaryMessenger, codec: codec)
+    if let api = api {
+      setDelegateChannel.setMessageHandler { message, reply in
+        let args = message as! [Any?]
+        let pigeonInstanceArg = args[0] as! IMACompanionAdSlot
+        let delegateArg: IMACompanionDelegate? = nilOrValue(args[1])
+        do {
+          try api.pigeonDelegate.setDelegate(
+            pigeonApi: api, pigeonInstance: pigeonInstanceArg, delegate: delegateArg)
+          reply(wrapResult(nil))
+        } catch {
+          reply(wrapError(error))
+        }
+      }
+    } else {
+      setDelegateChannel.setMessageHandler(nil)
+    }
+  }
+
+  ///Creates a Dart instance of IMACompanionAdSlot and attaches it to [pigeonInstance].
+  func pigeonNewInstance(
+    pigeonInstance: IMACompanionAdSlot, completion: @escaping (Result) -> Void
+  ) {
+    if pigeonRegistrar.ignoreCallsToDart {
+      completion(
+        .failure(
+          PigeonError(
+            code: "ignore-calls-error",
+            message: "Calls to Dart are being ignored.", details: "")))
+      return
+    }
+    if pigeonRegistrar.instanceManager.containsInstance(pigeonInstance as AnyObject) {
+      completion(.success(Void()))
+      return
+    }
+    let pigeonIdentifierArg = pigeonRegistrar.instanceManager.addHostCreatedInstance(
+      pigeonInstance as AnyObject)
+    let viewArg = try! pigeonDelegate.view(pigeonApi: self, pigeonInstance: pigeonInstance)
+    let binaryMessenger = pigeonRegistrar.binaryMessenger
+    let codec = pigeonRegistrar.codec
+    let channelName: String =
+      "dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.pigeon_newInstance"
+    let channel = FlutterBasicMessageChannel(
+      name: channelName, binaryMessenger: binaryMessenger, codec: codec)
+    channel.sendMessage([pigeonIdentifierArg, viewArg] as [Any?]) { response in
+      guard let listResponse = response as? [Any?] else {
+        completion(.failure(createConnectionError(withChannelName: channelName)))
+        return
+      }
+      if listResponse.count > 1 {
+        let code: String = listResponse[0] as! String
+        let message: String? = nilOrValue(listResponse[1])
+        let details: String? = nilOrValue(listResponse[2])
+        completion(.failure(PigeonError(code: code, message: message, details: details)))
+      } else {
+        completion(.success(Void()))
+      }
+    }
+  }
+}
+protocol PigeonApiDelegateIMACompanionDelegate {
+  func pigeonDefaultConstructor(pigeonApi: PigeonApiIMACompanionDelegate) throws
+    -> IMACompanionDelegate
+}
+
+protocol PigeonApiProtocolIMACompanionDelegate {
+  /// Called when the slot is either filled or not filled.
+  func companionAdSlotFilled(
+    pigeonInstance pigeonInstanceArg: IMACompanionDelegate, slot slotArg: IMACompanionAdSlot,
+    filled filledArg: Bool, completion: @escaping (Result) -> Void)
+  /// Called when the slot is clicked on by the user and will successfully
+  /// navigate away.
+  func companionSlotWasClicked(
+    pigeonInstance pigeonInstanceArg: IMACompanionDelegate, slot slotArg: IMACompanionAdSlot,
+    completion: @escaping (Result) -> Void)
+}
+
+final class PigeonApiIMACompanionDelegate: PigeonApiProtocolIMACompanionDelegate {
+  unowned let pigeonRegistrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar
+  let pigeonDelegate: PigeonApiDelegateIMACompanionDelegate
+  ///An implementation of [NSObject] used to access callback methods
+  var pigeonApiNSObject: PigeonApiNSObject {
+    return pigeonRegistrar.apiDelegate.pigeonApiNSObject(pigeonRegistrar)
+  }
+
+  init(
+    pigeonRegistrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar,
+    delegate: PigeonApiDelegateIMACompanionDelegate
+  ) {
+    self.pigeonRegistrar = pigeonRegistrar
+    self.pigeonDelegate = delegate
+  }
+  static func setUpMessageHandlers(
+    binaryMessenger: FlutterBinaryMessenger, api: PigeonApiIMACompanionDelegate?
+  ) {
+    let codec: FlutterStandardMessageCodec =
+      api != nil
+      ? FlutterStandardMessageCodec(
+        readerWriter: InteractiveMediaAdsLibraryPigeonInternalProxyApiCodecReaderWriter(
+          pigeonRegistrar: api!.pigeonRegistrar))
+      : FlutterStandardMessageCodec.sharedInstance()
+    let pigeonDefaultConstructorChannel = FlutterBasicMessageChannel(
+      name:
+        "dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.pigeon_defaultConstructor",
+      binaryMessenger: binaryMessenger, codec: codec)
+    if let api = api {
+      pigeonDefaultConstructorChannel.setMessageHandler { message, reply in
+        let args = message as! [Any?]
+        let pigeonIdentifierArg = args[0] as! Int64
+        do {
+          api.pigeonRegistrar.instanceManager.addDartCreatedInstance(
+            try api.pigeonDelegate.pigeonDefaultConstructor(pigeonApi: api),
+            withIdentifier: pigeonIdentifierArg)
+          reply(wrapResult(nil))
+        } catch {
+          reply(wrapError(error))
+        }
+      }
+    } else {
+      pigeonDefaultConstructorChannel.setMessageHandler(nil)
+    }
+  }
+
+  ///Creates a Dart instance of IMACompanionDelegate and attaches it to [pigeonInstance].
+  func pigeonNewInstance(
+    pigeonInstance: IMACompanionDelegate, completion: @escaping (Result) -> Void
+  ) {
+    if pigeonRegistrar.ignoreCallsToDart {
+      completion(
+        .failure(
+          PigeonError(
+            code: "ignore-calls-error",
+            message: "Calls to Dart are being ignored.", details: "")))
+      return
+    }
+    if pigeonRegistrar.instanceManager.containsInstance(pigeonInstance as AnyObject) {
+      completion(.success(Void()))
+      return
+    }
+    let pigeonIdentifierArg = pigeonRegistrar.instanceManager.addHostCreatedInstance(
+      pigeonInstance as AnyObject)
+    let binaryMessenger = pigeonRegistrar.binaryMessenger
+    let codec = pigeonRegistrar.codec
+    let channelName: String =
+      "dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.pigeon_newInstance"
+    let channel = FlutterBasicMessageChannel(
+      name: channelName, binaryMessenger: binaryMessenger, codec: codec)
+    channel.sendMessage([pigeonIdentifierArg] as [Any?]) { response in
+      guard let listResponse = response as? [Any?] else {
+        completion(.failure(createConnectionError(withChannelName: channelName)))
+        return
+      }
+      if listResponse.count > 1 {
+        let code: String = listResponse[0] as! String
+        let message: String? = nilOrValue(listResponse[1])
+        let details: String? = nilOrValue(listResponse[2])
+        completion(.failure(PigeonError(code: code, message: message, details: details)))
+      } else {
+        completion(.success(Void()))
+      }
+    }
+  }
+  /// Called when the slot is either filled or not filled.
+  func companionAdSlotFilled(
+    pigeonInstance pigeonInstanceArg: IMACompanionDelegate, slot slotArg: IMACompanionAdSlot,
+    filled filledArg: Bool, completion: @escaping (Result) -> Void
+  ) {
+    if pigeonRegistrar.ignoreCallsToDart {
+      completion(
+        .failure(
+          PigeonError(
+            code: "ignore-calls-error",
+            message: "Calls to Dart are being ignored.", details: "")))
+      return
+    }
+    let binaryMessenger = pigeonRegistrar.binaryMessenger
+    let codec = pigeonRegistrar.codec
+    let channelName: String =
+      "dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionAdSlotFilled"
+    let channel = FlutterBasicMessageChannel(
+      name: channelName, binaryMessenger: binaryMessenger, codec: codec)
+    channel.sendMessage([pigeonInstanceArg, slotArg, filledArg] as [Any?]) { response in
+      guard let listResponse = response as? [Any?] else {
+        completion(.failure(createConnectionError(withChannelName: channelName)))
+        return
+      }
+      if listResponse.count > 1 {
+        let code: String = listResponse[0] as! String
+        let message: String? = nilOrValue(listResponse[1])
+        let details: String? = nilOrValue(listResponse[2])
+        completion(.failure(PigeonError(code: code, message: message, details: details)))
+      } else {
+        completion(.success(Void()))
+      }
+    }
+  }
+
+  /// Called when the slot is clicked on by the user and will successfully
+  /// navigate away.
+  func companionSlotWasClicked(
+    pigeonInstance pigeonInstanceArg: IMACompanionDelegate, slot slotArg: IMACompanionAdSlot,
+    completion: @escaping (Result) -> Void
+  ) {
+    if pigeonRegistrar.ignoreCallsToDart {
+      completion(
+        .failure(
+          PigeonError(
+            code: "ignore-calls-error",
+            message: "Calls to Dart are being ignored.", details: "")))
+      return
+    }
+    let binaryMessenger = pigeonRegistrar.binaryMessenger
+    let codec = pigeonRegistrar.codec
+    let channelName: String =
+      "dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionSlotWasClicked"
+    let channel = FlutterBasicMessageChannel(
+      name: channelName, binaryMessenger: binaryMessenger, codec: codec)
+    channel.sendMessage([pigeonInstanceArg, slotArg] as [Any?]) { response in
+      guard let listResponse = response as? [Any?] else {
+        completion(.failure(createConnectionError(withChannelName: channelName)))
+        return
+      }
+      if listResponse.count > 1 {
+        let code: String = listResponse[0] as! String
+        let message: String? = nilOrValue(listResponse[1])
+        let details: String? = nilOrValue(listResponse[2])
+        completion(.failure(PigeonError(code: code, message: message, details: details)))
+      } else {
+        completion(.success(Void()))
+      }
+    }
+  }
+
+}
diff --git a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/ProxyApiDelegate.swift b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/ProxyApiDelegate.swift
index 3c9a26c6a4fc..0475adf37efa 100644
--- a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/ProxyApiDelegate.swift
+++ b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/ProxyApiDelegate.swift
@@ -131,4 +131,18 @@ open class ProxyApiDelegate: InteractiveMediaAdsLibraryPigeonProxyApiDelegate {
     return PigeonApiIMACompanionAd(
       pigeonRegistrar: registrar, delegate: CompanionAdProxyAPIDelegate())
   }
+
+  func pigeonApiIMACompanionAdSlot(_ registrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar)
+    -> PigeonApiIMACompanionAdSlot
+  {
+    return PigeonApiIMACompanionAdSlot(
+      pigeonRegistrar: registrar, delegate: CompanionAdSlotProxyAPIDelegate())
+  }
+
+  func pigeonApiIMACompanionDelegate(_ registrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar)
+    -> PigeonApiIMACompanionDelegate
+  {
+    return PigeonApiIMACompanionDelegate(
+      pigeonRegistrar: registrar, delegate: CompanionDelegateProxyAPIDelegate())
+  }
 }
diff --git a/packages/interactive_media_ads/lib/src/ios/interactive_media_ads.g.dart b/packages/interactive_media_ads/lib/src/ios/interactive_media_ads.g.dart
index b3ac07482862..a26cfa675acb 100644
--- a/packages/interactive_media_ads/lib/src/ios/interactive_media_ads.g.dart
+++ b/packages/interactive_media_ads/lib/src/ios/interactive_media_ads.g.dart
@@ -173,6 +173,10 @@ class PigeonInstanceManager {
         pigeon_instanceManager: instanceManager);
     IMACompanionAd.pigeon_setUpMessageHandlers(
         pigeon_instanceManager: instanceManager);
+    IMACompanionAdSlot.pigeon_setUpMessageHandlers(
+        pigeon_instanceManager: instanceManager);
+    IMACompanionDelegate.pigeon_setUpMessageHandlers(
+        pigeon_instanceManager: instanceManager);
     return instanceManager;
   }
 
@@ -3608,3 +3612,450 @@ class IMACompanionAd extends NSObject {
     );
   }
 }
+
+/// Ad slot for companion ads.
+///
+/// See https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side/reference/Classes/IMACompanionAdSlot.
+class IMACompanionAdSlot extends PigeonInternalProxyApiBaseClass {
+  /// Initializes an instance of a IMACompanionAdSlot with fluid size.
+  IMACompanionAdSlot({
+    super.pigeon_binaryMessenger,
+    super.pigeon_instanceManager,
+    required this.view,
+  }) {
+    final int pigeonVar_instanceIdentifier =
+        pigeon_instanceManager.addDartCreatedInstance(this);
+    final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec =
+        _pigeonVar_codecIMACompanionAdSlot;
+    final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger;
+    () async {
+      const String pigeonVar_channelName =
+          'dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.pigeon_defaultConstructor';
+      final BasicMessageChannel pigeonVar_channel =
+          BasicMessageChannel(
+        pigeonVar_channelName,
+        pigeonChannelCodec,
+        binaryMessenger: pigeonVar_binaryMessenger,
+      );
+      final List? pigeonVar_replyList = await pigeonVar_channel
+              .send([pigeonVar_instanceIdentifier, view])
+          as List?;
+      if (pigeonVar_replyList == null) {
+        throw _createConnectionError(pigeonVar_channelName);
+      } else if (pigeonVar_replyList.length > 1) {
+        throw PlatformException(
+          code: pigeonVar_replyList[0]! as String,
+          message: pigeonVar_replyList[1] as String?,
+          details: pigeonVar_replyList[2],
+        );
+      } else {
+        return;
+      }
+    }();
+  }
+
+  /// Initializes an instance of a IMACompanionAdSlot with design ad width and
+  /// height.
+  ///
+  /// `width` and `height` are in pixels.
+  IMACompanionAdSlot.size({
+    super.pigeon_binaryMessenger,
+    super.pigeon_instanceManager,
+    required this.view,
+    required int width,
+    required int height,
+  }) {
+    final int pigeonVar_instanceIdentifier =
+        pigeon_instanceManager.addDartCreatedInstance(this);
+    final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec =
+        _pigeonVar_codecIMACompanionAdSlot;
+    final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger;
+    () async {
+      const String pigeonVar_channelName =
+          'dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.size';
+      final BasicMessageChannel pigeonVar_channel =
+          BasicMessageChannel(
+        pigeonVar_channelName,
+        pigeonChannelCodec,
+        binaryMessenger: pigeonVar_binaryMessenger,
+      );
+      final List? pigeonVar_replyList = await pigeonVar_channel.send(
+              [pigeonVar_instanceIdentifier, view, width, height])
+          as List?;
+      if (pigeonVar_replyList == null) {
+        throw _createConnectionError(pigeonVar_channelName);
+      } else if (pigeonVar_replyList.length > 1) {
+        throw PlatformException(
+          code: pigeonVar_replyList[0]! as String,
+          message: pigeonVar_replyList[1] as String?,
+          details: pigeonVar_replyList[2],
+        );
+      } else {
+        return;
+      }
+    }();
+  }
+
+  /// Constructs [IMACompanionAdSlot] without creating the associated native object.
+  ///
+  /// This should only be used by subclasses created by this library or to
+  /// create copies for an [PigeonInstanceManager].
+  @protected
+  IMACompanionAdSlot.pigeon_detached({
+    super.pigeon_binaryMessenger,
+    super.pigeon_instanceManager,
+    required this.view,
+  });
+
+  late final _PigeonInternalProxyApiBaseCodec
+      _pigeonVar_codecIMACompanionAdSlot =
+      _PigeonInternalProxyApiBaseCodec(pigeon_instanceManager);
+
+  /// The view the companion will be rendered in.
+  ///
+  /// Display this view in your application before video ad starts.
+  final UIView view;
+
+  static void pigeon_setUpMessageHandlers({
+    bool pigeon_clearHandlers = false,
+    BinaryMessenger? pigeon_binaryMessenger,
+    PigeonInstanceManager? pigeon_instanceManager,
+    IMACompanionAdSlot Function(UIView view)? pigeon_newInstance,
+  }) {
+    final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec =
+        _PigeonInternalProxyApiBaseCodec(
+            pigeon_instanceManager ?? PigeonInstanceManager.instance);
+    final BinaryMessenger? binaryMessenger = pigeon_binaryMessenger;
+    {
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
+              Object?>(
+          'dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.pigeon_newInstance',
+          pigeonChannelCodec,
+          binaryMessenger: binaryMessenger);
+      if (pigeon_clearHandlers) {
+        pigeonVar_channel.setMessageHandler(null);
+      } else {
+        pigeonVar_channel.setMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.pigeon_newInstance was null.');
+          final List args = (message as List?)!;
+          final int? arg_pigeon_instanceIdentifier = (args[0] as int?);
+          assert(arg_pigeon_instanceIdentifier != null,
+              'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.pigeon_newInstance was null, expected non-null int.');
+          final UIView? arg_view = (args[1] as UIView?);
+          assert(arg_view != null,
+              'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.pigeon_newInstance was null, expected non-null UIView.');
+          try {
+            (pigeon_instanceManager ?? PigeonInstanceManager.instance)
+                .addHostCreatedInstance(
+              pigeon_newInstance?.call(arg_view!) ??
+                  IMACompanionAdSlot.pigeon_detached(
+                    pigeon_binaryMessenger: pigeon_binaryMessenger,
+                    pigeon_instanceManager: pigeon_instanceManager,
+                    view: arg_view!,
+                  ),
+              arg_pigeon_instanceIdentifier!,
+            );
+            return wrapResponse(empty: true);
+          } on PlatformException catch (e) {
+            return wrapResponse(error: e);
+          } catch (e) {
+            return wrapResponse(
+                error: PlatformException(code: 'error', message: e.toString()));
+          }
+        });
+      }
+    }
+  }
+
+  /// The IMACompanionDelegate for receiving events from the companion ad slot.
+  ///
+  /// This instance only creates a weak reference to the delegate, so the Dart
+  /// instance should create an explicit reference to receive callbacks.
+  Future setDelegate(IMACompanionDelegate? delegate) async {
+    final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec =
+        _pigeonVar_codecIMACompanionAdSlot;
+    final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger;
+    const String pigeonVar_channelName =
+        'dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.setDelegate';
+    final BasicMessageChannel pigeonVar_channel =
+        BasicMessageChannel(
+      pigeonVar_channelName,
+      pigeonChannelCodec,
+      binaryMessenger: pigeonVar_binaryMessenger,
+    );
+    final List? pigeonVar_replyList = await pigeonVar_channel
+        .send([this, delegate]) as List?;
+    if (pigeonVar_replyList == null) {
+      throw _createConnectionError(pigeonVar_channelName);
+    } else if (pigeonVar_replyList.length > 1) {
+      throw PlatformException(
+        code: pigeonVar_replyList[0]! as String,
+        message: pigeonVar_replyList[1] as String?,
+        details: pigeonVar_replyList[2],
+      );
+    } else {
+      return;
+    }
+  }
+
+  @override
+  IMACompanionAdSlot pigeon_copy() {
+    return IMACompanionAdSlot.pigeon_detached(
+      pigeon_binaryMessenger: pigeon_binaryMessenger,
+      pigeon_instanceManager: pigeon_instanceManager,
+      view: view,
+    );
+  }
+}
+
+/// Delegate to receive events from the companion ad slot.
+///
+/// See https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side/reference/Protocols/IMACompanionDelegate.html.
+class IMACompanionDelegate extends NSObject {
+  IMACompanionDelegate({
+    super.pigeon_binaryMessenger,
+    super.pigeon_instanceManager,
+    this.companionAdSlotFilled,
+    this.companionSlotWasClicked,
+  }) : super.pigeon_detached() {
+    final int pigeonVar_instanceIdentifier =
+        pigeon_instanceManager.addDartCreatedInstance(this);
+    final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec =
+        _pigeonVar_codecIMACompanionDelegate;
+    final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger;
+    () async {
+      const String pigeonVar_channelName =
+          'dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.pigeon_defaultConstructor';
+      final BasicMessageChannel pigeonVar_channel =
+          BasicMessageChannel(
+        pigeonVar_channelName,
+        pigeonChannelCodec,
+        binaryMessenger: pigeonVar_binaryMessenger,
+      );
+      final List? pigeonVar_replyList = await pigeonVar_channel
+          .send([pigeonVar_instanceIdentifier]) as List?;
+      if (pigeonVar_replyList == null) {
+        throw _createConnectionError(pigeonVar_channelName);
+      } else if (pigeonVar_replyList.length > 1) {
+        throw PlatformException(
+          code: pigeonVar_replyList[0]! as String,
+          message: pigeonVar_replyList[1] as String?,
+          details: pigeonVar_replyList[2],
+        );
+      } else {
+        return;
+      }
+    }();
+  }
+
+  /// Constructs [IMACompanionDelegate] without creating the associated native object.
+  ///
+  /// This should only be used by subclasses created by this library or to
+  /// create copies for an [PigeonInstanceManager].
+  @protected
+  IMACompanionDelegate.pigeon_detached({
+    super.pigeon_binaryMessenger,
+    super.pigeon_instanceManager,
+    this.companionAdSlotFilled,
+    this.companionSlotWasClicked,
+  }) : super.pigeon_detached();
+
+  late final _PigeonInternalProxyApiBaseCodec
+      _pigeonVar_codecIMACompanionDelegate =
+      _PigeonInternalProxyApiBaseCodec(pigeon_instanceManager);
+
+  /// Called when the slot is either filled or not filled.
+  ///
+  /// For the associated Native object to be automatically garbage collected,
+  /// it is required that the implementation of this `Function` doesn't have a
+  /// strong reference to the encapsulating class instance. When this `Function`
+  /// references a non-local variable, it is strongly recommended to access it
+  /// with a `WeakReference`:
+  ///
+  /// ```dart
+  /// final WeakReference weakMyVariable = WeakReference(myVariable);
+  /// final IMACompanionDelegate instance = IMACompanionDelegate(
+  ///  companionAdSlotFilled: (IMACompanionDelegate pigeon_instance, ...) {
+  ///    print(weakMyVariable?.target);
+  ///  },
+  /// );
+  /// ```
+  ///
+  /// Alternatively, [PigeonInstanceManager.removeWeakReference] can be used to
+  /// release the associated Native object manually.
+  final void Function(
+    IMACompanionDelegate pigeon_instance,
+    IMACompanionAdSlot slot,
+    bool filled,
+  )? companionAdSlotFilled;
+
+  /// Called when the slot is clicked on by the user and will successfully
+  /// navigate away.
+  ///
+  /// For the associated Native object to be automatically garbage collected,
+  /// it is required that the implementation of this `Function` doesn't have a
+  /// strong reference to the encapsulating class instance. When this `Function`
+  /// references a non-local variable, it is strongly recommended to access it
+  /// with a `WeakReference`:
+  ///
+  /// ```dart
+  /// final WeakReference weakMyVariable = WeakReference(myVariable);
+  /// final IMACompanionDelegate instance = IMACompanionDelegate(
+  ///  companionSlotWasClicked: (IMACompanionDelegate pigeon_instance, ...) {
+  ///    print(weakMyVariable?.target);
+  ///  },
+  /// );
+  /// ```
+  ///
+  /// Alternatively, [PigeonInstanceManager.removeWeakReference] can be used to
+  /// release the associated Native object manually.
+  final void Function(
+    IMACompanionDelegate pigeon_instance,
+    IMACompanionAdSlot slot,
+  )? companionSlotWasClicked;
+
+  static void pigeon_setUpMessageHandlers({
+    bool pigeon_clearHandlers = false,
+    BinaryMessenger? pigeon_binaryMessenger,
+    PigeonInstanceManager? pigeon_instanceManager,
+    IMACompanionDelegate Function()? pigeon_newInstance,
+    void Function(
+      IMACompanionDelegate pigeon_instance,
+      IMACompanionAdSlot slot,
+      bool filled,
+    )? companionAdSlotFilled,
+    void Function(
+      IMACompanionDelegate pigeon_instance,
+      IMACompanionAdSlot slot,
+    )? companionSlotWasClicked,
+  }) {
+    final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec =
+        _PigeonInternalProxyApiBaseCodec(
+            pigeon_instanceManager ?? PigeonInstanceManager.instance);
+    final BinaryMessenger? binaryMessenger = pigeon_binaryMessenger;
+    {
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
+              Object?>(
+          'dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.pigeon_newInstance',
+          pigeonChannelCodec,
+          binaryMessenger: binaryMessenger);
+      if (pigeon_clearHandlers) {
+        pigeonVar_channel.setMessageHandler(null);
+      } else {
+        pigeonVar_channel.setMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.pigeon_newInstance was null.');
+          final List args = (message as List?)!;
+          final int? arg_pigeon_instanceIdentifier = (args[0] as int?);
+          assert(arg_pigeon_instanceIdentifier != null,
+              'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.pigeon_newInstance was null, expected non-null int.');
+          try {
+            (pigeon_instanceManager ?? PigeonInstanceManager.instance)
+                .addHostCreatedInstance(
+              pigeon_newInstance?.call() ??
+                  IMACompanionDelegate.pigeon_detached(
+                    pigeon_binaryMessenger: pigeon_binaryMessenger,
+                    pigeon_instanceManager: pigeon_instanceManager,
+                  ),
+              arg_pigeon_instanceIdentifier!,
+            );
+            return wrapResponse(empty: true);
+          } on PlatformException catch (e) {
+            return wrapResponse(error: e);
+          } catch (e) {
+            return wrapResponse(
+                error: PlatformException(code: 'error', message: e.toString()));
+          }
+        });
+      }
+    }
+
+    {
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
+              Object?>(
+          'dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionAdSlotFilled',
+          pigeonChannelCodec,
+          binaryMessenger: binaryMessenger);
+      if (pigeon_clearHandlers) {
+        pigeonVar_channel.setMessageHandler(null);
+      } else {
+        pigeonVar_channel.setMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionAdSlotFilled was null.');
+          final List args = (message as List?)!;
+          final IMACompanionDelegate? arg_pigeon_instance =
+              (args[0] as IMACompanionDelegate?);
+          assert(arg_pigeon_instance != null,
+              'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionAdSlotFilled was null, expected non-null IMACompanionDelegate.');
+          final IMACompanionAdSlot? arg_slot = (args[1] as IMACompanionAdSlot?);
+          assert(arg_slot != null,
+              'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionAdSlotFilled was null, expected non-null IMACompanionAdSlot.');
+          final bool? arg_filled = (args[2] as bool?);
+          assert(arg_filled != null,
+              'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionAdSlotFilled was null, expected non-null bool.');
+          try {
+            (companionAdSlotFilled ??
+                    arg_pigeon_instance!.companionAdSlotFilled)
+                ?.call(arg_pigeon_instance!, arg_slot!, arg_filled!);
+            return wrapResponse(empty: true);
+          } on PlatformException catch (e) {
+            return wrapResponse(error: e);
+          } catch (e) {
+            return wrapResponse(
+                error: PlatformException(code: 'error', message: e.toString()));
+          }
+        });
+      }
+    }
+
+    {
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
+              Object?>(
+          'dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionSlotWasClicked',
+          pigeonChannelCodec,
+          binaryMessenger: binaryMessenger);
+      if (pigeon_clearHandlers) {
+        pigeonVar_channel.setMessageHandler(null);
+      } else {
+        pigeonVar_channel.setMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionSlotWasClicked was null.');
+          final List args = (message as List?)!;
+          final IMACompanionDelegate? arg_pigeon_instance =
+              (args[0] as IMACompanionDelegate?);
+          assert(arg_pigeon_instance != null,
+              'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionSlotWasClicked was null, expected non-null IMACompanionDelegate.');
+          final IMACompanionAdSlot? arg_slot = (args[1] as IMACompanionAdSlot?);
+          assert(arg_slot != null,
+              'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionSlotWasClicked was null, expected non-null IMACompanionAdSlot.');
+          try {
+            (companionSlotWasClicked ??
+                    arg_pigeon_instance!.companionSlotWasClicked)
+                ?.call(arg_pigeon_instance!, arg_slot!);
+            return wrapResponse(empty: true);
+          } on PlatformException catch (e) {
+            return wrapResponse(error: e);
+          } catch (e) {
+            return wrapResponse(
+                error: PlatformException(code: 'error', message: e.toString()));
+          }
+        });
+      }
+    }
+  }
+
+  @override
+  IMACompanionDelegate pigeon_copy() {
+    return IMACompanionDelegate.pigeon_detached(
+      pigeon_binaryMessenger: pigeon_binaryMessenger,
+      pigeon_instanceManager: pigeon_instanceManager,
+      companionAdSlotFilled: companionAdSlotFilled,
+      companionSlotWasClicked: companionSlotWasClicked,
+    );
+  }
+}
diff --git a/packages/interactive_media_ads/lib/src/ios/interactive_media_ads_proxy.dart b/packages/interactive_media_ads/lib/src/ios/interactive_media_ads_proxy.dart
index 664578c3f682..53b472f4fb62 100644
--- a/packages/interactive_media_ads/lib/src/ios/interactive_media_ads_proxy.dart
+++ b/packages/interactive_media_ads/lib/src/ios/interactive_media_ads_proxy.dart
@@ -22,6 +22,9 @@ class InteractiveMediaAdsProxy {
     this.newIMAAdsManagerDelegate = IMAAdsManagerDelegate.new,
     this.newIMAAdsRenderingSettings = IMAAdsRenderingSettings.new,
     this.newIMAFriendlyObstruction = IMAFriendlyObstruction.new,
+    this.newIMACompanionAdSlot = IMACompanionAdSlot.new,
+    this.sizeIMACompanionAdSlot = IMACompanionAdSlot.size,
+    this.newIMACompanionDelegate = IMACompanionDelegate.new,
   });
 
   /// Constructs [IMAAdDisplayContainer].
@@ -80,4 +83,18 @@ class InteractiveMediaAdsProxy {
     required FriendlyObstructionPurpose purpose,
     String? detailedReason,
   }) newIMAFriendlyObstruction;
+
+  /// Constructs [IMACompanionAdSlot].
+  final IMACompanionAdSlot Function({required UIView view})
+      newIMACompanionAdSlot;
+
+  /// Constructs [IMACompanionAdSlot].
+  final IMACompanionAdSlot Function({
+    required int width,
+    required int height,
+    required UIView view,
+  }) sizeIMACompanionAdSlot;
+
+  /// Constructs [IMACompanionDelegate].
+  final IMACompanionDelegate Function() newIMACompanionDelegate;
 }
diff --git a/packages/interactive_media_ads/pigeons/interactive_media_ads_ios.dart b/packages/interactive_media_ads/pigeons/interactive_media_ads_ios.dart
index ff34c8ed01b8..da64692f8456 100644
--- a/packages/interactive_media_ads/pigeons/interactive_media_ads_ios.dart
+++ b/packages/interactive_media_ads/pigeons/interactive_media_ads_ios.dart
@@ -608,3 +608,47 @@ abstract class IMACompanionAd extends NSObject {
   /// 0 if unavailable.
   late final int height;
 }
+
+/// Ad slot for companion ads.
+///
+/// See https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side/reference/Classes/IMACompanionAdSlot.
+@ProxyApi()
+abstract class IMACompanionAdSlot {
+  /// Initializes an instance of a IMACompanionAdSlot with fluid size.
+  IMACompanionAdSlot();
+
+  /// Initializes an instance of a IMACompanionAdSlot with design ad width and
+  /// height.
+  ///
+  /// `width` and `height` are in pixels.
+  IMACompanionAdSlot.size(int width, int height);
+
+  /// The view the companion will be rendered in.
+  ///
+  /// Display this view in your application before video ad starts.
+  late final UIView view;
+
+  /// The IMACompanionDelegate for receiving events from the companion ad slot.
+  ///
+  /// This instance only creates a weak reference to the delegate, so the Dart
+  /// instance should create an explicit reference to receive callbacks.
+  void setDelegate(IMACompanionDelegate? delegate);
+}
+
+/// Delegate to receive events from the companion ad slot.
+///
+/// See https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side/reference/Protocols/IMACompanionDelegate.html.
+@ProxyApi()
+abstract class IMACompanionDelegate extends NSObject {
+  IMACompanionDelegate();
+
+  /// Called when the slot is either filled or not filled.
+  late void Function(
+    IMACompanionAdSlot slot,
+    bool filled,
+  )? companionAdSlotFilled;
+
+  /// Called when the slot is clicked on by the user and will successfully
+  /// navigate away.
+  late void Function(IMACompanionAdSlot slot)? companionSlotWasClicked;
+}
diff --git a/packages/interactive_media_ads/pubspec.yaml b/packages/interactive_media_ads/pubspec.yaml
index d3101f0322d7..7f8c020004be 100644
--- a/packages/interactive_media_ads/pubspec.yaml
+++ b/packages/interactive_media_ads/pubspec.yaml
@@ -2,7 +2,7 @@ name: interactive_media_ads
 description: A Flutter plugin for using the Interactive Media Ads SDKs on Android and iOS.
 repository: https://github.com/flutter/packages/tree/main/packages/interactive_media_ads
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+interactive_media_ads%22
-version: 0.2.2+13 # This must match the version in
+version: 0.2.2+14 # This must match the version in
   # `android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt` and
   # `ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift`
 
diff --git a/packages/local_auth/local_auth/example/android/app/build.gradle b/packages/local_auth/local_auth/example/android/app/build.gradle
index f075d5813cf9..c564af855289 100644
--- a/packages/local_auth/local_auth/example/android/app/build.gradle
+++ b/packages/local_auth/local_auth/example/android/app/build.gradle
@@ -36,7 +36,6 @@ android {
         versionCode flutterVersionCode.toInteger()
         versionName flutterVersionName
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
-        multiDexEnabled true
     }
 
     buildTypes {
diff --git a/packages/local_auth/local_auth_android/example/android/app/build.gradle b/packages/local_auth/local_auth_android/example/android/app/build.gradle
index 2da8796f938e..7db5363be38d 100644
--- a/packages/local_auth/local_auth_android/example/android/app/build.gradle
+++ b/packages/local_auth/local_auth_android/example/android/app/build.gradle
@@ -36,7 +36,6 @@ android {
         versionCode flutterVersionCode.toInteger()
         versionName flutterVersionName
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
-        multiDexEnabled true
     }
 
     buildTypes {
diff --git a/packages/palette_generator/CHANGELOG.md b/packages/palette_generator/CHANGELOG.md
index fccfa3851c40..73b2ee0f5a47 100644
--- a/packages/palette_generator/CHANGELOG.md
+++ b/packages/palette_generator/CHANGELOG.md
@@ -1,5 +1,6 @@
-## NEXT
+## 0.3.3+5
 
+* Updates README to link to the published example.
 * Updates minimum supported SDK version to Flutter 3.19/Dart 3.3.
 
 ## 0.3.3+4
diff --git a/packages/palette_generator/README.md b/packages/palette_generator/README.md
index 9dbfd45e9b53..4cf11c0486f6 100644
--- a/packages/palette_generator/README.md
+++ b/packages/palette_generator/README.md
@@ -7,11 +7,5 @@ find colors for a user interface.
 
 ## Example
 
-Import the library via
-
-```dart
-import 'package:palette_generator/palette_generator.dart';
-```
-
-Then use the `PaletteGenerator` Dart class in your code. To see how this is done,
-check out the [image_colors example app](example/).
+To see how to use the `PaletteGenerator` class in your code, see
+[the example app](https://pub.dev/packages/palette_generator/example).
diff --git a/packages/palette_generator/pubspec.yaml b/packages/palette_generator/pubspec.yaml
index f5159a4f3877..ed67a31c72c9 100644
--- a/packages/palette_generator/pubspec.yaml
+++ b/packages/palette_generator/pubspec.yaml
@@ -2,7 +2,7 @@ name: palette_generator
 description: Flutter package for generating palette colors from a source image.
 repository: https://github.com/flutter/packages/tree/main/packages/palette_generator
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+palette_generator%22
-version: 0.3.3+4
+version: 0.3.3+5
 
 environment:
   sdk: ^3.3.0
diff --git a/packages/path_provider/path_provider/CHANGELOG.md b/packages/path_provider/path_provider/CHANGELOG.md
index 78b39cf0f36e..6a8b2aeacd09 100644
--- a/packages/path_provider/path_provider/CHANGELOG.md
+++ b/packages/path_provider/path_provider/CHANGELOG.md
@@ -1,6 +1,7 @@
-## NEXT
+## 2.1.5
 
 * Updates minimum supported SDK version to Flutter 3.19/Dart 3.3.
+* Updates minimum required `path_provider_android` to [2.2.5](https://pub.dev/packages/path_provider_android/changelog#225) as the v1 Android embedder is no longer available.
 
 ## 2.1.4
 
diff --git a/packages/path_provider/path_provider/pubspec.yaml b/packages/path_provider/path_provider/pubspec.yaml
index 616da9bd98a1..c972341e43bb 100644
--- a/packages/path_provider/path_provider/pubspec.yaml
+++ b/packages/path_provider/path_provider/pubspec.yaml
@@ -2,11 +2,11 @@ name: path_provider
 description: Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories.
 repository: https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_provider%22
-version: 2.1.4
+version: 2.1.5
 
 environment:
-  sdk: ^3.3.0
-  flutter: ">=3.19.0"
+  sdk: ^3.4.0
+  flutter: ">=3.22.0"
 
 flutter:
   plugin:
@@ -25,7 +25,7 @@ flutter:
 dependencies:
   flutter:
     sdk: flutter
-  path_provider_android: ^2.2.0
+  path_provider_android: ^2.2.5
   path_provider_foundation: ^2.3.2
   path_provider_linux: ^2.2.0
   path_provider_platform_interface: ^2.1.0
diff --git a/packages/path_provider/path_provider_android/CHANGELOG.md b/packages/path_provider/path_provider_android/CHANGELOG.md
index 9b2e75648d2f..352bad5b6cb7 100644
--- a/packages/path_provider/path_provider_android/CHANGELOG.md
+++ b/packages/path_provider/path_provider_android/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 2.2.13
+
+* Updates annotations lib to 1.9.0.
+
 ## 2.2.12
 
 * Updates Pigeon for non-nullable collection type support.
diff --git a/packages/path_provider/path_provider_android/android/build.gradle b/packages/path_provider/path_provider_android/android/build.gradle
index b21cad02e4cd..69a189f90d45 100644
--- a/packages/path_provider/path_provider_android/android/build.gradle
+++ b/packages/path_provider/path_provider_android/android/build.gradle
@@ -54,6 +54,6 @@ android {
 }
 
 dependencies {
-    implementation 'androidx.annotation:annotation:1.8.2'
+    implementation 'androidx.annotation:annotation:1.9.0'
     testImplementation 'junit:junit:4.13.2'
 }
diff --git a/packages/path_provider/path_provider_android/pubspec.yaml b/packages/path_provider/path_provider_android/pubspec.yaml
index fd8ffced5f6d..d46959f9cd75 100644
--- a/packages/path_provider/path_provider_android/pubspec.yaml
+++ b/packages/path_provider/path_provider_android/pubspec.yaml
@@ -2,7 +2,7 @@ name: path_provider_android
 description: Android implementation of the path_provider plugin.
 repository: https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_android
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_provider%22
-version: 2.2.12
+version: 2.2.13
 
 environment:
   sdk: ^3.5.0
diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md
index dea1af969017..85842f046117 100644
--- a/packages/pigeon/CHANGELOG.md
+++ b/packages/pigeon/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 22.6.0
+
+* [swift] Adds `includeErrorClass` to `SwiftOptions`.
+
 ## 22.5.0
 
 * [swift] Adds implementation for `@ProxyApi`.
diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart
index 37bce3f64029..cbec3e8da6fc 100644
--- a/packages/pigeon/lib/generator_tools.dart
+++ b/packages/pigeon/lib/generator_tools.dart
@@ -14,7 +14,7 @@ import 'ast.dart';
 /// The current version of pigeon.
 ///
 /// This must match the version in pubspec.yaml.
-const String pigeonVersion = '22.5.0';
+const String pigeonVersion = '22.6.0';
 
 /// Read all the content from [stdin] to a String.
 String readStdin() {
diff --git a/packages/pigeon/lib/pigeon_lib.dart b/packages/pigeon/lib/pigeon_lib.dart
index 8b8a0506877b..075049d98298 100644
--- a/packages/pigeon/lib/pigeon_lib.dart
+++ b/packages/pigeon/lib/pigeon_lib.dart
@@ -745,6 +745,7 @@ class SwiftGeneratorAdapter implements GeneratorAdapter {
               path.posix.join(options.basePath ?? '', options.copyrightHeader))
           : null,
       errorClassName: swiftOptions.errorClassName,
+      includeErrorClass: swiftOptions.includeErrorClass,
     ));
     const SwiftGenerator generator = SwiftGenerator();
     generator.generate(
diff --git a/packages/pigeon/lib/swift_generator.dart b/packages/pigeon/lib/swift_generator.dart
index bda343b8b6ce..289c50dbd887 100644
--- a/packages/pigeon/lib/swift_generator.dart
+++ b/packages/pigeon/lib/swift_generator.dart
@@ -28,6 +28,7 @@ class SwiftOptions {
     this.copyrightHeader,
     this.fileSpecificClassNameComponent,
     this.errorClassName,
+    this.includeErrorClass = true,
   });
 
   /// A copyright header that will get prepended to generated code.
@@ -39,6 +40,12 @@ class SwiftOptions {
   /// The name of the error class used for passing custom error parameters.
   final String? errorClassName;
 
+  /// Whether to include the error class in generation.
+  ///
+  /// This should only ever be set to false if you have another generated
+  /// Swift file in the same directory.
+  final bool includeErrorClass;
+
   /// Creates a [SwiftOptions] from a Map representation where:
   /// `x = SwiftOptions.fromList(x.toMap())`.
   static SwiftOptions fromList(Map map) {
@@ -47,6 +54,7 @@ class SwiftOptions {
       fileSpecificClassNameComponent:
           map['fileSpecificClassNameComponent'] as String?,
       errorClassName: map['errorClassName'] as String?,
+      includeErrorClass: map['includeErrorClass'] as bool? ?? true,
     );
   }
 
@@ -58,6 +66,7 @@ class SwiftOptions {
       if (fileSpecificClassNameComponent != null)
         'fileSpecificClassNameComponent': fileSpecificClassNameComponent!,
       if (errorClassName != null) 'errorClassName': errorClassName!,
+      'includeErrorClass': includeErrorClass,
     };
     return result;
   }
@@ -1303,7 +1312,9 @@ private func nilOrValue(_ value: Any?) -> T? {
         .any((Api api) => api.methods.isNotEmpty);
     final bool hasProxyApi = root.apis.any((Api api) => api is AstProxyApi);
 
-    _writePigeonError(generatorOptions, indent);
+    if (generatorOptions.includeErrorClass) {
+      _writePigeonError(generatorOptions, indent);
+    }
 
     if (hasHostApi || hasProxyApi) {
       _writeWrapResult(indent);
diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml
index df2a2009fecb..cddaae515813 100644
--- a/packages/pigeon/pubspec.yaml
+++ b/packages/pigeon/pubspec.yaml
@@ -2,7 +2,7 @@ name: pigeon
 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%3A%22p%3A+pigeon%22
-version: 22.5.0 # This must match the version in lib/generator_tools.dart
+version: 22.6.0 # This must match the version in lib/generator_tools.dart
 
 environment:
   sdk: ^3.3.0
diff --git a/packages/pigeon/tool/shared/generation.dart b/packages/pigeon/tool/shared/generation.dart
index 695789fb6261..4cee0d4de568 100644
--- a/packages/pigeon/tool/shared/generation.dart
+++ b/packages/pigeon/tool/shared/generation.dart
@@ -91,7 +91,8 @@ Future generateTestPigeons(
         ? 'FlutterError'
         : '${pascalCaseName}Error';
 
-    final bool swiftErrorUseDefaultErrorName = input == 'core_tests';
+    final bool swiftErrorUseDefaultErrorName =
+        input == 'core_tests' || input == 'background_platform_channels';
 
     final String? swiftErrorClassName =
         swiftErrorUseDefaultErrorName ? null : '${pascalCaseName}Error';
@@ -117,6 +118,7 @@ Future generateTestPigeons(
           ? null
           : '$outputBase/ios/Classes/$pascalCaseName.gen.swift',
       swiftErrorClassName: swiftErrorClassName,
+      swiftIncludeErrorClass: input != 'core_tests',
       // Linux
       gobjectHeaderOut: skipLanguages.contains(GeneratorLanguage.gobject)
           ? null
@@ -148,6 +150,7 @@ Future generateTestPigeons(
           ? null
           : '$outputBase/macos/Classes/$pascalCaseName.gen.swift',
       swiftErrorClassName: swiftErrorClassName,
+      swiftIncludeErrorClass: input != 'core_tests',
       suppressVersion: true,
       dartPackageName: 'pigeon_integration_tests',
       injectOverflowTypes: includeOverflow && input == 'core_tests',
@@ -212,6 +215,7 @@ Future runPigeon({
   String? kotlinPackage,
   String? kotlinErrorClassName,
   bool kotlinIncludeErrorClass = true,
+  bool swiftIncludeErrorClass = true,
   String? swiftOut,
   String? swiftErrorClassName,
   String? cppHeaderOut,
@@ -272,6 +276,7 @@ Future runPigeon({
       swiftOut: swiftOut,
       swiftOptions: SwiftOptions(
         errorClassName: swiftErrorClassName,
+        includeErrorClass: swiftIncludeErrorClass,
       ),
       basePath: basePath,
       dartPackageName: dartPackageName,
diff --git a/packages/url_launcher/url_launcher_android/CHANGELOG.md b/packages/url_launcher/url_launcher_android/CHANGELOG.md
index 3ab3f0e892e4..6438d626505e 100644
--- a/packages/url_launcher/url_launcher_android/CHANGELOG.md
+++ b/packages/url_launcher/url_launcher_android/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 6.3.13
+
+* Bumps androidx.annotation:annotation from 1.8.2 to 1.9.0.
+
 ## 6.3.12
 
 * Updates Java compatibility version to 11.
diff --git a/packages/url_launcher/url_launcher_android/android/build.gradle b/packages/url_launcher/url_launcher_android/android/build.gradle
index c874093d4487..3e6f706b2560 100644
--- a/packages/url_launcher/url_launcher_android/android/build.gradle
+++ b/packages/url_launcher/url_launcher_android/android/build.gradle
@@ -62,7 +62,7 @@ dependencies {
 
     // Java language implementation
     implementation "androidx.core:core:1.13.1"
-    implementation 'androidx.annotation:annotation:1.8.2'
+    implementation 'androidx.annotation:annotation:1.9.0'
     implementation 'androidx.browser:browser:1.8.0'
     testImplementation 'junit:junit:4.13.2'
     testImplementation 'org.mockito:mockito-core:5.1.1'
diff --git a/packages/url_launcher/url_launcher_android/pubspec.yaml b/packages/url_launcher/url_launcher_android/pubspec.yaml
index 7313168e669c..6603730ecf1e 100644
--- a/packages/url_launcher/url_launcher_android/pubspec.yaml
+++ b/packages/url_launcher/url_launcher_android/pubspec.yaml
@@ -2,7 +2,7 @@ name: url_launcher_android
 description: Android implementation of the url_launcher plugin.
 repository: https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_android
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+url_launcher%22
-version: 6.3.12
+version: 6.3.13
 environment:
   sdk: ^3.5.0
   flutter: ">=3.24.0"
diff --git a/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart b/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart
index 1a33f3aea7c6..b3de107d4368 100644
--- a/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart
+++ b/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart
@@ -86,7 +86,6 @@ class UrlLauncherPlugin extends UrlLauncherPlatform {
     final String target = webOnlyWindowName ??
         ((_isSafari && _isSafariTargetTopScheme(scheme)) ? '_top' : '');
 
-    // ignore: unsafe_html
     _window.open(url, target, 'noopener,noreferrer');
 
     return true;
diff --git a/packages/video_player/video_player_android/CHANGELOG.md b/packages/video_player/video_player_android/CHANGELOG.md
index 5b0edb5398bc..ef0db8cc5913 100644
--- a/packages/video_player/video_player_android/CHANGELOG.md
+++ b/packages/video_player/video_player_android/CHANGELOG.md
@@ -1,7 +1,20 @@
+## 2.7.16
+
+* Updates internal Pigeon API to use newer features.
+
+## 2.7.15
+
+* Changes the rotation correction calculation for Android API 29+ to use
+  the one that is reported by the video's format instead of the unapplied
+  rotation degrees that Exoplayer does not report on Android API 21+.
+* Changes the rotation correction calculation for Android APIs 21-28 to 0
+  because the Impeller backend used on those API versions correctly rotates
+  the video being played automatically.
+
 ## 2.7.14
 
 * Removes SSL workaround for API 19, which is no longer supported.
-* 
+
 ## 2.7.13
 
 * When `AndroidVideoPlayer` attempts to operate on a `textureId` that is not
diff --git a/packages/video_player/video_player_android/android/build.gradle b/packages/video_player/video_player_android/android/build.gradle
index b8ceea25cd70..92decbdda718 100644
--- a/packages/video_player/video_player_android/android/build.gradle
+++ b/packages/video_player/video_player_android/android/build.gradle
@@ -57,6 +57,11 @@ android {
         unitTests.includeAndroidResources = true
         unitTests.returnDefaultValues = true
         unitTests.all {
+            // The org.gradle.jvmargs property that may be set in gradle.properties does not impact
+            // the Java heap size when running the Android unit tests. The following property here
+            // sets the heap size to a size large enough to run the robolectric tests across
+            // multiple SDK levels.
+            jvmArgs "-Xmx1g"
             testLogging {
                events "passed", "skipped", "failed", "standardOut", "standardError"
                outputs.upToDateWhen {false}
diff --git a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/ExoPlayerEventListener.java b/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/ExoPlayerEventListener.java
index c8f2816571de..df6115fd5846 100644
--- a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/ExoPlayerEventListener.java
+++ b/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/ExoPlayerEventListener.java
@@ -4,11 +4,15 @@
 
 package io.flutter.plugins.videoplayer;
 
+import android.os.Build;
 import androidx.annotation.NonNull;
+import androidx.annotation.OptIn;
+import androidx.media3.common.Format;
 import androidx.media3.common.PlaybackException;
 import androidx.media3.common.Player;
 import androidx.media3.common.VideoSize;
 import androidx.media3.exoplayer.ExoPlayer;
+import java.util.Objects;
 
 final class ExoPlayerEventListener implements Player.Listener {
   private final ExoPlayer exoPlayer;
@@ -16,6 +20,32 @@ final class ExoPlayerEventListener implements Player.Listener {
   private boolean isBuffering = false;
   private boolean isInitialized;
 
+  private enum RotationDegrees {
+    ROTATE_0(0),
+    ROTATE_90(90),
+    ROTATE_180(180),
+    ROTATE_270(270);
+
+    private final int degrees;
+
+    RotationDegrees(int degrees) {
+      this.degrees = degrees;
+    }
+
+    public static RotationDegrees fromDegrees(int degrees) {
+      for (RotationDegrees rotationDegrees : RotationDegrees.values()) {
+        if (rotationDegrees.degrees == degrees) {
+          return rotationDegrees;
+        }
+      }
+      throw new IllegalArgumentException("Invalid rotation degrees specified: " + degrees);
+    }
+
+    public int getDegrees() {
+      return this.degrees;
+    }
+  }
+
   ExoPlayerEventListener(ExoPlayer exoPlayer, VideoPlayerCallbacks events) {
     this(exoPlayer, events, false);
   }
@@ -49,23 +79,80 @@ private void sendInitialized() {
     int width = videoSize.width;
     int height = videoSize.height;
     if (width != 0 && height != 0) {
-      int rotationDegrees = videoSize.unappliedRotationDegrees;
-      // Switch the width/height if video was taken in portrait mode
-      if (rotationDegrees == 90 || rotationDegrees == 270) {
+      RotationDegrees reportedRotationCorrection = RotationDegrees.ROTATE_0;
+
+      if (Build.VERSION.SDK_INT <= 21) {
+        // On API 21 and below, Exoplayer may not internally handle rotation correction
+        // and reports it through VideoSize.unappliedRotationDegrees. We may apply it to
+        // fix the case of upside-down playback.
+        try {
+          reportedRotationCorrection =
+              RotationDegrees.fromDegrees(videoSize.unappliedRotationDegrees);
+          rotationCorrection =
+              getRotationCorrectionFromUnappliedRotation(reportedRotationCorrection);
+        } catch (IllegalArgumentException e) {
+          // Unapplied rotation other than 0, 90, 180, 270 reported by VideoSize. Because this is unexpected,
+          // we apply no rotation correction.
+          reportedRotationCorrection = RotationDegrees.ROTATE_0;
+          rotationCorrection = 0;
+        }
+      }
+      // TODO(camsim99): Replace this with a call to `handlesCropAndRotation` when it is
+      // available in stable. https://github.com/flutter/flutter/issues/157198
+      else if (Build.VERSION.SDK_INT < 29) {
+        // When the SurfaceTexture backend for Impeller is used, the preview should already
+        // be correctly rotated.
+        rotationCorrection = 0;
+      } else {
+        // The video's Format also provides a rotation correction that may be used to
+        // correct the rotation, so we try to use that to correct the video rotation
+        // when the ImageReader backend for Impeller is used.
+        rotationCorrection = getRotationCorrectionFromFormat(exoPlayer);
+
+        try {
+          reportedRotationCorrection = RotationDegrees.fromDegrees(rotationCorrection);
+        } catch (IllegalArgumentException e) {
+          // Rotation correction other than 0, 90, 180, 270 reported by Format. Because this is unexpected,
+          // we apply no rotation correction.
+          reportedRotationCorrection = RotationDegrees.ROTATE_0;
+          rotationCorrection = 0;
+        }
+      }
+
+      // Switch the width/height if video was taken in portrait mode and a rotation
+      // correction was detected.
+      if (reportedRotationCorrection == RotationDegrees.ROTATE_90
+          || reportedRotationCorrection == RotationDegrees.ROTATE_270) {
         width = videoSize.height;
         height = videoSize.width;
       }
-      // Rotating the video with ExoPlayer does not seem to be possible with a Surface,
-      // so inform the Flutter code that the widget needs to be rotated to prevent
-      // upside-down playback for videos with rotationDegrees of 180 (other orientations work
-      // correctly without correction).
-      if (rotationDegrees == 180) {
-        rotationCorrection = rotationDegrees;
-      }
     }
     events.onInitialized(width, height, exoPlayer.getDuration(), rotationCorrection);
   }
 
+  private int getRotationCorrectionFromUnappliedRotation(RotationDegrees unappliedRotationDegrees) {
+    int rotationCorrection = 0;
+
+    // Rotating the video with ExoPlayer does not seem to be possible with a Surface,
+    // so inform the Flutter code that the widget needs to be rotated to prevent
+    // upside-down playback for videos with unappliedRotationDegrees of 180 (other orientations
+    // work correctly without correction).
+    if (unappliedRotationDegrees == RotationDegrees.ROTATE_180) {
+      rotationCorrection = unappliedRotationDegrees.getDegrees();
+    }
+
+    return rotationCorrection;
+  }
+
+  @OptIn(markerClass = androidx.media3.common.util.UnstableApi.class)
+  // A video's Format and its rotation degrees are unstable because they are not guaranteed
+  // the same implementation across API versions. It is possible that this logic may need
+  // revisiting should the implementation change across versions of the Exoplayer API.
+  private int getRotationCorrectionFromFormat(ExoPlayer exoPlayer) {
+    Format videoFormat = Objects.requireNonNull(exoPlayer.getVideoFormat());
+    return videoFormat.rotationDegrees;
+  }
+
   @Override
   public void onPlaybackStateChanged(final int playbackState) {
     switch (playbackState) {
diff --git a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java b/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java
index b37b3b098f28..870045518852 100644
--- a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java
+++ b/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java
@@ -1,7 +1,7 @@
 // Copyright 2013 The Flutter Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-// Autogenerated from Pigeon (v22.4.2), do not edit directly.
+// Autogenerated from Pigeon (v22.5.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 package io.flutter.plugins.videoplayer;
@@ -65,441 +65,6 @@ protected static ArrayList wrapError(@NonNull Throwable exception) {
   @Retention(CLASS)
   @interface CanIgnoreReturnValue {}
 
-  /** Generated class from Pigeon that represents data sent in messages. */
-  public static final class TextureMessage {
-    private @NonNull Long textureId;
-
-    public @NonNull Long getTextureId() {
-      return textureId;
-    }
-
-    public void setTextureId(@NonNull Long setterArg) {
-      if (setterArg == null) {
-        throw new IllegalStateException("Nonnull field \"textureId\" is null.");
-      }
-      this.textureId = setterArg;
-    }
-
-    /** Constructor is non-public to enforce null safety; use Builder. */
-    TextureMessage() {}
-
-    @Override
-    public boolean equals(Object o) {
-      if (this == o) {
-        return true;
-      }
-      if (o == null || getClass() != o.getClass()) {
-        return false;
-      }
-      TextureMessage that = (TextureMessage) o;
-      return textureId.equals(that.textureId);
-    }
-
-    @Override
-    public int hashCode() {
-      return Objects.hash(textureId);
-    }
-
-    public static final class Builder {
-
-      private @Nullable Long textureId;
-
-      @CanIgnoreReturnValue
-      public @NonNull Builder setTextureId(@NonNull Long setterArg) {
-        this.textureId = setterArg;
-        return this;
-      }
-
-      public @NonNull TextureMessage build() {
-        TextureMessage pigeonReturn = new TextureMessage();
-        pigeonReturn.setTextureId(textureId);
-        return pigeonReturn;
-      }
-    }
-
-    @NonNull
-    ArrayList toList() {
-      ArrayList toListResult = new ArrayList<>(1);
-      toListResult.add(textureId);
-      return toListResult;
-    }
-
-    static @NonNull TextureMessage fromList(@NonNull ArrayList pigeonVar_list) {
-      TextureMessage pigeonResult = new TextureMessage();
-      Object textureId = pigeonVar_list.get(0);
-      pigeonResult.setTextureId((Long) textureId);
-      return pigeonResult;
-    }
-  }
-
-  /** Generated class from Pigeon that represents data sent in messages. */
-  public static final class LoopingMessage {
-    private @NonNull Long textureId;
-
-    public @NonNull Long getTextureId() {
-      return textureId;
-    }
-
-    public void setTextureId(@NonNull Long setterArg) {
-      if (setterArg == null) {
-        throw new IllegalStateException("Nonnull field \"textureId\" is null.");
-      }
-      this.textureId = setterArg;
-    }
-
-    private @NonNull Boolean isLooping;
-
-    public @NonNull Boolean getIsLooping() {
-      return isLooping;
-    }
-
-    public void setIsLooping(@NonNull Boolean setterArg) {
-      if (setterArg == null) {
-        throw new IllegalStateException("Nonnull field \"isLooping\" is null.");
-      }
-      this.isLooping = setterArg;
-    }
-
-    /** Constructor is non-public to enforce null safety; use Builder. */
-    LoopingMessage() {}
-
-    @Override
-    public boolean equals(Object o) {
-      if (this == o) {
-        return true;
-      }
-      if (o == null || getClass() != o.getClass()) {
-        return false;
-      }
-      LoopingMessage that = (LoopingMessage) o;
-      return textureId.equals(that.textureId) && isLooping.equals(that.isLooping);
-    }
-
-    @Override
-    public int hashCode() {
-      return Objects.hash(textureId, isLooping);
-    }
-
-    public static final class Builder {
-
-      private @Nullable Long textureId;
-
-      @CanIgnoreReturnValue
-      public @NonNull Builder setTextureId(@NonNull Long setterArg) {
-        this.textureId = setterArg;
-        return this;
-      }
-
-      private @Nullable Boolean isLooping;
-
-      @CanIgnoreReturnValue
-      public @NonNull Builder setIsLooping(@NonNull Boolean setterArg) {
-        this.isLooping = setterArg;
-        return this;
-      }
-
-      public @NonNull LoopingMessage build() {
-        LoopingMessage pigeonReturn = new LoopingMessage();
-        pigeonReturn.setTextureId(textureId);
-        pigeonReturn.setIsLooping(isLooping);
-        return pigeonReturn;
-      }
-    }
-
-    @NonNull
-    ArrayList toList() {
-      ArrayList toListResult = new ArrayList<>(2);
-      toListResult.add(textureId);
-      toListResult.add(isLooping);
-      return toListResult;
-    }
-
-    static @NonNull LoopingMessage fromList(@NonNull ArrayList pigeonVar_list) {
-      LoopingMessage pigeonResult = new LoopingMessage();
-      Object textureId = pigeonVar_list.get(0);
-      pigeonResult.setTextureId((Long) textureId);
-      Object isLooping = pigeonVar_list.get(1);
-      pigeonResult.setIsLooping((Boolean) isLooping);
-      return pigeonResult;
-    }
-  }
-
-  /** Generated class from Pigeon that represents data sent in messages. */
-  public static final class VolumeMessage {
-    private @NonNull Long textureId;
-
-    public @NonNull Long getTextureId() {
-      return textureId;
-    }
-
-    public void setTextureId(@NonNull Long setterArg) {
-      if (setterArg == null) {
-        throw new IllegalStateException("Nonnull field \"textureId\" is null.");
-      }
-      this.textureId = setterArg;
-    }
-
-    private @NonNull Double volume;
-
-    public @NonNull Double getVolume() {
-      return volume;
-    }
-
-    public void setVolume(@NonNull Double setterArg) {
-      if (setterArg == null) {
-        throw new IllegalStateException("Nonnull field \"volume\" is null.");
-      }
-      this.volume = setterArg;
-    }
-
-    /** Constructor is non-public to enforce null safety; use Builder. */
-    VolumeMessage() {}
-
-    @Override
-    public boolean equals(Object o) {
-      if (this == o) {
-        return true;
-      }
-      if (o == null || getClass() != o.getClass()) {
-        return false;
-      }
-      VolumeMessage that = (VolumeMessage) o;
-      return textureId.equals(that.textureId) && volume.equals(that.volume);
-    }
-
-    @Override
-    public int hashCode() {
-      return Objects.hash(textureId, volume);
-    }
-
-    public static final class Builder {
-
-      private @Nullable Long textureId;
-
-      @CanIgnoreReturnValue
-      public @NonNull Builder setTextureId(@NonNull Long setterArg) {
-        this.textureId = setterArg;
-        return this;
-      }
-
-      private @Nullable Double volume;
-
-      @CanIgnoreReturnValue
-      public @NonNull Builder setVolume(@NonNull Double setterArg) {
-        this.volume = setterArg;
-        return this;
-      }
-
-      public @NonNull VolumeMessage build() {
-        VolumeMessage pigeonReturn = new VolumeMessage();
-        pigeonReturn.setTextureId(textureId);
-        pigeonReturn.setVolume(volume);
-        return pigeonReturn;
-      }
-    }
-
-    @NonNull
-    ArrayList toList() {
-      ArrayList toListResult = new ArrayList<>(2);
-      toListResult.add(textureId);
-      toListResult.add(volume);
-      return toListResult;
-    }
-
-    static @NonNull VolumeMessage fromList(@NonNull ArrayList pigeonVar_list) {
-      VolumeMessage pigeonResult = new VolumeMessage();
-      Object textureId = pigeonVar_list.get(0);
-      pigeonResult.setTextureId((Long) textureId);
-      Object volume = pigeonVar_list.get(1);
-      pigeonResult.setVolume((Double) volume);
-      return pigeonResult;
-    }
-  }
-
-  /** Generated class from Pigeon that represents data sent in messages. */
-  public static final class PlaybackSpeedMessage {
-    private @NonNull Long textureId;
-
-    public @NonNull Long getTextureId() {
-      return textureId;
-    }
-
-    public void setTextureId(@NonNull Long setterArg) {
-      if (setterArg == null) {
-        throw new IllegalStateException("Nonnull field \"textureId\" is null.");
-      }
-      this.textureId = setterArg;
-    }
-
-    private @NonNull Double speed;
-
-    public @NonNull Double getSpeed() {
-      return speed;
-    }
-
-    public void setSpeed(@NonNull Double setterArg) {
-      if (setterArg == null) {
-        throw new IllegalStateException("Nonnull field \"speed\" is null.");
-      }
-      this.speed = setterArg;
-    }
-
-    /** Constructor is non-public to enforce null safety; use Builder. */
-    PlaybackSpeedMessage() {}
-
-    @Override
-    public boolean equals(Object o) {
-      if (this == o) {
-        return true;
-      }
-      if (o == null || getClass() != o.getClass()) {
-        return false;
-      }
-      PlaybackSpeedMessage that = (PlaybackSpeedMessage) o;
-      return textureId.equals(that.textureId) && speed.equals(that.speed);
-    }
-
-    @Override
-    public int hashCode() {
-      return Objects.hash(textureId, speed);
-    }
-
-    public static final class Builder {
-
-      private @Nullable Long textureId;
-
-      @CanIgnoreReturnValue
-      public @NonNull Builder setTextureId(@NonNull Long setterArg) {
-        this.textureId = setterArg;
-        return this;
-      }
-
-      private @Nullable Double speed;
-
-      @CanIgnoreReturnValue
-      public @NonNull Builder setSpeed(@NonNull Double setterArg) {
-        this.speed = setterArg;
-        return this;
-      }
-
-      public @NonNull PlaybackSpeedMessage build() {
-        PlaybackSpeedMessage pigeonReturn = new PlaybackSpeedMessage();
-        pigeonReturn.setTextureId(textureId);
-        pigeonReturn.setSpeed(speed);
-        return pigeonReturn;
-      }
-    }
-
-    @NonNull
-    ArrayList toList() {
-      ArrayList toListResult = new ArrayList<>(2);
-      toListResult.add(textureId);
-      toListResult.add(speed);
-      return toListResult;
-    }
-
-    static @NonNull PlaybackSpeedMessage fromList(@NonNull ArrayList pigeonVar_list) {
-      PlaybackSpeedMessage pigeonResult = new PlaybackSpeedMessage();
-      Object textureId = pigeonVar_list.get(0);
-      pigeonResult.setTextureId((Long) textureId);
-      Object speed = pigeonVar_list.get(1);
-      pigeonResult.setSpeed((Double) speed);
-      return pigeonResult;
-    }
-  }
-
-  /** Generated class from Pigeon that represents data sent in messages. */
-  public static final class PositionMessage {
-    private @NonNull Long textureId;
-
-    public @NonNull Long getTextureId() {
-      return textureId;
-    }
-
-    public void setTextureId(@NonNull Long setterArg) {
-      if (setterArg == null) {
-        throw new IllegalStateException("Nonnull field \"textureId\" is null.");
-      }
-      this.textureId = setterArg;
-    }
-
-    private @NonNull Long position;
-
-    public @NonNull Long getPosition() {
-      return position;
-    }
-
-    public void setPosition(@NonNull Long setterArg) {
-      if (setterArg == null) {
-        throw new IllegalStateException("Nonnull field \"position\" is null.");
-      }
-      this.position = setterArg;
-    }
-
-    /** Constructor is non-public to enforce null safety; use Builder. */
-    PositionMessage() {}
-
-    @Override
-    public boolean equals(Object o) {
-      if (this == o) {
-        return true;
-      }
-      if (o == null || getClass() != o.getClass()) {
-        return false;
-      }
-      PositionMessage that = (PositionMessage) o;
-      return textureId.equals(that.textureId) && position.equals(that.position);
-    }
-
-    @Override
-    public int hashCode() {
-      return Objects.hash(textureId, position);
-    }
-
-    public static final class Builder {
-
-      private @Nullable Long textureId;
-
-      @CanIgnoreReturnValue
-      public @NonNull Builder setTextureId(@NonNull Long setterArg) {
-        this.textureId = setterArg;
-        return this;
-      }
-
-      private @Nullable Long position;
-
-      @CanIgnoreReturnValue
-      public @NonNull Builder setPosition(@NonNull Long setterArg) {
-        this.position = setterArg;
-        return this;
-      }
-
-      public @NonNull PositionMessage build() {
-        PositionMessage pigeonReturn = new PositionMessage();
-        pigeonReturn.setTextureId(textureId);
-        pigeonReturn.setPosition(position);
-        return pigeonReturn;
-      }
-    }
-
-    @NonNull
-    ArrayList toList() {
-      ArrayList toListResult = new ArrayList<>(2);
-      toListResult.add(textureId);
-      toListResult.add(position);
-      return toListResult;
-    }
-
-    static @NonNull PositionMessage fromList(@NonNull ArrayList pigeonVar_list) {
-      PositionMessage pigeonResult = new PositionMessage();
-      Object textureId = pigeonVar_list.get(0);
-      pigeonResult.setTextureId((Long) textureId);
-      Object position = pigeonVar_list.get(1);
-      pigeonResult.setPosition((Long) position);
-      return pigeonResult;
-    }
-  }
-
   /** Generated class from Pigeon that represents data sent in messages. */
   public static final class CreateMessage {
     private @Nullable String asset;
@@ -659,73 +224,6 @@ ArrayList toList() {
     }
   }
 
-  /** Generated class from Pigeon that represents data sent in messages. */
-  public static final class MixWithOthersMessage {
-    private @NonNull Boolean mixWithOthers;
-
-    public @NonNull Boolean getMixWithOthers() {
-      return mixWithOthers;
-    }
-
-    public void setMixWithOthers(@NonNull Boolean setterArg) {
-      if (setterArg == null) {
-        throw new IllegalStateException("Nonnull field \"mixWithOthers\" is null.");
-      }
-      this.mixWithOthers = setterArg;
-    }
-
-    /** Constructor is non-public to enforce null safety; use Builder. */
-    MixWithOthersMessage() {}
-
-    @Override
-    public boolean equals(Object o) {
-      if (this == o) {
-        return true;
-      }
-      if (o == null || getClass() != o.getClass()) {
-        return false;
-      }
-      MixWithOthersMessage that = (MixWithOthersMessage) o;
-      return mixWithOthers.equals(that.mixWithOthers);
-    }
-
-    @Override
-    public int hashCode() {
-      return Objects.hash(mixWithOthers);
-    }
-
-    public static final class Builder {
-
-      private @Nullable Boolean mixWithOthers;
-
-      @CanIgnoreReturnValue
-      public @NonNull Builder setMixWithOthers(@NonNull Boolean setterArg) {
-        this.mixWithOthers = setterArg;
-        return this;
-      }
-
-      public @NonNull MixWithOthersMessage build() {
-        MixWithOthersMessage pigeonReturn = new MixWithOthersMessage();
-        pigeonReturn.setMixWithOthers(mixWithOthers);
-        return pigeonReturn;
-      }
-    }
-
-    @NonNull
-    ArrayList toList() {
-      ArrayList toListResult = new ArrayList<>(1);
-      toListResult.add(mixWithOthers);
-      return toListResult;
-    }
-
-    static @NonNull MixWithOthersMessage fromList(@NonNull ArrayList pigeonVar_list) {
-      MixWithOthersMessage pigeonResult = new MixWithOthersMessage();
-      Object mixWithOthers = pigeonVar_list.get(0);
-      pigeonResult.setMixWithOthers((Boolean) mixWithOthers);
-      return pigeonResult;
-    }
-  }
-
   private static class PigeonCodec extends StandardMessageCodec {
     public static final PigeonCodec INSTANCE = new PigeonCodec();
 
@@ -735,19 +233,7 @@ private PigeonCodec() {}
     protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) {
       switch (type) {
         case (byte) 129:
-          return TextureMessage.fromList((ArrayList) readValue(buffer));
-        case (byte) 130:
-          return LoopingMessage.fromList((ArrayList) readValue(buffer));
-        case (byte) 131:
-          return VolumeMessage.fromList((ArrayList) readValue(buffer));
-        case (byte) 132:
-          return PlaybackSpeedMessage.fromList((ArrayList) readValue(buffer));
-        case (byte) 133:
-          return PositionMessage.fromList((ArrayList) readValue(buffer));
-        case (byte) 134:
           return CreateMessage.fromList((ArrayList) readValue(buffer));
-        case (byte) 135:
-          return MixWithOthersMessage.fromList((ArrayList) readValue(buffer));
         default:
           return super.readValueOfType(type, buffer);
       }
@@ -755,27 +241,9 @@ protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) {
 
     @Override
     protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) {
-      if (value instanceof TextureMessage) {
+      if (value instanceof CreateMessage) {
         stream.write(129);
-        writeValue(stream, ((TextureMessage) value).toList());
-      } else if (value instanceof LoopingMessage) {
-        stream.write(130);
-        writeValue(stream, ((LoopingMessage) value).toList());
-      } else if (value instanceof VolumeMessage) {
-        stream.write(131);
-        writeValue(stream, ((VolumeMessage) value).toList());
-      } else if (value instanceof PlaybackSpeedMessage) {
-        stream.write(132);
-        writeValue(stream, ((PlaybackSpeedMessage) value).toList());
-      } else if (value instanceof PositionMessage) {
-        stream.write(133);
-        writeValue(stream, ((PositionMessage) value).toList());
-      } else if (value instanceof CreateMessage) {
-        stream.write(134);
         writeValue(stream, ((CreateMessage) value).toList());
-      } else if (value instanceof MixWithOthersMessage) {
-        stream.write(135);
-        writeValue(stream, ((MixWithOthersMessage) value).toList());
       } else {
         super.writeValue(stream, value);
       }
@@ -788,26 +256,26 @@ public interface AndroidVideoPlayerApi {
     void initialize();
 
     @NonNull
-    TextureMessage create(@NonNull CreateMessage msg);
+    Long create(@NonNull CreateMessage msg);
 
-    void dispose(@NonNull TextureMessage msg);
+    void dispose(@NonNull Long textureId);
 
-    void setLooping(@NonNull LoopingMessage msg);
+    void setLooping(@NonNull Long textureId, @NonNull Boolean looping);
 
-    void setVolume(@NonNull VolumeMessage msg);
+    void setVolume(@NonNull Long textureId, @NonNull Double volume);
 
-    void setPlaybackSpeed(@NonNull PlaybackSpeedMessage msg);
+    void setPlaybackSpeed(@NonNull Long textureId, @NonNull Double speed);
 
-    void play(@NonNull TextureMessage msg);
+    void play(@NonNull Long textureId);
 
     @NonNull
-    PositionMessage position(@NonNull TextureMessage msg);
+    Long position(@NonNull Long textureId);
 
-    void seekTo(@NonNull PositionMessage msg);
+    void seekTo(@NonNull Long textureId, @NonNull Long position);
 
-    void pause(@NonNull TextureMessage msg);
+    void pause(@NonNull Long textureId);
 
-    void setMixWithOthers(@NonNull MixWithOthersMessage msg);
+    void setMixWithOthers(@NonNull Boolean mixWithOthers);
 
     /** The codec used by AndroidVideoPlayerApi. */
     static @NonNull MessageCodec getCodec() {
@@ -864,7 +332,7 @@ static void setUp(
                 ArrayList args = (ArrayList) message;
                 CreateMessage msgArg = (CreateMessage) args.get(0);
                 try {
-                  TextureMessage output = api.create(msgArg);
+                  Long output = api.create(msgArg);
                   wrapped.add(0, output);
                 } catch (Throwable exception) {
                   wrapped = wrapError(exception);
@@ -887,9 +355,9 @@ static void setUp(
               (message, reply) -> {
                 ArrayList wrapped = new ArrayList<>();
                 ArrayList args = (ArrayList) message;
-                TextureMessage msgArg = (TextureMessage) args.get(0);
+                Long textureIdArg = (Long) args.get(0);
                 try {
-                  api.dispose(msgArg);
+                  api.dispose(textureIdArg);
                   wrapped.add(0, null);
                 } catch (Throwable exception) {
                   wrapped = wrapError(exception);
@@ -912,9 +380,10 @@ static void setUp(
               (message, reply) -> {
                 ArrayList wrapped = new ArrayList<>();
                 ArrayList args = (ArrayList) message;
-                LoopingMessage msgArg = (LoopingMessage) args.get(0);
+                Long textureIdArg = (Long) args.get(0);
+                Boolean loopingArg = (Boolean) args.get(1);
                 try {
-                  api.setLooping(msgArg);
+                  api.setLooping(textureIdArg, loopingArg);
                   wrapped.add(0, null);
                 } catch (Throwable exception) {
                   wrapped = wrapError(exception);
@@ -937,9 +406,10 @@ static void setUp(
               (message, reply) -> {
                 ArrayList wrapped = new ArrayList<>();
                 ArrayList args = (ArrayList) message;
-                VolumeMessage msgArg = (VolumeMessage) args.get(0);
+                Long textureIdArg = (Long) args.get(0);
+                Double volumeArg = (Double) args.get(1);
                 try {
-                  api.setVolume(msgArg);
+                  api.setVolume(textureIdArg, volumeArg);
                   wrapped.add(0, null);
                 } catch (Throwable exception) {
                   wrapped = wrapError(exception);
@@ -962,9 +432,10 @@ static void setUp(
               (message, reply) -> {
                 ArrayList wrapped = new ArrayList<>();
                 ArrayList args = (ArrayList) message;
-                PlaybackSpeedMessage msgArg = (PlaybackSpeedMessage) args.get(0);
+                Long textureIdArg = (Long) args.get(0);
+                Double speedArg = (Double) args.get(1);
                 try {
-                  api.setPlaybackSpeed(msgArg);
+                  api.setPlaybackSpeed(textureIdArg, speedArg);
                   wrapped.add(0, null);
                 } catch (Throwable exception) {
                   wrapped = wrapError(exception);
@@ -987,9 +458,9 @@ static void setUp(
               (message, reply) -> {
                 ArrayList wrapped = new ArrayList<>();
                 ArrayList args = (ArrayList) message;
-                TextureMessage msgArg = (TextureMessage) args.get(0);
+                Long textureIdArg = (Long) args.get(0);
                 try {
-                  api.play(msgArg);
+                  api.play(textureIdArg);
                   wrapped.add(0, null);
                 } catch (Throwable exception) {
                   wrapped = wrapError(exception);
@@ -1012,9 +483,9 @@ static void setUp(
               (message, reply) -> {
                 ArrayList wrapped = new ArrayList<>();
                 ArrayList args = (ArrayList) message;
-                TextureMessage msgArg = (TextureMessage) args.get(0);
+                Long textureIdArg = (Long) args.get(0);
                 try {
-                  PositionMessage output = api.position(msgArg);
+                  Long output = api.position(textureIdArg);
                   wrapped.add(0, output);
                 } catch (Throwable exception) {
                   wrapped = wrapError(exception);
@@ -1037,9 +508,10 @@ static void setUp(
               (message, reply) -> {
                 ArrayList wrapped = new ArrayList<>();
                 ArrayList args = (ArrayList) message;
-                PositionMessage msgArg = (PositionMessage) args.get(0);
+                Long textureIdArg = (Long) args.get(0);
+                Long positionArg = (Long) args.get(1);
                 try {
-                  api.seekTo(msgArg);
+                  api.seekTo(textureIdArg, positionArg);
                   wrapped.add(0, null);
                 } catch (Throwable exception) {
                   wrapped = wrapError(exception);
@@ -1062,9 +534,9 @@ static void setUp(
               (message, reply) -> {
                 ArrayList wrapped = new ArrayList<>();
                 ArrayList args = (ArrayList) message;
-                TextureMessage msgArg = (TextureMessage) args.get(0);
+                Long textureIdArg = (Long) args.get(0);
                 try {
-                  api.pause(msgArg);
+                  api.pause(textureIdArg);
                   wrapped.add(0, null);
                 } catch (Throwable exception) {
                   wrapped = wrapError(exception);
@@ -1087,9 +559,9 @@ static void setUp(
               (message, reply) -> {
                 ArrayList wrapped = new ArrayList<>();
                 ArrayList args = (ArrayList) message;
-                MixWithOthersMessage msgArg = (MixWithOthersMessage) args.get(0);
+                Boolean mixWithOthersArg = (Boolean) args.get(0);
                 try {
-                  api.setMixWithOthers(msgArg);
+                  api.setMixWithOthers(mixWithOthersArg);
                   wrapped.add(0, null);
                 } catch (Throwable exception) {
                   wrapped = wrapError(exception);
diff --git a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java b/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java
index d1911d8cc378..d248ad2f0be8 100644
--- a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java
+++ b/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java
@@ -14,12 +14,6 @@
 import io.flutter.plugin.common.EventChannel;
 import io.flutter.plugins.videoplayer.Messages.AndroidVideoPlayerApi;
 import io.flutter.plugins.videoplayer.Messages.CreateMessage;
-import io.flutter.plugins.videoplayer.Messages.LoopingMessage;
-import io.flutter.plugins.videoplayer.Messages.MixWithOthersMessage;
-import io.flutter.plugins.videoplayer.Messages.PlaybackSpeedMessage;
-import io.flutter.plugins.videoplayer.Messages.PositionMessage;
-import io.flutter.plugins.videoplayer.Messages.TextureMessage;
-import io.flutter.plugins.videoplayer.Messages.VolumeMessage;
 import io.flutter.view.TextureRegistry;
 
 /** Android platform implementation of the VideoPlayerPlugin. */
@@ -71,11 +65,13 @@ public void onDestroy() {
     disposeAllPlayers();
   }
 
+  @Override
   public void initialize() {
     disposeAllPlayers();
   }
 
-  public @NonNull TextureMessage create(@NonNull CreateMessage arg) {
+  @Override
+  public @NonNull Long create(@NonNull CreateMessage arg) {
     TextureRegistry.SurfaceProducer handle = flutterState.textureRegistry.createSurfaceProducer();
     EventChannel eventChannel =
         new EventChannel(
@@ -120,7 +116,7 @@ public void initialize() {
             videoAsset,
             options));
 
-    return new TextureMessage.Builder().setTextureId(handle.id()).build();
+    return handle.id();
   }
 
   @NonNull
@@ -139,56 +135,60 @@ private VideoPlayer getPlayer(long textureId) {
     return player;
   }
 
-  public void dispose(@NonNull TextureMessage arg) {
-    VideoPlayer player = getPlayer(arg.getTextureId());
+  @Override
+  public void dispose(@NonNull Long textureId) {
+    VideoPlayer player = getPlayer(textureId);
     player.dispose();
-    videoPlayers.remove(arg.getTextureId());
+    videoPlayers.remove(textureId);
   }
 
-  public void setLooping(@NonNull LoopingMessage arg) {
-    VideoPlayer player = getPlayer(arg.getTextureId());
-    player.setLooping(arg.getIsLooping());
+  @Override
+  public void setLooping(@NonNull Long textureId, @NonNull Boolean looping) {
+    VideoPlayer player = getPlayer(textureId);
+    player.setLooping(looping);
   }
 
-  public void setVolume(@NonNull VolumeMessage arg) {
-    VideoPlayer player = getPlayer(arg.getTextureId());
-    player.setVolume(arg.getVolume());
+  @Override
+  public void setVolume(@NonNull Long textureId, @NonNull Double volume) {
+    VideoPlayer player = getPlayer(textureId);
+    player.setVolume(volume);
   }
 
-  public void setPlaybackSpeed(@NonNull PlaybackSpeedMessage arg) {
-    VideoPlayer player = getPlayer(arg.getTextureId());
-    player.setPlaybackSpeed(arg.getSpeed());
+  @Override
+  public void setPlaybackSpeed(@NonNull Long textureId, @NonNull Double speed) {
+    VideoPlayer player = getPlayer(textureId);
+    player.setPlaybackSpeed(speed);
   }
 
-  public void play(@NonNull TextureMessage arg) {
-    VideoPlayer player = getPlayer(arg.getTextureId());
+  @Override
+  public void play(@NonNull Long textureId) {
+    VideoPlayer player = getPlayer(textureId);
     player.play();
   }
 
-  public @NonNull PositionMessage position(@NonNull TextureMessage arg) {
-    VideoPlayer player = getPlayer(arg.getTextureId());
-    PositionMessage result =
-        new PositionMessage.Builder()
-            .setPosition(player.getPosition())
-            .setTextureId(arg.getTextureId())
-            .build();
+  @Override
+  public @NonNull Long position(@NonNull Long textureId) {
+    VideoPlayer player = getPlayer(textureId);
+    long position = player.getPosition();
     player.sendBufferingUpdate();
-    return result;
+    return position;
   }
 
-  public void seekTo(@NonNull PositionMessage arg) {
-    VideoPlayer player = getPlayer(arg.getTextureId());
-    player.seekTo(arg.getPosition().intValue());
+  @Override
+  public void seekTo(@NonNull Long textureId, @NonNull Long position) {
+    VideoPlayer player = getPlayer(textureId);
+    player.seekTo(position.intValue());
   }
 
-  public void pause(@NonNull TextureMessage arg) {
-    VideoPlayer player = getPlayer(arg.getTextureId());
+  @Override
+  public void pause(@NonNull Long textureId) {
+    VideoPlayer player = getPlayer(textureId);
     player.pause();
   }
 
   @Override
-  public void setMixWithOthers(@NonNull MixWithOthersMessage arg) {
-    options.mixWithOthers = arg.getMixWithOthers();
+  public void setMixWithOthers(@NonNull Boolean mixWithOthers) {
+    options.mixWithOthers = mixWithOthers;
   }
 
   private interface KeyForAssetFn {
diff --git a/packages/video_player/video_player_android/android/src/test/java/io/flutter/plugins/videoplayer/ExoPlayerEventListenerTests.java b/packages/video_player/video_player_android/android/src/test/java/io/flutter/plugins/videoplayer/ExoPlayerEventListenerTest.java
similarity index 64%
rename from packages/video_player/video_player_android/android/src/test/java/io/flutter/plugins/videoplayer/ExoPlayerEventListenerTests.java
rename to packages/video_player/video_player_android/android/src/test/java/io/flutter/plugins/videoplayer/ExoPlayerEventListenerTest.java
index 1d00d31b8ee5..65dfb311c31c 100644
--- a/packages/video_player/video_player_android/android/src/test/java/io/flutter/plugins/videoplayer/ExoPlayerEventListenerTests.java
+++ b/packages/video_player/video_player_android/android/src/test/java/io/flutter/plugins/videoplayer/ExoPlayerEventListenerTest.java
@@ -12,6 +12,7 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import androidx.media3.common.Format;
 import androidx.media3.common.PlaybackException;
 import androidx.media3.common.Player;
 import androidx.media3.common.VideoSize;
@@ -24,6 +25,7 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 /**
  * Unit tests for {@link ExoPlayerEventListener}.
@@ -33,7 +35,7 @@
  * ({@link VideoPlayerCallbacks} and/or interface with the player instance as expected.
  */
 @RunWith(RobolectricTestRunner.class)
-public final class ExoPlayerEventListenerTests {
+public final class ExoPlayerEventListenerTest {
   @Mock private ExoPlayer mockExoPlayer;
   @Mock private VideoPlayerCallbacks mockCallbacks;
   private ExoPlayerEventListener eventListener;
@@ -46,7 +48,8 @@ public void setUp() {
   }
 
   @Test
-  public void onPlaybackStateChangedReadySendInitialized() {
+  @Config(maxSdk = 28)
+  public void onPlaybackStateChangedReadySendInitialized_belowAndroid29() {
     VideoSize size = new VideoSize(800, 400, 0, 0);
     when(mockExoPlayer.getVideoSize()).thenReturn(size);
     when(mockExoPlayer.getDuration()).thenReturn(10L);
@@ -56,7 +59,25 @@ public void onPlaybackStateChangedReadySendInitialized() {
   }
 
   @Test
-  public void onPlaybackStateChangedReadyInPortraitMode90DegreesSwapWidthAndHeight() {
+  @Config(minSdk = 29)
+  public void
+      onPlaybackStateChangedReadySendInitializedWithRotationCorrectionAndWidthAndHeightSwap_aboveAndroid29() {
+    VideoSize size = new VideoSize(800, 400, 0, 0);
+    int rotationCorrection = 90;
+    Format videoFormat = new Format.Builder().setRotationDegrees(rotationCorrection).build();
+
+    when(mockExoPlayer.getVideoSize()).thenReturn(size);
+    when(mockExoPlayer.getDuration()).thenReturn(10L);
+    when(mockExoPlayer.getVideoFormat()).thenReturn(videoFormat);
+
+    eventListener.onPlaybackStateChanged(Player.STATE_READY);
+    verify(mockCallbacks).onInitialized(400, 800, 10L, rotationCorrection);
+  }
+
+  @Test
+  @Config(maxSdk = 21)
+  public void
+      onPlaybackStateChangedReadyInPortraitMode90DegreesSwapWidthAndHeight_belowAndroid21() {
     VideoSize size = new VideoSize(800, 400, 90, 0);
     when(mockExoPlayer.getVideoSize()).thenReturn(size);
     when(mockExoPlayer.getDuration()).thenReturn(10L);
@@ -66,7 +87,38 @@ public void onPlaybackStateChangedReadyInPortraitMode90DegreesSwapWidthAndHeight
   }
 
   @Test
-  public void onPlaybackStateChangedReadyInPortraitMode270DegreesSwapWidthAndHeight() {
+  @Config(minSdk = 22, maxSdk = 28)
+  public void
+      onPlaybackStateChangedReadyInPortraitMode90DegreesDoesNotSwapWidthAndHeight_aboveAndroid21belowAndroid29() {
+    VideoSize size = new VideoSize(800, 400, 90, 0);
+
+    when(mockExoPlayer.getVideoSize()).thenReturn(size);
+    when(mockExoPlayer.getDuration()).thenReturn(10L);
+
+    eventListener.onPlaybackStateChanged(Player.STATE_READY);
+    verify(mockCallbacks).onInitialized(800, 400, 10L, 0);
+  }
+
+  @Test
+  @Config(minSdk = 29)
+  public void
+      onPlaybackStateChangedReadyInPortraitMode90DegreesSwapWidthAndHeight_aboveAndroid29() {
+    VideoSize size = new VideoSize(800, 400, 0, 0);
+    int rotationCorrection = 90;
+    Format videoFormat = new Format.Builder().setRotationDegrees(rotationCorrection).build();
+
+    when(mockExoPlayer.getVideoSize()).thenReturn(size);
+    when(mockExoPlayer.getDuration()).thenReturn(10L);
+    when(mockExoPlayer.getVideoFormat()).thenReturn(videoFormat);
+
+    eventListener.onPlaybackStateChanged(Player.STATE_READY);
+    verify(mockCallbacks).onInitialized(400, 800, 10L, 90);
+  }
+
+  @Test
+  @Config(maxSdk = 21)
+  public void
+      onPlaybackStateChangedReadyInPortraitMode270DegreesSwapWidthAndHeight_belowAndroid21() {
     VideoSize size = new VideoSize(800, 400, 270, 0);
     when(mockExoPlayer.getVideoSize()).thenReturn(size);
     when(mockExoPlayer.getDuration()).thenReturn(10L);
@@ -76,7 +128,36 @@ public void onPlaybackStateChangedReadyInPortraitMode270DegreesSwapWidthAndHeigh
   }
 
   @Test
-  public void onPlaybackStateChangedReadyFlipped180DegreesInformEventHandler() {
+  @Config(minSdk = 22, maxSdk = 28)
+  public void
+      onPlaybackStateChangedReadyInPortraitMode270DegreesDoesNotSwapWidthAndHeight_aboveAndroid21belowAndroid29() {
+    VideoSize size = new VideoSize(800, 400, 270, 0);
+    when(mockExoPlayer.getVideoSize()).thenReturn(size);
+    when(mockExoPlayer.getDuration()).thenReturn(10L);
+
+    eventListener.onPlaybackStateChanged(Player.STATE_READY);
+    verify(mockCallbacks).onInitialized(800, 400, 10L, 0);
+  }
+
+  @Test
+  @Config(minSdk = 29)
+  public void
+      onPlaybackStateChangedReadyInPortraitMode270DegreesSwapWidthAndHeight_aboveAndroid29() {
+    VideoSize size = new VideoSize(800, 400, 0, 0);
+    int rotationCorrection = 270;
+    Format videoFormat = new Format.Builder().setRotationDegrees(rotationCorrection).build();
+
+    when(mockExoPlayer.getVideoSize()).thenReturn(size);
+    when(mockExoPlayer.getDuration()).thenReturn(10L);
+    when(mockExoPlayer.getVideoFormat()).thenReturn(videoFormat);
+
+    eventListener.onPlaybackStateChanged(Player.STATE_READY);
+    verify(mockCallbacks).onInitialized(400, 800, 10L, 270);
+  }
+
+  @Test
+  @Config(maxSdk = 21)
+  public void onPlaybackStateChangedReadyFlipped180DegreesInformEventHandler_belowAndroid21() {
     VideoSize size = new VideoSize(800, 400, 180, 0);
     when(mockExoPlayer.getVideoSize()).thenReturn(size);
     when(mockExoPlayer.getDuration()).thenReturn(10L);
diff --git a/packages/video_player/video_player_android/example/integration_test/video_player_test.dart b/packages/video_player/video_player_android/example/integration_test/video_player_test.dart
index fc69114c63fd..f347214b9e79 100644
--- a/packages/video_player/video_player_android/example/integration_test/video_player_test.dart
+++ b/packages/video_player/video_player_android/example/integration_test/video_player_test.dart
@@ -95,6 +95,7 @@ void main() {
     await tester.pumpAndSettle(_playDuration);
 
     await player.pause(textureId);
+    await tester.pumpAndSettle(_playDuration);
     final Duration pausedDuration = await player.getPosition(textureId);
     await tester.pumpAndSettle(_playDuration);
 
diff --git a/packages/video_player/video_player_android/lib/src/android_video_player.dart b/packages/video_player/video_player_android/lib/src/android_video_player.dart
index 7d4a600397d4..45665631d932 100644
--- a/packages/video_player/video_player_android/lib/src/android_video_player.dart
+++ b/packages/video_player/video_player_android/lib/src/android_video_player.dart
@@ -27,7 +27,7 @@ class AndroidVideoPlayer extends VideoPlayerPlatform {
 
   @override
   Future dispose(int textureId) {
-    return _api.dispose(TextureMessage(textureId: textureId));
+    return _api.dispose(textureId);
   }
 
   @override
@@ -59,59 +59,45 @@ class AndroidVideoPlayer extends VideoPlayerPlatform {
       formatHint: formatHint,
     );
 
-    final TextureMessage response = await _api.create(message);
-    return response.textureId;
+    return _api.create(message);
   }
 
   @override
   Future setLooping(int textureId, bool looping) {
-    return _api.setLooping(LoopingMessage(
-      textureId: textureId,
-      isLooping: looping,
-    ));
+    return _api.setLooping(textureId, looping);
   }
 
   @override
   Future play(int textureId) {
-    return _api.play(TextureMessage(textureId: textureId));
+    return _api.play(textureId);
   }
 
   @override
   Future pause(int textureId) {
-    return _api.pause(TextureMessage(textureId: textureId));
+    return _api.pause(textureId);
   }
 
   @override
   Future setVolume(int textureId, double volume) {
-    return _api.setVolume(VolumeMessage(
-      textureId: textureId,
-      volume: volume,
-    ));
+    return _api.setVolume(textureId, volume);
   }
 
   @override
   Future setPlaybackSpeed(int textureId, double speed) {
     assert(speed > 0);
 
-    return _api.setPlaybackSpeed(PlaybackSpeedMessage(
-      textureId: textureId,
-      speed: speed,
-    ));
+    return _api.setPlaybackSpeed(textureId, speed);
   }
 
   @override
   Future seekTo(int textureId, Duration position) {
-    return _api.seekTo(PositionMessage(
-      textureId: textureId,
-      position: position.inMilliseconds,
-    ));
+    return _api.seekTo(textureId, position.inMilliseconds);
   }
 
   @override
   Future getPosition(int textureId) async {
-    final PositionMessage response =
-        await _api.position(TextureMessage(textureId: textureId));
-    return Duration(milliseconds: response.position);
+    final int position = await _api.position(textureId);
+    return Duration(milliseconds: position);
   }
 
   @override
@@ -162,8 +148,7 @@ class AndroidVideoPlayer extends VideoPlayerPlatform {
 
   @override
   Future setMixWithOthers(bool mixWithOthers) {
-    return _api
-        .setMixWithOthers(MixWithOthersMessage(mixWithOthers: mixWithOthers));
+    return _api.setMixWithOthers(mixWithOthers);
   }
 
   EventChannel _eventChannelFor(int textureId) {
diff --git a/packages/video_player/video_player_android/lib/src/messages.g.dart b/packages/video_player/video_player_android/lib/src/messages.g.dart
index 9cff05e9e9dc..e3190b389e4e 100644
--- a/packages/video_player/video_player_android/lib/src/messages.g.dart
+++ b/packages/video_player/video_player_android/lib/src/messages.g.dart
@@ -1,7 +1,7 @@
 // Copyright 2013 The Flutter Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-// Autogenerated from Pigeon (v22.4.2), do not edit directly.
+// Autogenerated from Pigeon (v22.5.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers
 
@@ -29,131 +29,6 @@ List wrapResponse(
   return [error.code, error.message, error.details];
 }
 
-class TextureMessage {
-  TextureMessage({
-    required this.textureId,
-  });
-
-  int textureId;
-
-  Object encode() {
-    return [
-      textureId,
-    ];
-  }
-
-  static TextureMessage decode(Object result) {
-    result as List;
-    return TextureMessage(
-      textureId: result[0]! as int,
-    );
-  }
-}
-
-class LoopingMessage {
-  LoopingMessage({
-    required this.textureId,
-    required this.isLooping,
-  });
-
-  int textureId;
-
-  bool isLooping;
-
-  Object encode() {
-    return [
-      textureId,
-      isLooping,
-    ];
-  }
-
-  static LoopingMessage decode(Object result) {
-    result as List;
-    return LoopingMessage(
-      textureId: result[0]! as int,
-      isLooping: result[1]! as bool,
-    );
-  }
-}
-
-class VolumeMessage {
-  VolumeMessage({
-    required this.textureId,
-    required this.volume,
-  });
-
-  int textureId;
-
-  double volume;
-
-  Object encode() {
-    return [
-      textureId,
-      volume,
-    ];
-  }
-
-  static VolumeMessage decode(Object result) {
-    result as List;
-    return VolumeMessage(
-      textureId: result[0]! as int,
-      volume: result[1]! as double,
-    );
-  }
-}
-
-class PlaybackSpeedMessage {
-  PlaybackSpeedMessage({
-    required this.textureId,
-    required this.speed,
-  });
-
-  int textureId;
-
-  double speed;
-
-  Object encode() {
-    return [
-      textureId,
-      speed,
-    ];
-  }
-
-  static PlaybackSpeedMessage decode(Object result) {
-    result as List;
-    return PlaybackSpeedMessage(
-      textureId: result[0]! as int,
-      speed: result[1]! as double,
-    );
-  }
-}
-
-class PositionMessage {
-  PositionMessage({
-    required this.textureId,
-    required this.position,
-  });
-
-  int textureId;
-
-  int position;
-
-  Object encode() {
-    return [
-      textureId,
-      position,
-    ];
-  }
-
-  static PositionMessage decode(Object result) {
-    result as List;
-    return PositionMessage(
-      textureId: result[0]! as int,
-      position: result[1]! as int,
-    );
-  }
-}
-
 class CreateMessage {
   CreateMessage({
     this.asset,
@@ -196,27 +71,6 @@ class CreateMessage {
   }
 }
 
-class MixWithOthersMessage {
-  MixWithOthersMessage({
-    required this.mixWithOthers,
-  });
-
-  bool mixWithOthers;
-
-  Object encode() {
-    return [
-      mixWithOthers,
-    ];
-  }
-
-  static MixWithOthersMessage decode(Object result) {
-    result as List;
-    return MixWithOthersMessage(
-      mixWithOthers: result[0]! as bool,
-    );
-  }
-}
-
 class _PigeonCodec extends StandardMessageCodec {
   const _PigeonCodec();
   @override
@@ -224,26 +78,8 @@ class _PigeonCodec extends StandardMessageCodec {
     if (value is int) {
       buffer.putUint8(4);
       buffer.putInt64(value);
-    } else if (value is TextureMessage) {
-      buffer.putUint8(129);
-      writeValue(buffer, value.encode());
-    } else if (value is LoopingMessage) {
-      buffer.putUint8(130);
-      writeValue(buffer, value.encode());
-    } else if (value is VolumeMessage) {
-      buffer.putUint8(131);
-      writeValue(buffer, value.encode());
-    } else if (value is PlaybackSpeedMessage) {
-      buffer.putUint8(132);
-      writeValue(buffer, value.encode());
-    } else if (value is PositionMessage) {
-      buffer.putUint8(133);
-      writeValue(buffer, value.encode());
     } else if (value is CreateMessage) {
-      buffer.putUint8(134);
-      writeValue(buffer, value.encode());
-    } else if (value is MixWithOthersMessage) {
-      buffer.putUint8(135);
+      buffer.putUint8(129);
       writeValue(buffer, value.encode());
     } else {
       super.writeValue(buffer, value);
@@ -254,19 +90,7 @@ class _PigeonCodec extends StandardMessageCodec {
   Object? readValueOfType(int type, ReadBuffer buffer) {
     switch (type) {
       case 129:
-        return TextureMessage.decode(readValue(buffer)!);
-      case 130:
-        return LoopingMessage.decode(readValue(buffer)!);
-      case 131:
-        return VolumeMessage.decode(readValue(buffer)!);
-      case 132:
-        return PlaybackSpeedMessage.decode(readValue(buffer)!);
-      case 133:
-        return PositionMessage.decode(readValue(buffer)!);
-      case 134:
         return CreateMessage.decode(readValue(buffer)!);
-      case 135:
-        return MixWithOthersMessage.decode(readValue(buffer)!);
       default:
         return super.readValueOfType(type, buffer);
     }
@@ -312,7 +136,7 @@ class AndroidVideoPlayerApi {
     }
   }
 
-  Future create(CreateMessage msg) async {
+  Future create(CreateMessage msg) async {
     final String pigeonVar_channelName =
         'dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.create$pigeonVar_messageChannelSuffix';
     final BasicMessageChannel pigeonVar_channel =
@@ -337,11 +161,11 @@ class AndroidVideoPlayerApi {
         message: 'Host platform returned null value for non-null return value.',
       );
     } else {
-      return (pigeonVar_replyList[0] as TextureMessage?)!;
+      return (pigeonVar_replyList[0] as int?)!;
     }
   }
 
-  Future dispose(TextureMessage msg) async {
+  Future dispose(int textureId) async {
     final String pigeonVar_channelName =
         'dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.dispose$pigeonVar_messageChannelSuffix';
     final BasicMessageChannel pigeonVar_channel =
@@ -351,7 +175,7 @@ class AndroidVideoPlayerApi {
       binaryMessenger: pigeonVar_binaryMessenger,
     );
     final List? pigeonVar_replyList =
-        await pigeonVar_channel.send([msg]) as List?;
+        await pigeonVar_channel.send([textureId]) as List?;
     if (pigeonVar_replyList == null) {
       throw _createConnectionError(pigeonVar_channelName);
     } else if (pigeonVar_replyList.length > 1) {
@@ -365,7 +189,7 @@ class AndroidVideoPlayerApi {
     }
   }
 
-  Future setLooping(LoopingMessage msg) async {
+  Future setLooping(int textureId, bool looping) async {
     final String pigeonVar_channelName =
         'dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setLooping$pigeonVar_messageChannelSuffix';
     final BasicMessageChannel pigeonVar_channel =
@@ -374,8 +198,8 @@ class AndroidVideoPlayerApi {
       pigeonChannelCodec,
       binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? pigeonVar_replyList =
-        await pigeonVar_channel.send([msg]) as List?;
+    final List? pigeonVar_replyList = await pigeonVar_channel
+        .send([textureId, looping]) as List?;
     if (pigeonVar_replyList == null) {
       throw _createConnectionError(pigeonVar_channelName);
     } else if (pigeonVar_replyList.length > 1) {
@@ -389,7 +213,7 @@ class AndroidVideoPlayerApi {
     }
   }
 
-  Future setVolume(VolumeMessage msg) async {
+  Future setVolume(int textureId, double volume) async {
     final String pigeonVar_channelName =
         'dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setVolume$pigeonVar_messageChannelSuffix';
     final BasicMessageChannel pigeonVar_channel =
@@ -398,8 +222,8 @@ class AndroidVideoPlayerApi {
       pigeonChannelCodec,
       binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? pigeonVar_replyList =
-        await pigeonVar_channel.send([msg]) as List?;
+    final List? pigeonVar_replyList = await pigeonVar_channel
+        .send([textureId, volume]) as List?;
     if (pigeonVar_replyList == null) {
       throw _createConnectionError(pigeonVar_channelName);
     } else if (pigeonVar_replyList.length > 1) {
@@ -413,7 +237,7 @@ class AndroidVideoPlayerApi {
     }
   }
 
-  Future setPlaybackSpeed(PlaybackSpeedMessage msg) async {
+  Future setPlaybackSpeed(int textureId, double speed) async {
     final String pigeonVar_channelName =
         'dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setPlaybackSpeed$pigeonVar_messageChannelSuffix';
     final BasicMessageChannel pigeonVar_channel =
@@ -422,8 +246,8 @@ class AndroidVideoPlayerApi {
       pigeonChannelCodec,
       binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? pigeonVar_replyList =
-        await pigeonVar_channel.send([msg]) as List?;
+    final List? pigeonVar_replyList = await pigeonVar_channel
+        .send([textureId, speed]) as List?;
     if (pigeonVar_replyList == null) {
       throw _createConnectionError(pigeonVar_channelName);
     } else if (pigeonVar_replyList.length > 1) {
@@ -437,7 +261,7 @@ class AndroidVideoPlayerApi {
     }
   }
 
-  Future play(TextureMessage msg) async {
+  Future play(int textureId) async {
     final String pigeonVar_channelName =
         'dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.play$pigeonVar_messageChannelSuffix';
     final BasicMessageChannel pigeonVar_channel =
@@ -447,7 +271,7 @@ class AndroidVideoPlayerApi {
       binaryMessenger: pigeonVar_binaryMessenger,
     );
     final List? pigeonVar_replyList =
-        await pigeonVar_channel.send([msg]) as List?;
+        await pigeonVar_channel.send([textureId]) as List?;
     if (pigeonVar_replyList == null) {
       throw _createConnectionError(pigeonVar_channelName);
     } else if (pigeonVar_replyList.length > 1) {
@@ -461,7 +285,7 @@ class AndroidVideoPlayerApi {
     }
   }
 
-  Future position(TextureMessage msg) async {
+  Future position(int textureId) async {
     final String pigeonVar_channelName =
         'dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.position$pigeonVar_messageChannelSuffix';
     final BasicMessageChannel pigeonVar_channel =
@@ -471,7 +295,7 @@ class AndroidVideoPlayerApi {
       binaryMessenger: pigeonVar_binaryMessenger,
     );
     final List? pigeonVar_replyList =
-        await pigeonVar_channel.send([msg]) as List?;
+        await pigeonVar_channel.send([textureId]) as List?;
     if (pigeonVar_replyList == null) {
       throw _createConnectionError(pigeonVar_channelName);
     } else if (pigeonVar_replyList.length > 1) {
@@ -486,11 +310,11 @@ class AndroidVideoPlayerApi {
         message: 'Host platform returned null value for non-null return value.',
       );
     } else {
-      return (pigeonVar_replyList[0] as PositionMessage?)!;
+      return (pigeonVar_replyList[0] as int?)!;
     }
   }
 
-  Future seekTo(PositionMessage msg) async {
+  Future seekTo(int textureId, int position) async {
     final String pigeonVar_channelName =
         'dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.seekTo$pigeonVar_messageChannelSuffix';
     final BasicMessageChannel pigeonVar_channel =
@@ -499,8 +323,8 @@ class AndroidVideoPlayerApi {
       pigeonChannelCodec,
       binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? pigeonVar_replyList =
-        await pigeonVar_channel.send([msg]) as List?;
+    final List? pigeonVar_replyList = await pigeonVar_channel
+        .send([textureId, position]) as List?;
     if (pigeonVar_replyList == null) {
       throw _createConnectionError(pigeonVar_channelName);
     } else if (pigeonVar_replyList.length > 1) {
@@ -514,7 +338,7 @@ class AndroidVideoPlayerApi {
     }
   }
 
-  Future pause(TextureMessage msg) async {
+  Future pause(int textureId) async {
     final String pigeonVar_channelName =
         'dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.pause$pigeonVar_messageChannelSuffix';
     final BasicMessageChannel pigeonVar_channel =
@@ -524,7 +348,7 @@ class AndroidVideoPlayerApi {
       binaryMessenger: pigeonVar_binaryMessenger,
     );
     final List? pigeonVar_replyList =
-        await pigeonVar_channel.send([msg]) as List?;
+        await pigeonVar_channel.send([textureId]) as List?;
     if (pigeonVar_replyList == null) {
       throw _createConnectionError(pigeonVar_channelName);
     } else if (pigeonVar_replyList.length > 1) {
@@ -538,7 +362,7 @@ class AndroidVideoPlayerApi {
     }
   }
 
-  Future setMixWithOthers(MixWithOthersMessage msg) async {
+  Future setMixWithOthers(bool mixWithOthers) async {
     final String pigeonVar_channelName =
         'dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setMixWithOthers$pigeonVar_messageChannelSuffix';
     final BasicMessageChannel pigeonVar_channel =
@@ -547,8 +371,8 @@ class AndroidVideoPlayerApi {
       pigeonChannelCodec,
       binaryMessenger: pigeonVar_binaryMessenger,
     );
-    final List? pigeonVar_replyList =
-        await pigeonVar_channel.send([msg]) as List?;
+    final List? pigeonVar_replyList = await pigeonVar_channel
+        .send([mixWithOthers]) as List?;
     if (pigeonVar_replyList == null) {
       throw _createConnectionError(pigeonVar_channelName);
     } else if (pigeonVar_replyList.length > 1) {
diff --git a/packages/video_player/video_player_android/pigeons/messages.dart b/packages/video_player/video_player_android/pigeons/messages.dart
index 8538f52cedcf..37bde3dcda5f 100644
--- a/packages/video_player/video_player_android/pigeons/messages.dart
+++ b/packages/video_player/video_player_android/pigeons/messages.dart
@@ -13,35 +13,6 @@ import 'package:pigeon/pigeon.dart';
   ),
   copyrightHeader: 'pigeons/copyright.txt',
 ))
-class TextureMessage {
-  TextureMessage(this.textureId);
-  int textureId;
-}
-
-class LoopingMessage {
-  LoopingMessage(this.textureId, this.isLooping);
-  int textureId;
-  bool isLooping;
-}
-
-class VolumeMessage {
-  VolumeMessage(this.textureId, this.volume);
-  int textureId;
-  double volume;
-}
-
-class PlaybackSpeedMessage {
-  PlaybackSpeedMessage(this.textureId, this.speed);
-  int textureId;
-  double speed;
-}
-
-class PositionMessage {
-  PositionMessage(this.textureId, this.position);
-  int textureId;
-  int position;
-}
-
 class CreateMessage {
   CreateMessage({required this.httpHeaders});
   String? asset;
@@ -51,22 +22,17 @@ class CreateMessage {
   Map httpHeaders;
 }
 
-class MixWithOthersMessage {
-  MixWithOthersMessage(this.mixWithOthers);
-  bool mixWithOthers;
-}
-
 @HostApi(dartHostTestHandler: 'TestHostVideoPlayerApi')
 abstract class AndroidVideoPlayerApi {
   void initialize();
-  TextureMessage create(CreateMessage msg);
-  void dispose(TextureMessage msg);
-  void setLooping(LoopingMessage msg);
-  void setVolume(VolumeMessage msg);
-  void setPlaybackSpeed(PlaybackSpeedMessage msg);
-  void play(TextureMessage msg);
-  PositionMessage position(TextureMessage msg);
-  void seekTo(PositionMessage msg);
-  void pause(TextureMessage msg);
-  void setMixWithOthers(MixWithOthersMessage msg);
+  int create(CreateMessage msg);
+  void dispose(int textureId);
+  void setLooping(int textureId, bool looping);
+  void setVolume(int textureId, double volume);
+  void setPlaybackSpeed(int textureId, double speed);
+  void play(int textureId);
+  int position(int textureId);
+  void seekTo(int textureId, int position);
+  void pause(int textureId);
+  void setMixWithOthers(bool mixWithOthers);
 }
diff --git a/packages/video_player/video_player_android/pubspec.yaml b/packages/video_player/video_player_android/pubspec.yaml
index 0eee37495de4..ababc4aca4ea 100644
--- a/packages/video_player/video_player_android/pubspec.yaml
+++ b/packages/video_player/video_player_android/pubspec.yaml
@@ -2,7 +2,7 @@ name: video_player_android
 description: Android implementation of the video_player plugin.
 repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player_android
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22
-version: 2.7.14
+version: 2.7.16
 
 environment:
   sdk: ^3.5.0
diff --git a/packages/video_player/video_player_android/test/android_video_player_test.dart b/packages/video_player/video_player_android/test/android_video_player_test.dart
index dc9544781cf6..2c99cb934d02 100644
--- a/packages/video_player/video_player_android/test/android_video_player_test.dart
+++ b/packages/video_player/video_player_android/test/android_video_player_test.dart
@@ -12,25 +12,25 @@ import 'test_api.g.dart';
 
 class _ApiLogger implements TestHostVideoPlayerApi {
   final List log = [];
-  TextureMessage? textureMessage;
-  CreateMessage? createMessage;
-  PositionMessage? positionMessage;
-  LoopingMessage? loopingMessage;
-  VolumeMessage? volumeMessage;
-  PlaybackSpeedMessage? playbackSpeedMessage;
-  MixWithOthersMessage? mixWithOthersMessage;
+  int? passedTextureId;
+  CreateMessage? passedCreateMessage;
+  int? passedPosition;
+  bool? passedLooping;
+  double? passedVolume;
+  double? passedPlaybackSpeed;
+  bool? passedMixWithOthers;
 
   @override
-  TextureMessage create(CreateMessage arg) {
+  int create(CreateMessage arg) {
     log.add('create');
-    createMessage = arg;
-    return TextureMessage(textureId: 3);
+    passedCreateMessage = arg;
+    return 3;
   }
 
   @override
-  void dispose(TextureMessage arg) {
+  void dispose(int textureId) {
     log.add('dispose');
-    textureMessage = arg;
+    passedTextureId = textureId;
   }
 
   @override
@@ -39,52 +39,56 @@ class _ApiLogger implements TestHostVideoPlayerApi {
   }
 
   @override
-  void pause(TextureMessage arg) {
+  void pause(int textureId) {
     log.add('pause');
-    textureMessage = arg;
+    passedTextureId = textureId;
   }
 
   @override
-  void play(TextureMessage arg) {
+  void play(int textureId) {
     log.add('play');
-    textureMessage = arg;
+    passedTextureId = textureId;
   }
 
   @override
-  void setMixWithOthers(MixWithOthersMessage arg) {
+  void setMixWithOthers(bool mixWithOthers) {
     log.add('setMixWithOthers');
-    mixWithOthersMessage = arg;
+    passedMixWithOthers = mixWithOthers;
   }
 
   @override
-  PositionMessage position(TextureMessage arg) {
+  int position(int textureId) {
     log.add('position');
-    textureMessage = arg;
-    return PositionMessage(textureId: arg.textureId, position: 234);
+    passedTextureId = textureId;
+    return 234;
   }
 
   @override
-  void seekTo(PositionMessage arg) {
+  void seekTo(int textureId, int position) {
     log.add('seekTo');
-    positionMessage = arg;
+    passedTextureId = textureId;
+    passedPosition = position;
   }
 
   @override
-  void setLooping(LoopingMessage arg) {
+  void setLooping(int textureId, bool looping) {
     log.add('setLooping');
-    loopingMessage = arg;
+    passedTextureId = textureId;
+    passedLooping = looping;
   }
 
   @override
-  void setVolume(VolumeMessage arg) {
+  void setVolume(int textureId, double volume) {
     log.add('setVolume');
-    volumeMessage = arg;
+    passedTextureId = textureId;
+    passedVolume = volume;
   }
 
   @override
-  void setPlaybackSpeed(PlaybackSpeedMessage arg) {
+  void setPlaybackSpeed(int textureId, double speed) {
     log.add('setPlaybackSpeed');
-    playbackSpeedMessage = arg;
+    passedTextureId = textureId;
+    passedPlaybackSpeed = speed;
   }
 }
 
@@ -116,7 +120,7 @@ void main() {
     test('dispose', () async {
       await player.dispose(1);
       expect(log.log.last, 'dispose');
-      expect(log.textureMessage?.textureId, 1);
+      expect(log.passedTextureId, 1);
     });
 
     test('create with asset', () async {
@@ -126,8 +130,8 @@ void main() {
         package: 'somePackage',
       ));
       expect(log.log.last, 'create');
-      expect(log.createMessage?.asset, 'someAsset');
-      expect(log.createMessage?.packageName, 'somePackage');
+      expect(log.passedCreateMessage?.asset, 'someAsset');
+      expect(log.passedCreateMessage?.packageName, 'somePackage');
       expect(textureId, 3);
     });
 
@@ -138,11 +142,11 @@ void main() {
         formatHint: VideoFormat.dash,
       ));
       expect(log.log.last, 'create');
-      expect(log.createMessage?.asset, null);
-      expect(log.createMessage?.uri, 'someUri');
-      expect(log.createMessage?.packageName, null);
-      expect(log.createMessage?.formatHint, 'dash');
-      expect(log.createMessage?.httpHeaders, {});
+      expect(log.passedCreateMessage?.asset, null);
+      expect(log.passedCreateMessage?.uri, 'someUri');
+      expect(log.passedCreateMessage?.packageName, null);
+      expect(log.passedCreateMessage?.formatHint, 'dash');
+      expect(log.passedCreateMessage?.httpHeaders, {});
       expect(textureId, 3);
     });
 
@@ -153,11 +157,11 @@ void main() {
         httpHeaders: {'Authorization': 'Bearer token'},
       ));
       expect(log.log.last, 'create');
-      expect(log.createMessage?.asset, null);
-      expect(log.createMessage?.uri, 'someUri');
-      expect(log.createMessage?.packageName, null);
-      expect(log.createMessage?.formatHint, null);
-      expect(log.createMessage?.httpHeaders,
+      expect(log.passedCreateMessage?.asset, null);
+      expect(log.passedCreateMessage?.uri, 'someUri');
+      expect(log.passedCreateMessage?.packageName, null);
+      expect(log.passedCreateMessage?.formatHint, null);
+      expect(log.passedCreateMessage?.httpHeaders,
           {'Authorization': 'Bearer token'});
       expect(textureId, 3);
     });
@@ -168,7 +172,7 @@ void main() {
         uri: 'someUri',
       ));
       expect(log.log.last, 'create');
-      expect(log.createMessage?.uri, 'someUri');
+      expect(log.passedCreateMessage?.uri, 'someUri');
       expect(textureId, 3);
     });
 
@@ -179,65 +183,65 @@ void main() {
         httpHeaders: {'Authorization': 'Bearer token'},
       ));
       expect(log.log.last, 'create');
-      expect(log.createMessage?.uri, 'someUri');
-      expect(log.createMessage?.httpHeaders,
+      expect(log.passedCreateMessage?.uri, 'someUri');
+      expect(log.passedCreateMessage?.httpHeaders,
           {'Authorization': 'Bearer token'});
       expect(textureId, 3);
     });
     test('setLooping', () async {
       await player.setLooping(1, true);
       expect(log.log.last, 'setLooping');
-      expect(log.loopingMessage?.textureId, 1);
-      expect(log.loopingMessage?.isLooping, true);
+      expect(log.passedTextureId, 1);
+      expect(log.passedLooping, true);
     });
 
     test('play', () async {
       await player.play(1);
       expect(log.log.last, 'play');
-      expect(log.textureMessage?.textureId, 1);
+      expect(log.passedTextureId, 1);
     });
 
     test('pause', () async {
       await player.pause(1);
       expect(log.log.last, 'pause');
-      expect(log.textureMessage?.textureId, 1);
+      expect(log.passedTextureId, 1);
     });
 
     test('setMixWithOthers', () async {
       await player.setMixWithOthers(true);
       expect(log.log.last, 'setMixWithOthers');
-      expect(log.mixWithOthersMessage?.mixWithOthers, true);
+      expect(log.passedMixWithOthers, true);
 
       await player.setMixWithOthers(false);
       expect(log.log.last, 'setMixWithOthers');
-      expect(log.mixWithOthersMessage?.mixWithOthers, false);
+      expect(log.passedMixWithOthers, false);
     });
 
     test('setVolume', () async {
       await player.setVolume(1, 0.7);
       expect(log.log.last, 'setVolume');
-      expect(log.volumeMessage?.textureId, 1);
-      expect(log.volumeMessage?.volume, 0.7);
+      expect(log.passedTextureId, 1);
+      expect(log.passedVolume, 0.7);
     });
 
     test('setPlaybackSpeed', () async {
       await player.setPlaybackSpeed(1, 1.5);
       expect(log.log.last, 'setPlaybackSpeed');
-      expect(log.playbackSpeedMessage?.textureId, 1);
-      expect(log.playbackSpeedMessage?.speed, 1.5);
+      expect(log.passedTextureId, 1);
+      expect(log.passedPlaybackSpeed, 1.5);
     });
 
     test('seekTo', () async {
       await player.seekTo(1, const Duration(milliseconds: 12345));
       expect(log.log.last, 'seekTo');
-      expect(log.positionMessage?.textureId, 1);
-      expect(log.positionMessage?.position, 12345);
+      expect(log.passedTextureId, 1);
+      expect(log.passedPosition, 12345);
     });
 
     test('getPosition', () async {
       final Duration position = await player.getPosition(1);
       expect(log.log.last, 'position');
-      expect(log.textureMessage?.textureId, 1);
+      expect(log.passedTextureId, 1);
       expect(position, const Duration(milliseconds: 234));
     });
 
diff --git a/packages/video_player/video_player_android/test/test_api.g.dart b/packages/video_player/video_player_android/test/test_api.g.dart
index 6dadde6b37e4..838dcfbc5a21 100644
--- a/packages/video_player/video_player_android/test/test_api.g.dart
+++ b/packages/video_player/video_player_android/test/test_api.g.dart
@@ -1,7 +1,7 @@
 // Copyright 2013 The Flutter Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-// Autogenerated from Pigeon (v22.4.2), do not edit directly.
+// Autogenerated from Pigeon (v22.5.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import, no_leading_underscores_for_local_identifiers
 // ignore_for_file: avoid_relative_lib_imports
@@ -20,26 +20,8 @@ class _PigeonCodec extends StandardMessageCodec {
     if (value is int) {
       buffer.putUint8(4);
       buffer.putInt64(value);
-    } else if (value is TextureMessage) {
-      buffer.putUint8(129);
-      writeValue(buffer, value.encode());
-    } else if (value is LoopingMessage) {
-      buffer.putUint8(130);
-      writeValue(buffer, value.encode());
-    } else if (value is VolumeMessage) {
-      buffer.putUint8(131);
-      writeValue(buffer, value.encode());
-    } else if (value is PlaybackSpeedMessage) {
-      buffer.putUint8(132);
-      writeValue(buffer, value.encode());
-    } else if (value is PositionMessage) {
-      buffer.putUint8(133);
-      writeValue(buffer, value.encode());
     } else if (value is CreateMessage) {
-      buffer.putUint8(134);
-      writeValue(buffer, value.encode());
-    } else if (value is MixWithOthersMessage) {
-      buffer.putUint8(135);
+      buffer.putUint8(129);
       writeValue(buffer, value.encode());
     } else {
       super.writeValue(buffer, value);
@@ -50,19 +32,7 @@ class _PigeonCodec extends StandardMessageCodec {
   Object? readValueOfType(int type, ReadBuffer buffer) {
     switch (type) {
       case 129:
-        return TextureMessage.decode(readValue(buffer)!);
-      case 130:
-        return LoopingMessage.decode(readValue(buffer)!);
-      case 131:
-        return VolumeMessage.decode(readValue(buffer)!);
-      case 132:
-        return PlaybackSpeedMessage.decode(readValue(buffer)!);
-      case 133:
-        return PositionMessage.decode(readValue(buffer)!);
-      case 134:
         return CreateMessage.decode(readValue(buffer)!);
-      case 135:
-        return MixWithOthersMessage.decode(readValue(buffer)!);
       default:
         return super.readValueOfType(type, buffer);
     }
@@ -76,25 +46,25 @@ abstract class TestHostVideoPlayerApi {
 
   void initialize();
 
-  TextureMessage create(CreateMessage msg);
+  int create(CreateMessage msg);
 
-  void dispose(TextureMessage msg);
+  void dispose(int textureId);
 
-  void setLooping(LoopingMessage msg);
+  void setLooping(int textureId, bool looping);
 
-  void setVolume(VolumeMessage msg);
+  void setVolume(int textureId, double volume);
 
-  void setPlaybackSpeed(PlaybackSpeedMessage msg);
+  void setPlaybackSpeed(int textureId, double speed);
 
-  void play(TextureMessage msg);
+  void play(int textureId);
 
-  PositionMessage position(TextureMessage msg);
+  int position(int textureId);
 
-  void seekTo(PositionMessage msg);
+  void seekTo(int textureId, int position);
 
-  void pause(TextureMessage msg);
+  void pause(int textureId);
 
-  void setMixWithOthers(MixWithOthersMessage msg);
+  void setMixWithOthers(bool mixWithOthers);
 
   static void setUp(
     TestHostVideoPlayerApi? api, {
@@ -150,7 +120,7 @@ abstract class TestHostVideoPlayerApi {
           assert(arg_msg != null,
               'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.create was null, expected non-null CreateMessage.');
           try {
-            final TextureMessage output = api.create(arg_msg!);
+            final int output = api.create(arg_msg!);
             return [output];
           } on PlatformException catch (e) {
             return wrapResponse(error: e);
@@ -178,11 +148,11 @@ abstract class TestHostVideoPlayerApi {
           assert(message != null,
               'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.dispose was null.');
           final List args = (message as List?)!;
-          final TextureMessage? arg_msg = (args[0] as TextureMessage?);
-          assert(arg_msg != null,
-              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.dispose was null, expected non-null TextureMessage.');
+          final int? arg_textureId = (args[0] as int?);
+          assert(arg_textureId != null,
+              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.dispose was null, expected non-null int.');
           try {
-            api.dispose(arg_msg!);
+            api.dispose(arg_textureId!);
             return wrapResponse(empty: true);
           } on PlatformException catch (e) {
             return wrapResponse(error: e);
@@ -210,11 +180,14 @@ abstract class TestHostVideoPlayerApi {
           assert(message != null,
               'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setLooping was null.');
           final List args = (message as List?)!;
-          final LoopingMessage? arg_msg = (args[0] as LoopingMessage?);
-          assert(arg_msg != null,
-              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setLooping was null, expected non-null LoopingMessage.');
+          final int? arg_textureId = (args[0] as int?);
+          assert(arg_textureId != null,
+              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setLooping was null, expected non-null int.');
+          final bool? arg_looping = (args[1] as bool?);
+          assert(arg_looping != null,
+              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setLooping was null, expected non-null bool.');
           try {
-            api.setLooping(arg_msg!);
+            api.setLooping(arg_textureId!, arg_looping!);
             return wrapResponse(empty: true);
           } on PlatformException catch (e) {
             return wrapResponse(error: e);
@@ -242,11 +215,14 @@ abstract class TestHostVideoPlayerApi {
           assert(message != null,
               'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setVolume was null.');
           final List args = (message as List?)!;
-          final VolumeMessage? arg_msg = (args[0] as VolumeMessage?);
-          assert(arg_msg != null,
-              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setVolume was null, expected non-null VolumeMessage.');
+          final int? arg_textureId = (args[0] as int?);
+          assert(arg_textureId != null,
+              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setVolume was null, expected non-null int.');
+          final double? arg_volume = (args[1] as double?);
+          assert(arg_volume != null,
+              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setVolume was null, expected non-null double.');
           try {
-            api.setVolume(arg_msg!);
+            api.setVolume(arg_textureId!, arg_volume!);
             return wrapResponse(empty: true);
           } on PlatformException catch (e) {
             return wrapResponse(error: e);
@@ -274,12 +250,14 @@ abstract class TestHostVideoPlayerApi {
           assert(message != null,
               'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setPlaybackSpeed was null.');
           final List args = (message as List?)!;
-          final PlaybackSpeedMessage? arg_msg =
-              (args[0] as PlaybackSpeedMessage?);
-          assert(arg_msg != null,
-              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setPlaybackSpeed was null, expected non-null PlaybackSpeedMessage.');
+          final int? arg_textureId = (args[0] as int?);
+          assert(arg_textureId != null,
+              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setPlaybackSpeed was null, expected non-null int.');
+          final double? arg_speed = (args[1] as double?);
+          assert(arg_speed != null,
+              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setPlaybackSpeed was null, expected non-null double.');
           try {
-            api.setPlaybackSpeed(arg_msg!);
+            api.setPlaybackSpeed(arg_textureId!, arg_speed!);
             return wrapResponse(empty: true);
           } on PlatformException catch (e) {
             return wrapResponse(error: e);
@@ -307,11 +285,11 @@ abstract class TestHostVideoPlayerApi {
           assert(message != null,
               'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.play was null.');
           final List args = (message as List?)!;
-          final TextureMessage? arg_msg = (args[0] as TextureMessage?);
-          assert(arg_msg != null,
-              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.play was null, expected non-null TextureMessage.');
+          final int? arg_textureId = (args[0] as int?);
+          assert(arg_textureId != null,
+              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.play was null, expected non-null int.');
           try {
-            api.play(arg_msg!);
+            api.play(arg_textureId!);
             return wrapResponse(empty: true);
           } on PlatformException catch (e) {
             return wrapResponse(error: e);
@@ -339,11 +317,11 @@ abstract class TestHostVideoPlayerApi {
           assert(message != null,
               'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.position was null.');
           final List args = (message as List?)!;
-          final TextureMessage? arg_msg = (args[0] as TextureMessage?);
-          assert(arg_msg != null,
-              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.position was null, expected non-null TextureMessage.');
+          final int? arg_textureId = (args[0] as int?);
+          assert(arg_textureId != null,
+              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.position was null, expected non-null int.');
           try {
-            final PositionMessage output = api.position(arg_msg!);
+            final int output = api.position(arg_textureId!);
             return [output];
           } on PlatformException catch (e) {
             return wrapResponse(error: e);
@@ -371,11 +349,14 @@ abstract class TestHostVideoPlayerApi {
           assert(message != null,
               'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.seekTo was null.');
           final List args = (message as List?)!;
-          final PositionMessage? arg_msg = (args[0] as PositionMessage?);
-          assert(arg_msg != null,
-              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.seekTo was null, expected non-null PositionMessage.');
+          final int? arg_textureId = (args[0] as int?);
+          assert(arg_textureId != null,
+              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.seekTo was null, expected non-null int.');
+          final int? arg_position = (args[1] as int?);
+          assert(arg_position != null,
+              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.seekTo was null, expected non-null int.');
           try {
-            api.seekTo(arg_msg!);
+            api.seekTo(arg_textureId!, arg_position!);
             return wrapResponse(empty: true);
           } on PlatformException catch (e) {
             return wrapResponse(error: e);
@@ -403,11 +384,11 @@ abstract class TestHostVideoPlayerApi {
           assert(message != null,
               'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.pause was null.');
           final List args = (message as List?)!;
-          final TextureMessage? arg_msg = (args[0] as TextureMessage?);
-          assert(arg_msg != null,
-              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.pause was null, expected non-null TextureMessage.');
+          final int? arg_textureId = (args[0] as int?);
+          assert(arg_textureId != null,
+              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.pause was null, expected non-null int.');
           try {
-            api.pause(arg_msg!);
+            api.pause(arg_textureId!);
             return wrapResponse(empty: true);
           } on PlatformException catch (e) {
             return wrapResponse(error: e);
@@ -435,12 +416,11 @@ abstract class TestHostVideoPlayerApi {
           assert(message != null,
               'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setMixWithOthers was null.');
           final List args = (message as List?)!;
-          final MixWithOthersMessage? arg_msg =
-              (args[0] as MixWithOthersMessage?);
-          assert(arg_msg != null,
-              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setMixWithOthers was null, expected non-null MixWithOthersMessage.');
+          final bool? arg_mixWithOthers = (args[0] as bool?);
+          assert(arg_mixWithOthers != null,
+              'Argument for dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setMixWithOthers was null, expected non-null bool.');
           try {
-            api.setMixWithOthers(arg_msg!);
+            api.setMixWithOthers(arg_mixWithOthers!);
             return wrapResponse(empty: true);
           } on PlatformException catch (e) {
             return wrapResponse(error: e);
diff --git a/packages/video_player/video_player_web/CHANGELOG.md b/packages/video_player/video_player_web/CHANGELOG.md
index 39ffe350ed2d..20635077c16c 100644
--- a/packages/video_player/video_player_web/CHANGELOG.md
+++ b/packages/video_player/video_player_web/CHANGELOG.md
@@ -1,6 +1,7 @@
-## NEXT
+## 2.3.3
 
 * Updates minimum supported SDK version to Flutter 3.22/Dart 3.4.
+* Corrects the behavior of muting/unmuting videos in Chrome's Tap Emulation mode.
 
 ## 2.3.2
 
diff --git a/packages/video_player/video_player_web/example/integration_test/video_player_test.dart b/packages/video_player/video_player_web/example/integration_test/video_player_test.dart
index 51199ba79d2b..b78de966fe81 100644
--- a/packages/video_player/video_player_web/example/integration_test/video_player_test.dart
+++ b/packages/video_player/video_player_web/example/integration_test/video_player_test.dart
@@ -44,9 +44,14 @@ void main() {
       final VideoPlayer player = VideoPlayer(videoElement: video)..initialize();
 
       player.setVolume(0);
-
-      expect(video.volume, isZero, reason: 'Volume should be zero');
       expect(video.muted, isTrue, reason: 'muted attribute should be true');
+      // If the volume is set to zero, pressing unmute
+      // button may not restore the audio as expected.
+      expect(video.volume, greaterThan(0),
+          reason: 'Volume should not be set to zero when muted');
+      player.setVolume(0.5);
+      expect(video.volume, 0.5, reason: 'Volume should be set to 0.5');
+      expect(video.muted, isFalse, reason: 'Muted attribute should be false');
 
       expect(() {
         player.setVolume(-0.0001);
diff --git a/packages/video_player/video_player_web/lib/src/video_player.dart b/packages/video_player/video_player_web/lib/src/video_player.dart
index 72f4b7dc155b..6ef4ee1939e8 100644
--- a/packages/video_player/video_player_web/lib/src/video_player.dart
+++ b/packages/video_player/video_player_web/lib/src/video_player.dart
@@ -8,7 +8,6 @@ import 'dart:js_interop';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:video_player_platform_interface/video_player_platform_interface.dart';
-import 'package:web/helpers.dart';
 import 'package:web/web.dart' as web;
 
 import 'duration_utils.dart';
@@ -179,8 +178,13 @@ class VideoPlayer {
 
     // TODO(ditman): Do we need to expose a "muted" API?
     // https://github.com/flutter/flutter/issues/60721
-    _videoElement.muted = !(volume > 0.0);
-    _videoElement.volume = volume;
+
+    // If the volume is set to 0.0, only change muted attribute, but don't adjust the volume.
+    _videoElement.muted = volume == 0.0;
+    // Set the volume only if it's greater than 0.0.
+    if (volume > 0.0) {
+      _videoElement.volume = volume;
+    }
   }
 
   /// Sets the playback `speed`.
diff --git a/packages/video_player/video_player_web/pubspec.yaml b/packages/video_player/video_player_web/pubspec.yaml
index 8c51d65859d5..0985ee1297b5 100644
--- a/packages/video_player/video_player_web/pubspec.yaml
+++ b/packages/video_player/video_player_web/pubspec.yaml
@@ -2,7 +2,7 @@ name: video_player_web
 description: Web platform implementation of video_player.
 repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player_web
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22
-version: 2.3.2
+version: 2.3.3
 
 environment:
   sdk: ^3.4.0
diff --git a/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart
index e9d38e420f44..8a3477d4031b 100644
--- a/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart
+++ b/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart
@@ -22,7 +22,8 @@ import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
 Future main() async {
   IntegrationTestWidgetsFlutterBinding.ensureInitialized();
 
-  final HttpServer server = await HttpServer.bind(InternetAddress.anyIPv4, 0);
+  final HttpServer server =
+      await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
   unawaited(server.forEach((HttpRequest request) {
     if (request.uri.path == '/hello.txt') {
       request.response.writeln('Hello, world.');
diff --git a/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test_legacy.dart b/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test_legacy.dart
index 076c103bc2f8..46349b202e64 100644
--- a/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test_legacy.dart
+++ b/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test_legacy.dart
@@ -20,7 +20,8 @@ import 'package:webview_flutter/src/webview_flutter_legacy.dart';
 Future main() async {
   IntegrationTestWidgetsFlutterBinding.ensureInitialized();
 
-  final HttpServer server = await HttpServer.bind(InternetAddress.anyIPv4, 0);
+  final HttpServer server =
+      await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
   unawaited(server.forEach((HttpRequest request) {
     if (request.uri.path == '/hello.txt') {
       request.response.writeln('Hello, world.');
diff --git a/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart b/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart
index 2d8297fb5fd5..d18987223a11 100644
--- a/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart
+++ b/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart
@@ -60,7 +60,6 @@ class WebWebViewController extends PlatformWebViewController {
 
   @override
   Future loadHtmlString(String html, {String? baseUrl}) async {
-    // ignore: unsafe_html
     _webWebViewParams.iFrame.src = Uri.dataFromString(
       html,
       mimeType: 'text/html',
@@ -78,7 +77,6 @@ class WebWebViewController extends PlatformWebViewController {
     if (params.headers.isEmpty &&
         (params.body == null || params.body!.isEmpty) &&
         params.method == LoadRequestMethod.get) {
-      // ignore: unsafe_html
       _webWebViewParams.iFrame.src = params.uri.toString();
     } else {
       await _updateIFrameFromXhr(params);
@@ -99,7 +97,6 @@ class WebWebViewController extends PlatformWebViewController {
     final ContentType contentType = ContentType.parse(header);
     final Encoding encoding = Encoding.getByName(contentType.charset) ?? utf8;
 
-    // ignore: unsafe_html
     _webWebViewParams.iFrame.src = Uri.dataFromString(
       (await response.text().toDart).toDart,
       mimeType: contentType.mimeType,
diff --git a/packages/webview_flutter/webview_flutter_web/lib/src/webview_flutter_web_legacy.dart b/packages/webview_flutter/webview_flutter_web/lib/src/webview_flutter_web_legacy.dart
index 460323e4e267..4471ce6fed66 100644
--- a/packages/webview_flutter/webview_flutter_web/lib/src/webview_flutter_web_legacy.dart
+++ b/packages/webview_flutter/webview_flutter_web/lib/src/webview_flutter_web_legacy.dart
@@ -36,7 +36,6 @@ class WebWebViewPlatform implements WebViewPlatform {
         iFrame.style.border = 'none';
         final String? initialUrl = creationParams.initialUrl;
         if (initialUrl != null) {
-          // ignore: unsafe_html
           iFrame.src = initialUrl;
         }
         if (onWebViewPlatformCreated != null) {
@@ -127,7 +126,6 @@ class WebWebViewPlatformController implements WebViewPlatformController {
 
   @override
   Future loadUrl(String url, Map? headers) async {
-    // ignore: unsafe_html
     _element.src = url;
   }
 
@@ -176,7 +174,6 @@ class WebWebViewPlatformController implements WebViewPlatformController {
     String html, {
     String? baseUrl,
   }) async {
-    // ignore: unsafe_html
     _element.src = Uri.dataFromString(
       html,
       mimeType: 'text/html',
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/legacy/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/legacy/webview_flutter_test.dart
index 10d6514582bf..47c6876d13d9 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/legacy/webview_flutter_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/legacy/webview_flutter_test.dart
@@ -29,7 +29,8 @@ const bool skipOnIosFor154676 = true;
 Future main() async {
   IntegrationTestWidgetsFlutterBinding.ensureInitialized();
 
-  final HttpServer server = await HttpServer.bind(InternetAddress.anyIPv4, 0);
+  final HttpServer server =
+      await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
   unawaited(server.forEach((HttpRequest request) {
     if (request.uri.path == '/hello.txt') {
       request.response.writeln('Hello, world.');
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart
index 84bb246580f0..7ca004d40786 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart
@@ -24,7 +24,8 @@ import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
 Future main() async {
   IntegrationTestWidgetsFlutterBinding.ensureInitialized();
 
-  final HttpServer server = await HttpServer.bind(InternetAddress.anyIPv4, 0);
+  final HttpServer server =
+      await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
   unawaited(server.forEach((HttpRequest request) {
     if (request.uri.path == '/hello.txt') {
       request.response.writeln('Hello, world.');
diff --git a/script/configs/temp_exclude_excerpt.yaml b/script/configs/temp_exclude_excerpt.yaml
index 25580a780f97..3d39abc136bb 100644
--- a/script/configs/temp_exclude_excerpt.yaml
+++ b/script/configs/temp_exclude_excerpt.yaml
@@ -7,6 +7,5 @@
 # https://github.com/flutter/flutter/issues/102679
 - espresso
 - in_app_purchase/in_app_purchase
-- palette_generator
 - pointer_interceptor
 - quick_actions/quick_actions
diff --git a/script/tool/lib/src/create_all_packages_app_command.dart b/script/tool/lib/src/create_all_packages_app_command.dart
index ee1804fc1420..ab6b5637dd7b 100644
--- a/script/tool/lib/src/create_all_packages_app_command.dart
+++ b/script/tool/lib/src/create_all_packages_app_command.dart
@@ -217,7 +217,13 @@ class CreateAllPackagesAppCommand extends PackageCommand {
     final File gradleFile = app
         .platformDirectory(FlutterPlatform.android)
         .childDirectory('app')
-        .childFile('build.gradle');
+        .listSync()
+        .whereType()
+        .firstWhere(
+          (File file) => file.basename.startsWith('build.gradle'),
+        );
+
+    final bool gradleFileIsKotlin = gradleFile.basename.endsWith('kts');
 
     // Ensure that there is a dependencies section, so the dependencies addition
     // below will work.
@@ -229,18 +235,18 @@ dependencies {}
 ''');
     }
 
-    const String lifecycleDependency =
-        "    implementation 'androidx.lifecycle:lifecycle-runtime:2.2.0-rc01'";
+    final String lifecycleDependency = gradleFileIsKotlin
+        ? '    implementation("androidx.lifecycle:lifecycle-runtime:2.2.0-rc01")'
+        : "    implementation 'androidx.lifecycle:lifecycle-runtime:2.2.0-rc01'";
 
     _adjustFile(
       gradleFile,
       replacements: >{
-        // minSdkVersion 21 is required by camera_android.
-        'minSdkVersion': ['minSdkVersion 21'],
-        'compileSdkVersion': ['compileSdk 34'],
-      },
-      additions: >{
-        'defaultConfig {': ['        multiDexEnabled true'],
+        if (gradleFileIsKotlin)
+          'compileSdk': ['compileSdk = 34']
+        else ...>{
+          'compileSdkVersion': ['compileSdk 34'],
+        }
       },
       regexReplacements: >{
         // Tests for https://github.com/flutter/flutter/issues/43383
@@ -273,7 +279,7 @@ dependencies {}
     final VersionConstraint dartSdkConstraint =
         originalPubspec.environment?[dartSdkKey] ??
             VersionConstraint.compatibleWith(
-              Version.parse('2.12.0'),
+              Version.parse('3.0.0'),
             );
 
     final Map pluginDeps =
@@ -297,15 +303,15 @@ dependencies {}
     // An application cannot depend directly on multiple federated
     // implementations of the same plugin for the same platform, which means the
     // app cannot directly depend on both camera_android and
-    // camera_android_androidx. Since camera_android is endorsed, it will be
-    // included transitively already, so exclude it from the direct dependency
-    // list to allow including camera_android_androidx to ensure that they don't
-    // conflict at build time (if they did, it would be impossible to use
-    // camera_android_androidx while camera_android is endorsed).
+    // camera_android_androidx. Since camera_android_androidx is endorsed, it
+    // will be included transitively already, so exclude it from the direct
+    // dependency list to allow including camera_android to ensure that they
+    // don't conflict at build time (if they did, it would be impossible to use
+    // camera_android while camera_android_androidx is endorsed).
     // This is special-cased here, rather than being done via the normal
     // exclusion config file mechanism, because it still needs to be in the
     // depenedency overrides list to ensure that the version from path is used.
-    pubspec.dependencies.remove('camera_android');
+    pubspec.dependencies.remove('camera_android_camerax');
 
     app.pubspecFile.writeAsStringSync(_pubspecToString(pubspec));
   }
diff --git a/script/tool/lib/src/license_check_command.dart b/script/tool/lib/src/license_check_command.dart
index 5f01cca7b967..40e716591b3a 100644
--- a/script/tool/lib/src/license_check_command.dart
+++ b/script/tool/lib/src/license_check_command.dart
@@ -42,6 +42,13 @@ const Set _ignoredFullBasenameList = {
   'resource.h', // Generated by VS.
 };
 
+// Third-party packages where the code doesn't have file-level annotation, just
+// the package-level LICENSE file. Each entry must be a directory relative to
+// third_party/packages, as that is the only directory where this is allowed.
+const Set _unannotatedFileThirdPartyDirectories = {
+  'path_parsing',
+};
+
 // Copyright and license regexes for third-party code.
 //
 // These are intentionally very simple, since there is very little third-party
@@ -69,6 +76,16 @@ final List _thirdPartyLicenseBlockRegexes = [
     r'// Use of this source code is governed by a BSD-style license that can be\n'
     r'// found in the LICENSE file\.\n',
   ),
+  // packages/third_party/path_parsing.
+  RegExp(
+    r'Copyright \(c\) 2018 Dan Field\n\n'
+    r'Permission is hereby granted, free of charge, to any person obtaining a copy\n'
+    r'of this software and associated documentation files \(the "Software"\), to deal\n'
+    r'in the Software without restriction, including without limitation the rights\n'
+    r'to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n'
+    r'copies of the Software, and to permit persons to whom the Software is\n'
+    r'furnished to do so, subject to the following conditions:',
+  ),
 ];
 
 // The exact format of the BSD license that our license files should contain.
@@ -217,10 +234,26 @@ class LicenseCheckCommand extends PackageCommand {
 
     for (final File file in codeFiles) {
       print('Checking ${file.path}');
+      // Some third-party directories have code that doesn't annotate each file,
+      // so for those check the LICENSE file instead. This is done even though
+      // it's redundant to re-check it for each file because it ensures that we
+      // are still validating every file individually, rather than having a
+      // codepath where whole directories of files are ignored, which would have
+      // a much worse failure mode.
+      String content;
+      if (_unannotatedFileThirdPartyDirectories.any(
+          (String dir) => file.path.contains('/third_party/packages/$dir/'))) {
+        Directory packageDir = file.parent;
+        while (packageDir.parent.basename != 'packages') {
+          packageDir = packageDir.parent;
+        }
+        content = await packageDir.childFile('LICENSE').readAsString();
+      } else {
+        content = await file.readAsString();
+      }
       // On Windows, git may auto-convert line endings on checkout; this should
       // still pass since they will be converted back on commit.
-      final String content =
-          (await file.readAsString()).replaceAll('\r\n', '\n');
+      content = content.replaceAll('\r\n', '\n');
 
       final String firstParyLicense =
           firstPartyLicenseBlockByExtension[p.extension(file.path)] ??
diff --git a/script/tool/test/create_all_packages_app_command_test.dart b/script/tool/test/create_all_packages_app_command_test.dart
index 4e9c00599af4..bed615f12b6f 100644
--- a/script/tool/test/create_all_packages_app_command_test.dart
+++ b/script/tool/test/create_all_packages_app_command_test.dart
@@ -222,7 +222,7 @@ project 'Runner', {
     });
 
     test(
-        'pubspec special-cases camera_android to remove it from deps but not overrides',
+        'pubspec special-cases camera_android_camerax to remove it from deps but not overrides',
         () async {
       writeFakeFlutterCreateOutput(testRoot);
       final Directory cameraDir = packagesDir.childDirectory('camera');
@@ -241,16 +241,16 @@ project 'Runner', {
       expect(cameraDependency, isA());
       expect((cameraDependency! as PathDependency).path,
           endsWith('/packages/camera/camera'));
-      expect(cameraCameraXDependency, isA());
-      expect((cameraCameraXDependency! as PathDependency).path,
-          endsWith('/packages/camera/camera_android_camerax'));
-      expect(cameraAndroidDependency, null);
-
-      final Dependency? cameraAndroidOverride =
-          pubspec.dependencyOverrides['camera_android'];
-      expect(cameraAndroidOverride, isA());
-      expect((cameraAndroidOverride! as PathDependency).path,
+      expect(cameraAndroidDependency, isA());
+      expect((cameraAndroidDependency! as PathDependency).path,
           endsWith('/packages/camera/camera_android'));
+      expect(cameraCameraXDependency, null);
+
+      final Dependency? cameraCameraXOverride =
+          pubspec.dependencyOverrides['camera_android_camerax'];
+      expect(cameraCameraXOverride, isA());
+      expect((cameraCameraXOverride! as PathDependency).path,
+          endsWith('/packages/camera/camera_android_camerax'));
     });
 
     test('legacy files are copied when requested', () async {
@@ -342,7 +342,6 @@ android {
           buildGradle,
           containsAll([
             contains('This is the legacy file'),
-            contains('minSdkVersion 21'),
             contains('compileSdk 34'),
           ]));
     });
@@ -376,9 +375,7 @@ android {
       expect(
           buildGradle,
           containsAll([
-            contains('minSdkVersion 21'),
             contains('compileSdk 34'),
-            contains('multiDexEnabled true'),
             contains('androidx.lifecycle:lifecycle-runtime'),
           ]));
     });
diff --git a/third_party/packages/path_parsing/.gitignore b/third_party/packages/path_parsing/.gitignore
new file mode 100644
index 000000000000..43b5f446e6ea
--- /dev/null
+++ b/third_party/packages/path_parsing/.gitignore
@@ -0,0 +1,10 @@
+.DS_Store
+.dart_tool/
+
+.packages
+.pub/
+.idea/
+
+build/
+
+.flutter-plugins
diff --git a/third_party/packages/path_parsing/CHANGELOG.md b/third_party/packages/path_parsing/CHANGELOG.md
new file mode 100644
index 000000000000..72251a67cd1a
--- /dev/null
+++ b/third_party/packages/path_parsing/CHANGELOG.md
@@ -0,0 +1,47 @@
+## 1.0.2
+
+* Transfers the package source from https://github.com/google/process.dart to
+  https://github.com/dnfield/dart_path_parsing.
+
+## 1.0.1
+
+* Fix [bug in arc decomposition](https://github.com/dnfield/flutter_svg/issues/742).
+* Minor code cleanup for analysis warnings.
+
+## 1.0.0
+
+* Stable release.
+
+## 0.2.1
+
+* Performance improvements to parsing.
+
+## 0.2.0
+
+* Stable nullsafe release
+
+## 0.2.0-nullsafety.0
+
+* Nullsafety migration.
+
+## 0.1.4
+
+* Fix implementation of `_PathOffset`'s `==` operator.
+
+## 0.1.3
+
+* Fix a bug in decompose cubic curve - avoid trying to call `toInt()` on `double.infinity`
+* Bump test dependency.
+
+## 0.1.2
+
+* Fix bug with smooth curve commands
+* Add deep testing
+
+## 0.1.1
+
+* Fix link to homepage in pubspec, add example
+
+## 0.1.0
+
+* Initial release, based on the 0.2.4 release of path_drawing
diff --git a/third_party/packages/path_parsing/LICENSE b/third_party/packages/path_parsing/LICENSE
new file mode 100644
index 000000000000..246fd7b208c9
--- /dev/null
+++ b/third_party/packages/path_parsing/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2018 Dan Field
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/third_party/packages/path_parsing/METADATA b/third_party/packages/path_parsing/METADATA
new file mode 100644
index 000000000000..6b54af3ce828
--- /dev/null
+++ b/third_party/packages/path_parsing/METADATA
@@ -0,0 +1,15 @@
+name: "path_parsing"
+description:
+    "A pure Dart parsing library for SVG paths."
+
+third_party {
+  identifier {
+    type: "Git"
+    value: "https://github.com/dnfield/dart_path_parsing/"
+    primary_source: true
+    version: "6785396f6c5528c720adb14833b196e529e78998"
+  }
+  version: "6785396f6c5528c720adb14833b196e529e78998"
+  last_upgrade_date { year: 2024 month: 10 day: 24 }
+  license_type: NOTICE
+}
diff --git a/third_party/packages/path_parsing/README.md b/third_party/packages/path_parsing/README.md
new file mode 100644
index 000000000000..9f725f69396e
--- /dev/null
+++ b/third_party/packages/path_parsing/README.md
@@ -0,0 +1,5 @@
+# path_parsing
+
+Split from the Flutter path drawing library to create a pure Dart parsing
+library for SVG paths and code generation (without dependencies on Flutter
+runtime).
diff --git a/third_party/packages/path_parsing/example/main.dart b/third_party/packages/path_parsing/example/main.dart
new file mode 100644
index 000000000000..1d378235a46e
--- /dev/null
+++ b/third_party/packages/path_parsing/example/main.dart
@@ -0,0 +1,51 @@
+// ignore_for_file: avoid_print
+
+import 'package:path_parsing/path_parsing.dart';
+
+/// A [PathProxy] that dumps Flutter `Path` commands to the console.
+class PathPrinter extends PathProxy {
+  @override
+  void close() {
+    print('Path.close();');
+  }
+
+  @override
+  void cubicTo(
+    double x1,
+    double y1,
+    double x2,
+    double y2,
+    double x3,
+    double y3,
+  ) {
+    print('Path.cubicTo($x1, $y1, $x2, $y2, $x3, $y3);');
+  }
+
+  @override
+  void lineTo(double x, double y) {
+    print('Path.lineTo($x, $y);');
+  }
+
+  @override
+  void moveTo(double x, double y) {
+    print('Path.moveTo($x, $y);');
+  }
+}
+
+void main() {
+  const String pathData =
+      'M22.1595 3.80852C19.6789 1.35254 16.3807 -4.80966e-07 12.8727 '
+      '-4.80966e-07C9.36452 -4.80966e-07 6.06642 1.35254 3.58579 '
+      '3.80852C1.77297 5.60333 0.53896 7.8599 0.0171889 10.3343C-0.0738999 '
+      '10.7666 0.206109 11.1901 0.64265 11.2803C1.07908 11.3706 1.50711 11.0934 '
+      '1.5982 10.661C2.05552 8.49195 3.13775 6.51338 4.72783 4.9391C9.21893 '
+      '0.492838 16.5262 0.492728 21.0173 4.9391C25.5082 9.38548 25.5082 16.6202 '
+      '21.0173 21.0667C16.5265 25.5132 9.21893 25.5133 4.72805 21.0669C3.17644 '
+      '19.5307 2.10538 17.6035 1.63081 15.4937C1.53386 15.0627 1.10252 14.7908 '
+      '0.66697 14.887C0.231645 14.983 -0.0427272 15.4103 0.0542205 '
+      '15.8413C0.595668 18.2481 1.81686 20.4461 3.5859 22.1976C6.14623 '
+      '24.7325 9.50955 26 12.8727 26C16.236 26 19.5991 24.7326 22.1595 '
+      '22.1976C27.2802 17.1277 27.2802 8.87841 22.1595 3.80852Z';
+
+  writeSvgPathDataToPath(pathData, PathPrinter());
+}
diff --git a/third_party/packages/path_parsing/example/pubspec.yaml b/third_party/packages/path_parsing/example/pubspec.yaml
new file mode 100644
index 000000000000..dd9a6eef8dcb
--- /dev/null
+++ b/third_party/packages/path_parsing/example/pubspec.yaml
@@ -0,0 +1,9 @@
+name: path_parsing_example
+publish_to: none
+
+environment:
+  sdk: ^3.3.0
+
+dependencies:
+  path_parsing:
+    path: ../
diff --git a/third_party/packages/path_parsing/lib/path_parsing.dart b/third_party/packages/path_parsing/lib/path_parsing.dart
new file mode 100644
index 000000000000..dd0ef045b241
--- /dev/null
+++ b/third_party/packages/path_parsing/lib/path_parsing.dart
@@ -0,0 +1 @@
+export 'src/path_parsing.dart';
diff --git a/third_party/packages/path_parsing/lib/src/path_parsing.dart b/third_party/packages/path_parsing/lib/src/path_parsing.dart
new file mode 100644
index 000000000000..1a750a861c6a
--- /dev/null
+++ b/third_party/packages/path_parsing/lib/src/path_parsing.dart
@@ -0,0 +1,773 @@
+// This code has been "translated" largely from the Chromium/blink source
+// for SVG path parsing.
+// The following files can be cross referenced to the classes and methods here:
+//   * https://github.com/chromium/chromium/blob/master/third_party/blink/renderer/core/svg/svg_parser_utilities.cc
+//   * https://github.com/chromium/chromium/blob/master/third_party/blink/renderer/core/svg/svg_parser_utilities.h
+//   * https://github.com/chromium/chromium/blob/master/third_party/blink/renderer/core/svg/svg_path_string_source.cc
+//   * https://github.com/chromium/chromium/blob/master/third_party/blink/renderer/core/svg/svg_path_string_source.h
+//   * https://github.com/chromium/chromium/blob/master/third_party/blink/renderer/core/svg/svg_path_parser.cc
+//   * https://github.com/chromium/chromium/blob/master/third_party/blink/renderer/core/svg/svg_path_parser.h
+//   * https://github.com/chromium/chromium/blob/master/third_party/blink/renderer/core/html/parser/html_parser_idioms.h (IsHTMLSpace)
+//   * https://github.com/chromium/chromium/blob/master/third_party/blink/renderer/core/svg/svg_path_parser_test.cc
+
+// TODO(stuartmorgan): Remove public_member_api_docs, adding documentation for
+//  all public members.
+// TODO(stuartmorgan): Remove library_private_types_in_public_api and do a
+//  breaking change to not use _PathOffset in public APIs.
+// ignore_for_file: public_member_api_docs, library_private_types_in_public_api
+
+import 'dart:math' as math show atan2, cos, max, pi, pow, sin, sqrt, tan;
+
+import 'package:meta/meta.dart';
+import 'package:vector_math/vector_math.dart' show Matrix4, radians;
+
+import './path_segment_type.dart';
+
+/// Parse `svg`, emitting the segment data to `path`.
+void writeSvgPathDataToPath(String? svg, PathProxy path) {
+  if (svg == null || svg == '') {
+    return;
+  }
+
+  final SvgPathStringSource parser = SvgPathStringSource(svg);
+  final SvgPathNormalizer normalizer = SvgPathNormalizer();
+  for (final PathSegmentData seg in parser.parseSegments()) {
+    normalizer.emitSegment(seg, path);
+  }
+}
+
+/// A receiver for normalized [PathSegmentData].
+abstract class PathProxy {
+  void moveTo(double x, double y);
+  void lineTo(double x, double y);
+  void cubicTo(
+    double x1,
+    double y1,
+    double x2,
+    double y2,
+    double x3,
+    double y3,
+  );
+  void close();
+}
+
+/// Provides a minimal implementation of a [Point] or [Offset].
+// Takes care of a few things Point doesn't, without requiring Flutter as dependency
+@immutable
+class _PathOffset {
+  const _PathOffset(this.dx, this.dy)
+      : assert(dx != null), // ignore: unnecessary_null_comparison
+        assert(dy != null); // ignore: unnecessary_null_comparison
+
+  static _PathOffset get zero => const _PathOffset(0.0, 0.0);
+  final double dx;
+  final double dy;
+
+  double get direction => math.atan2(dy, dx);
+
+  _PathOffset translate(double translateX, double translateY) =>
+      _PathOffset(dx + translateX, dy + translateY);
+
+  _PathOffset operator +(_PathOffset other) =>
+      _PathOffset(dx + other.dx, dy + other.dy);
+  _PathOffset operator -(_PathOffset other) =>
+      _PathOffset(dx - other.dx, dy - other.dy);
+
+  _PathOffset operator *(double operand) =>
+      _PathOffset(dx * operand, dy * operand);
+
+  @override
+  String toString() => 'PathOffset{$dx,$dy}';
+
+  @override
+  bool operator ==(Object other) {
+    return other is _PathOffset && other.dx == dx && other.dy == dy;
+  }
+
+  // TODO(dnfield): Use a real hashing function - but this should at least be better than the default.
+  @override
+  int get hashCode => (((17 * 23) ^ dx.hashCode) * 23) ^ dy.hashCode;
+}
+
+const double _twoPiFloat = math.pi * 2.0;
+const double _piOverTwoFloat = math.pi / 2.0;
+
+class SvgPathStringSource {
+  SvgPathStringSource(this._string)
+      : assert(_string != null), // ignore: unnecessary_null_comparison
+        _previousCommand = SvgPathSegType.unknown,
+        _idx = 0,
+        _length = _string.length {
+    _skipOptionalSvgSpaces();
+  }
+
+  final String _string;
+
+  SvgPathSegType _previousCommand;
+  int _idx;
+  final int _length;
+
+  bool _isHtmlSpace(int character) {
+    // Histogram from Apple's page load test combined with some ad hoc browsing
+    // some other test suites.
+    //
+    //     82%: 216330 non-space characters, all > U+0020
+    //     11%:  30017 plain space characters, U+0020
+    //      5%:  12099 newline characters, U+000A
+    //      2%:   5346 tab characters, U+0009
+    //
+    // No other characters seen. No U+000C or U+000D, and no other control
+    // characters. Accordingly, we check for non-spaces first, then space, then
+    // newline, then tab, then the other characters.
+
+    return character <= AsciiConstants.space &&
+        (character == AsciiConstants.space ||
+            character == AsciiConstants.slashN ||
+            character == AsciiConstants.slashT ||
+            character == AsciiConstants.slashR ||
+            character == AsciiConstants.slashF);
+  }
+
+  /// Increments _idx to the first non-space character.
+  ///
+  /// Returns the code unit of the first non-space, or -1 if at end of string.
+  int _skipOptionalSvgSpaces() {
+    while (true) {
+      if (_idx >= _length) {
+        return -1;
+      }
+
+      final int c = _string.codeUnitAt(_idx);
+      if (!_isHtmlSpace(c)) {
+        return c;
+      }
+
+      _idx++;
+    }
+  }
+
+  void _skipOptionalSvgSpacesOrDelimiter(
+      [int delimiter = AsciiConstants.comma]) {
+    final int c = _skipOptionalSvgSpaces();
+    if (c == delimiter) {
+      _idx++;
+      _skipOptionalSvgSpaces();
+    }
+  }
+
+  static bool _isNumberStart(int lookahead) {
+    return (lookahead >= AsciiConstants.number0 &&
+            lookahead <= AsciiConstants.number9) ||
+        lookahead == AsciiConstants.plus ||
+        lookahead == AsciiConstants.minus ||
+        lookahead == AsciiConstants.period;
+  }
+
+  SvgPathSegType _maybeImplicitCommand(
+    int lookahead,
+    SvgPathSegType nextCommand,
+  ) {
+    // Check if the current lookahead may start a number - in which case it
+    // could be the start of an implicit command. The 'close' command does not
+    // have any parameters though and hence can't have an implicit
+    // 'continuation'.
+    if (!_isNumberStart(lookahead) ||
+        _previousCommand == SvgPathSegType.close) {
+      return nextCommand;
+    }
+    // Implicit continuations of moveto command translate to linetos.
+    if (_previousCommand == SvgPathSegType.moveToAbs) {
+      return SvgPathSegType.lineToAbs;
+    }
+    if (_previousCommand == SvgPathSegType.moveToRel) {
+      return SvgPathSegType.lineToRel;
+    }
+    return _previousCommand;
+  }
+
+  bool _isValidRange(double x) =>
+      -double.maxFinite <= x && x <= double.maxFinite;
+
+  bool _isValidExponent(double x) => -37 <= x && x <= 38;
+
+  /// Reads a code unit and advances the index.
+  ///
+  /// Returns -1 if at end of string.
+  @pragma('vm:prefer-inline')
+  int _readCodeUnit() {
+    if (_idx >= _length) {
+      return -1;
+    }
+    return _string.codeUnitAt(_idx++);
+  }
+
+  // We use this generic parseNumber function to allow the Path parsing code to
+  // work at a higher precision internally, without any unnecessary runtime cost
+  // or code complexity.
+  double _parseNumber() {
+    _skipOptionalSvgSpaces();
+
+    // Read the sign.
+    int sign = 1;
+    int c = _readCodeUnit();
+    if (c == AsciiConstants.plus) {
+      c = _readCodeUnit();
+    } else if (c == AsciiConstants.minus) {
+      sign = -1;
+      c = _readCodeUnit();
+    }
+
+    if ((c < AsciiConstants.number0 || c > AsciiConstants.number9) &&
+        c != AsciiConstants.period) {
+      throw StateError('First character of a number must be one of [0-9+-.].');
+    }
+
+    // Read the integer part, build left-to-right.
+    double integer = 0.0;
+    while (AsciiConstants.number0 <= c && c <= AsciiConstants.number9) {
+      integer = integer * 10 + (c - AsciiConstants.number0);
+      c = _readCodeUnit();
+    }
+
+    // Bail out early if this overflows.
+    if (!_isValidRange(integer)) {
+      throw StateError('Numeric overflow');
+    }
+
+    double decimal = 0.0;
+    if (c == AsciiConstants.period) {
+      // read the decimals
+      c = _readCodeUnit();
+
+      // There must be a least one digit following the .
+      if (c < AsciiConstants.number0 || c > AsciiConstants.number9) {
+        throw StateError('There must be at least one digit following the .');
+      }
+
+      double frac = 1.0;
+      while (AsciiConstants.number0 <= c && c <= AsciiConstants.number9) {
+        frac *= 0.1;
+        decimal += (c - AsciiConstants.number0) * frac;
+        c = _readCodeUnit();
+      }
+    }
+
+    double number = integer + decimal;
+    number *= sign;
+
+    // read the exponent part
+    if (_idx < _length &&
+        (c == AsciiConstants.lowerE || c == AsciiConstants.upperE) &&
+        (_string.codeUnitAt(_idx) != AsciiConstants.lowerX &&
+            _string.codeUnitAt(_idx) != AsciiConstants.lowerM)) {
+      c = _readCodeUnit();
+
+      // read the sign of the exponent
+      bool exponentIsNegative = false;
+      if (c == AsciiConstants.plus) {
+        c = _readCodeUnit();
+      } else if (c == AsciiConstants.minus) {
+        c = _readCodeUnit();
+        exponentIsNegative = true;
+      }
+
+      // There must be an exponent
+      if (c < AsciiConstants.number0 || c > AsciiConstants.number9) {
+        throw StateError('Missing exponent');
+      }
+
+      double exponent = 0.0;
+      while (c >= AsciiConstants.number0 && c <= AsciiConstants.number9) {
+        exponent *= 10.0;
+        exponent += c - AsciiConstants.number0;
+        c = _readCodeUnit();
+      }
+      if (exponentIsNegative) {
+        exponent = -exponent;
+      }
+      // Make sure exponent is valid.
+      if (!_isValidExponent(exponent)) {
+        throw StateError('Invalid exponent $exponent');
+      }
+      if (exponent != 0) {
+        number *= math.pow(10.0, exponent);
+      }
+    }
+
+    // Don't return Infinity() or NaN().
+    if (!_isValidRange(number)) {
+      throw StateError('Numeric overflow');
+    }
+
+    // At this stage, c contains an unprocessed character, and _idx has
+    // already been incremented.
+
+    // If c == -1, the input was already at the end of the string, so no
+    // further processing needs to occur.
+    if (c != -1) {
+      --_idx; // Put the unprocessed character back.
+
+      // if (mode & kAllowTrailingWhitespace)
+      _skipOptionalSvgSpacesOrDelimiter();
+    }
+    return number;
+  }
+
+  bool _parseArcFlag() {
+    if (!hasMoreData) {
+      throw StateError('Expected more data');
+    }
+    final int flagChar = _string.codeUnitAt(_idx++);
+    _skipOptionalSvgSpacesOrDelimiter();
+
+    if (flagChar == AsciiConstants.number0) {
+      return false;
+    } else if (flagChar == AsciiConstants.number1) {
+      return true;
+    } else {
+      throw StateError('Invalid flag value');
+    }
+  }
+
+  bool get hasMoreData => _idx < _length;
+
+  Iterable parseSegments() sync* {
+    while (hasMoreData) {
+      yield parseSegment();
+    }
+  }
+
+  PathSegmentData parseSegment() {
+    assert(hasMoreData);
+    final PathSegmentData segment = PathSegmentData();
+    final int lookahead = _string.codeUnitAt(_idx);
+    SvgPathSegType command = AsciiConstants.mapLetterToSegmentType(lookahead);
+    if (_previousCommand == SvgPathSegType.unknown) {
+      // First command has to be a moveto.
+      if (command != SvgPathSegType.moveToRel &&
+          command != SvgPathSegType.moveToAbs) {
+        throw StateError('Expected to find moveTo command');
+      }
+      // Consume command letter.
+      _idx++;
+    } else if (command == SvgPathSegType.unknown) {
+      // Possibly an implicit command.
+      assert(_previousCommand != SvgPathSegType.unknown);
+      command = _maybeImplicitCommand(lookahead, command);
+      if (command == SvgPathSegType.unknown) {
+        throw StateError('Expected a path command');
+      }
+    } else {
+      // Valid explicit command.
+      _idx++;
+    }
+
+    segment.command = _previousCommand = command;
+
+    switch (segment.command) {
+      case SvgPathSegType.cubicToRel:
+      case SvgPathSegType.cubicToAbs:
+        segment.point1 = _PathOffset(_parseNumber(), _parseNumber());
+        continue cubic_smooth;
+      case SvgPathSegType.smoothCubicToRel:
+      cubic_smooth:
+      case SvgPathSegType.smoothCubicToAbs:
+        segment.point2 = _PathOffset(_parseNumber(), _parseNumber());
+        continue quad_smooth;
+      case SvgPathSegType.moveToRel:
+      case SvgPathSegType.moveToAbs:
+      case SvgPathSegType.lineToRel:
+      case SvgPathSegType.lineToAbs:
+      case SvgPathSegType.smoothQuadToRel:
+      quad_smooth:
+      case SvgPathSegType.smoothQuadToAbs:
+        segment.targetPoint = _PathOffset(_parseNumber(), _parseNumber());
+      case SvgPathSegType.lineToHorizontalRel:
+      case SvgPathSegType.lineToHorizontalAbs:
+        segment.targetPoint =
+            _PathOffset(_parseNumber(), segment.targetPoint.dy);
+      case SvgPathSegType.lineToVerticalRel:
+      case SvgPathSegType.lineToVerticalAbs:
+        segment.targetPoint =
+            _PathOffset(segment.targetPoint.dx, _parseNumber());
+      case SvgPathSegType.close:
+        _skipOptionalSvgSpaces();
+      case SvgPathSegType.quadToRel:
+      case SvgPathSegType.quadToAbs:
+        segment.point1 = _PathOffset(_parseNumber(), _parseNumber());
+        segment.targetPoint = _PathOffset(_parseNumber(), _parseNumber());
+      case SvgPathSegType.arcToRel:
+      case SvgPathSegType.arcToAbs:
+        segment.point1 = _PathOffset(_parseNumber(), _parseNumber());
+        segment.arcAngle = _parseNumber();
+        segment.arcLarge = _parseArcFlag();
+        segment.arcSweep = _parseArcFlag();
+        segment.targetPoint = _PathOffset(_parseNumber(), _parseNumber());
+      case SvgPathSegType.unknown:
+        throw StateError('Unknown segment command');
+    }
+
+    return segment;
+  }
+}
+
+_PathOffset reflectedPoint(
+    _PathOffset reflectedIn, _PathOffset pointToReflect) {
+  return _PathOffset(2 * reflectedIn.dx - pointToReflect.dx,
+      2 * reflectedIn.dy - pointToReflect.dy);
+}
+
+const double _kOneOverThree = 1.0 / 3.0;
+
+/// Blend the points with a ratio (1/3):(2/3).
+_PathOffset blendPoints(_PathOffset p1, _PathOffset p2) {
+  return _PathOffset((p1.dx + 2 * p2.dx) * _kOneOverThree,
+      (p1.dy + 2 * p2.dy) * _kOneOverThree);
+}
+
+bool isCubicCommand(SvgPathSegType command) {
+  return command == SvgPathSegType.cubicToAbs ||
+      command == SvgPathSegType.cubicToRel ||
+      command == SvgPathSegType.smoothCubicToAbs ||
+      command == SvgPathSegType.smoothCubicToRel;
+}
+
+bool isQuadraticCommand(SvgPathSegType command) {
+  return command == SvgPathSegType.quadToAbs ||
+      command == SvgPathSegType.quadToRel ||
+      command == SvgPathSegType.smoothQuadToAbs ||
+      command == SvgPathSegType.smoothQuadToRel;
+}
+
+// TODO(dnfield): This can probably be cleaned up a bit.  Some of this was designed in such a way to pack data/optimize for C++
+// There are probably better/clearer ways to do it for Dart.
+class PathSegmentData {
+  PathSegmentData()
+      : command = SvgPathSegType.unknown,
+        arcSweep = false,
+        arcLarge = false;
+
+  _PathOffset get arcRadii => point1;
+
+  /// Angle in degrees.
+  double get arcAngle => point2.dx;
+
+  /// In degrees.
+  set arcAngle(double angle) => point2 = _PathOffset(angle, point2.dy);
+
+  double get r1 => arcRadii.dx;
+  double get r2 => arcRadii.dy;
+
+  bool get largeArcFlag => arcLarge;
+  bool get sweepFlag => arcSweep;
+
+  double get x => targetPoint.dx;
+  double get y => targetPoint.dy;
+
+  double get x1 => point1.dx;
+  double get y1 => point1.dy;
+
+  double get x2 => point2.dx;
+  double get y2 => point2.dy;
+
+  SvgPathSegType command;
+  _PathOffset targetPoint = _PathOffset.zero;
+  _PathOffset point1 = _PathOffset.zero;
+  _PathOffset point2 = _PathOffset.zero;
+  bool arcSweep;
+  bool arcLarge;
+
+  @override
+  String toString() {
+    return 'PathSegmentData{$command $targetPoint $point1 $point2 $arcSweep $arcLarge}';
+  }
+}
+
+class SvgPathNormalizer {
+  _PathOffset _currentPoint = _PathOffset.zero;
+  _PathOffset _subPathPoint = _PathOffset.zero;
+  _PathOffset _controlPoint = _PathOffset.zero;
+  SvgPathSegType _lastCommand = SvgPathSegType.unknown;
+
+  void emitSegment(PathSegmentData segment, PathProxy path) {
+    final PathSegmentData normSeg = segment;
+    assert(_currentPoint != null); // ignore: unnecessary_null_comparison
+    // Convert relative points to absolute points.
+    switch (segment.command) {
+      case SvgPathSegType.quadToRel:
+        normSeg.point1 += _currentPoint;
+        normSeg.targetPoint += _currentPoint;
+      case SvgPathSegType.cubicToRel:
+        normSeg.point1 += _currentPoint;
+        continue smooth_rel;
+      smooth_rel:
+      case SvgPathSegType.smoothCubicToRel:
+        normSeg.point2 += _currentPoint;
+        continue arc_rel;
+      case SvgPathSegType.moveToRel:
+      case SvgPathSegType.lineToRel:
+      case SvgPathSegType.lineToHorizontalRel:
+      case SvgPathSegType.lineToVerticalRel:
+      case SvgPathSegType.smoothQuadToRel:
+      arc_rel:
+      case SvgPathSegType.arcToRel:
+        normSeg.targetPoint += _currentPoint;
+      case SvgPathSegType.lineToHorizontalAbs:
+        normSeg.targetPoint =
+            _PathOffset(normSeg.targetPoint.dx, _currentPoint.dy);
+      case SvgPathSegType.lineToVerticalAbs:
+        normSeg.targetPoint =
+            _PathOffset(_currentPoint.dx, normSeg.targetPoint.dy);
+      case SvgPathSegType.close:
+        // Reset m_currentPoint for the next path.
+        normSeg.targetPoint = _subPathPoint;
+      // This switch is intentionally non-exhaustive.
+      // ignore: no_default_cases
+      default:
+        break;
+    }
+
+    // Update command verb, handle smooth segments and convert quadratic curve
+    // segments to cubics.
+    switch (segment.command) {
+      case SvgPathSegType.moveToRel:
+      case SvgPathSegType.moveToAbs:
+        _subPathPoint = normSeg.targetPoint;
+        // normSeg.command = SvgPathSegType.moveToAbs;
+        path.moveTo(normSeg.targetPoint.dx, normSeg.targetPoint.dy);
+      case SvgPathSegType.lineToRel:
+      case SvgPathSegType.lineToAbs:
+      case SvgPathSegType.lineToHorizontalRel:
+      case SvgPathSegType.lineToHorizontalAbs:
+      case SvgPathSegType.lineToVerticalRel:
+      case SvgPathSegType.lineToVerticalAbs:
+        // normSeg.command = SvgPathSegType.lineToAbs;
+        path.lineTo(normSeg.targetPoint.dx, normSeg.targetPoint.dy);
+      case SvgPathSegType.close:
+        // normSeg.command = SvgPathSegType.close;
+        path.close();
+      case SvgPathSegType.smoothCubicToRel:
+      case SvgPathSegType.smoothCubicToAbs:
+        if (!isCubicCommand(_lastCommand)) {
+          normSeg.point1 = _currentPoint;
+        } else {
+          normSeg.point1 = reflectedPoint(
+            _currentPoint,
+            _controlPoint,
+          );
+        }
+        continue cubic_abs2;
+      case SvgPathSegType.cubicToRel:
+      cubic_abs2:
+      case SvgPathSegType.cubicToAbs:
+        _controlPoint = normSeg.point2;
+        // normSeg.command = SvgPathSegType.cubicToAbs;
+        path.cubicTo(
+          normSeg.point1.dx,
+          normSeg.point1.dy,
+          normSeg.point2.dx,
+          normSeg.point2.dy,
+          normSeg.targetPoint.dx,
+          normSeg.targetPoint.dy,
+        );
+      case SvgPathSegType.smoothQuadToRel:
+      case SvgPathSegType.smoothQuadToAbs:
+        if (!isQuadraticCommand(_lastCommand)) {
+          normSeg.point1 = _currentPoint;
+        } else {
+          normSeg.point1 = reflectedPoint(
+            _currentPoint,
+            _controlPoint,
+          );
+        }
+        continue quad_abs2;
+      case SvgPathSegType.quadToRel:
+      quad_abs2:
+      case SvgPathSegType.quadToAbs:
+        // Save the unmodified control point.
+        _controlPoint = normSeg.point1;
+        normSeg.point1 = blendPoints(_currentPoint, _controlPoint);
+        normSeg.point2 = blendPoints(
+          normSeg.targetPoint,
+          _controlPoint,
+        );
+        // normSeg.command = SvgPathSegType.cubicToAbs;
+        path.cubicTo(
+          normSeg.point1.dx,
+          normSeg.point1.dy,
+          normSeg.point2.dx,
+          normSeg.point2.dy,
+          normSeg.targetPoint.dx,
+          normSeg.targetPoint.dy,
+        );
+      case SvgPathSegType.arcToRel:
+      case SvgPathSegType.arcToAbs:
+        if (!_decomposeArcToCubic(_currentPoint, normSeg, path)) {
+          // On failure, emit a line segment to the target point.
+          // normSeg.command = SvgPathSegType.lineToAbs;
+          path.lineTo(normSeg.targetPoint.dx, normSeg.targetPoint.dy);
+          // } else {
+          //   // decomposeArcToCubic() has already emitted the normalized
+          //   // segments, so set command to PathSegArcAbs, to skip any further
+          //   // emit.
+          //   // normSeg.command = SvgPathSegType.arcToAbs;
+        }
+      // This switch is intentionally non-exhaustive.
+      // ignore: no_default_cases
+      default:
+        throw StateError('Invalid command type in path');
+    }
+
+    _currentPoint = normSeg.targetPoint;
+
+    if (!isCubicCommand(segment.command) &&
+        !isQuadraticCommand(segment.command)) {
+      _controlPoint = _currentPoint;
+    }
+
+    _lastCommand = segment.command;
+  }
+
+// This works by converting the SVG arc to "simple" beziers.
+// Partly adapted from Niko's code in kdelibs/kdecore/svgicons.
+// See also SVG implementation notes:
+// http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
+  bool _decomposeArcToCubic(
+    _PathOffset currentPoint,
+    PathSegmentData arcSegment,
+    PathProxy path,
+  ) {
+    // If rx = 0 or ry = 0 then this arc is treated as a straight line segment (a
+    // "lineto") joining the endpoints.
+    // http://www.w3.org/TR/SVG/implnote.html#ArcOutOfRangeParameters
+    double rx = arcSegment.arcRadii.dx.abs();
+    double ry = arcSegment.arcRadii.dy.abs();
+    if (rx == 0 || ry == 0) {
+      return false;
+    }
+
+    // If the current point and target point for the arc are identical, it should
+    // be treated as a zero length path. This ensures continuity in animations.
+    if (arcSegment.targetPoint == currentPoint) {
+      return false;
+    }
+
+    final double angle = radians(arcSegment.arcAngle);
+
+    final _PathOffset midPointDistance =
+        (currentPoint - arcSegment.targetPoint) * 0.5;
+
+    final Matrix4 pointTransform = Matrix4.identity();
+    pointTransform.rotateZ(-angle);
+
+    final _PathOffset transformedMidPoint = _mapPoint(
+      pointTransform,
+      _PathOffset(
+        midPointDistance.dx,
+        midPointDistance.dy,
+      ),
+    );
+
+    final double squareRx = rx * rx;
+    final double squareRy = ry * ry;
+    final double squareX = transformedMidPoint.dx * transformedMidPoint.dx;
+    final double squareY = transformedMidPoint.dy * transformedMidPoint.dy;
+
+    // Check if the radii are big enough to draw the arc, scale radii if not.
+    // http://www.w3.org/TR/SVG/implnote.html#ArcCorrectionOutOfRangeRadii
+    final double radiiScale = squareX / squareRx + squareY / squareRy;
+    if (radiiScale > 1.0) {
+      rx *= math.sqrt(radiiScale);
+      ry *= math.sqrt(radiiScale);
+    }
+    pointTransform.setIdentity();
+
+    pointTransform.scale(1.0 / rx, 1.0 / ry);
+    pointTransform.rotateZ(-angle);
+
+    _PathOffset point1 = _mapPoint(pointTransform, currentPoint);
+    _PathOffset point2 = _mapPoint(pointTransform, arcSegment.targetPoint);
+    _PathOffset delta = point2 - point1;
+
+    final double d = delta.dx * delta.dx + delta.dy * delta.dy;
+    final double scaleFactorSquared = math.max(1.0 / d - 0.25, 0.0);
+    double scaleFactor = math.sqrt(scaleFactorSquared);
+    if (!scaleFactor.isFinite) {
+      scaleFactor = 0.0;
+    }
+
+    if (arcSegment.arcSweep == arcSegment.arcLarge) {
+      scaleFactor = -scaleFactor;
+    }
+
+    delta = delta * scaleFactor;
+    final _PathOffset centerPoint =
+        ((point1 + point2) * 0.5).translate(-delta.dy, delta.dx);
+
+    final double theta1 = (point1 - centerPoint).direction;
+    final double theta2 = (point2 - centerPoint).direction;
+
+    double thetaArc = theta2 - theta1;
+
+    if (thetaArc < 0.0 && arcSegment.arcSweep) {
+      thetaArc += _twoPiFloat;
+    } else if (thetaArc > 0.0 && !arcSegment.arcSweep) {
+      thetaArc -= _twoPiFloat;
+    }
+
+    pointTransform.setIdentity();
+    pointTransform.rotateZ(angle);
+    pointTransform.scale(rx, ry);
+
+    // Some results of atan2 on some platform implementations are not exact
+    // enough. So that we get more cubic curves than expected here. Adding 0.001f
+    // reduces the count of segments to the correct count.
+    final int segments = (thetaArc / (_piOverTwoFloat + 0.001)).abs().ceil();
+    for (int i = 0; i < segments; ++i) {
+      final double startTheta = theta1 + i * thetaArc / segments;
+      final double endTheta = theta1 + (i + 1) * thetaArc / segments;
+
+      final double t = (8.0 / 6.0) * math.tan(0.25 * (endTheta - startTheta));
+      if (!t.isFinite) {
+        return false;
+      }
+      final double sinStartTheta = math.sin(startTheta);
+      final double cosStartTheta = math.cos(startTheta);
+      final double sinEndTheta = math.sin(endTheta);
+      final double cosEndTheta = math.cos(endTheta);
+
+      point1 = _PathOffset(
+        cosStartTheta - t * sinStartTheta,
+        sinStartTheta + t * cosStartTheta,
+      ).translate(centerPoint.dx, centerPoint.dy);
+      final _PathOffset targetPoint = _PathOffset(
+        cosEndTheta,
+        sinEndTheta,
+      ).translate(centerPoint.dx, centerPoint.dy);
+      point2 = targetPoint.translate(t * sinEndTheta, -t * cosEndTheta);
+
+      final PathSegmentData cubicSegment = PathSegmentData();
+      cubicSegment.command = SvgPathSegType.cubicToAbs;
+      cubicSegment.point1 = _mapPoint(pointTransform, point1);
+      cubicSegment.point2 = _mapPoint(pointTransform, point2);
+      cubicSegment.targetPoint = _mapPoint(pointTransform, targetPoint);
+
+      path.cubicTo(cubicSegment.x1, cubicSegment.y1, cubicSegment.x2,
+          cubicSegment.y2, cubicSegment.x, cubicSegment.y);
+      //consumer_->EmitSegment(cubicSegment);
+    }
+    return true;
+  }
+
+  _PathOffset _mapPoint(Matrix4 transform, _PathOffset point) {
+    // a, b, 0.0, 0.0, c, d, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, e, f, 0.0, 1.0
+    return _PathOffset(
+      transform.storage[0] * point.dx +
+          transform.storage[4] * point.dy +
+          transform.storage[12],
+      transform.storage[1] * point.dx +
+          transform.storage[5] * point.dy +
+          transform.storage[13],
+    );
+  }
+}
diff --git a/third_party/packages/path_parsing/lib/src/path_segment_type.dart b/third_party/packages/path_parsing/lib/src/path_segment_type.dart
new file mode 100644
index 000000000000..0c2c097cb6d4
--- /dev/null
+++ b/third_party/packages/path_parsing/lib/src/path_segment_type.dart
@@ -0,0 +1,234 @@
+/// SvgPathSegType enumerates the various path segment commands.
+///
+/// [AsciiConstants] houses the ASCII numeric values of these commands
+enum SvgPathSegType {
+  /// Indicates initial state or error
+  unknown,
+
+  /// Z or z
+  close,
+
+  /// M
+  moveToAbs,
+
+  /// m
+  moveToRel,
+
+  /// L
+  lineToAbs,
+
+  /// l
+  lineToRel,
+
+  /// C
+  cubicToAbs,
+
+  /// c
+  cubicToRel,
+
+  /// Q
+  quadToAbs,
+
+  /// q
+  quadToRel,
+
+  /// A
+  arcToAbs,
+
+  /// a
+  arcToRel,
+
+  /// H
+  lineToHorizontalAbs,
+
+  /// h
+  lineToHorizontalRel,
+
+  /// V
+  lineToVerticalAbs,
+
+  /// v
+  lineToVerticalRel,
+
+  /// S
+  smoothCubicToAbs,
+
+  /// s
+  smoothCubicToRel,
+
+  /// T
+  smoothQuadToAbs,
+
+  /// t
+  smoothQuadToRel
+}
+
+/// Character constants used internally.  Note that this parser does not
+/// properly support non-ascii characters in the path, but it does support
+/// unicode encoding.
+///
+/// Only contains values that are used by the parser (does not contain the full
+/// ASCII set).
+class AsciiConstants {
+  const AsciiConstants._();
+
+  /// Returns the segment type corresponding to the letter constant [lookahead].
+  static SvgPathSegType mapLetterToSegmentType(int lookahead) {
+    return AsciiConstants.letterToSegmentType[lookahead] ??
+        SvgPathSegType.unknown;
+  }
+
+  /// Map to go from ASCII constant to [SvgPathSegType]
+  static const Map letterToSegmentType =
+      {
+    upperZ: SvgPathSegType.close,
+    lowerZ: SvgPathSegType.close,
+    upperM: SvgPathSegType.moveToAbs,
+    lowerM: SvgPathSegType.moveToRel,
+    upperL: SvgPathSegType.lineToAbs,
+    lowerL: SvgPathSegType.lineToRel,
+    upperC: SvgPathSegType.cubicToAbs,
+    lowerC: SvgPathSegType.cubicToRel,
+    upperQ: SvgPathSegType.quadToAbs,
+    lowerQ: SvgPathSegType.quadToRel,
+    upperA: SvgPathSegType.arcToAbs,
+    lowerA: SvgPathSegType.arcToRel,
+    upperH: SvgPathSegType.lineToHorizontalAbs,
+    lowerH: SvgPathSegType.lineToHorizontalRel,
+    upperV: SvgPathSegType.lineToVerticalAbs,
+    lowerV: SvgPathSegType.lineToVerticalRel,
+    upperS: SvgPathSegType.smoothCubicToAbs,
+    lowerS: SvgPathSegType.smoothCubicToRel,
+    upperT: SvgPathSegType.smoothQuadToAbs,
+    lowerT: SvgPathSegType.smoothQuadToRel,
+  };
+
+  /// `\t` (horizontal tab).
+  static const int slashT = 9;
+
+  /// `\n` (newline).
+  static const int slashN = 10;
+
+  /// `\f` (form feed).
+  static const int slashF = 12;
+
+  /// `\r` (carriage return).
+  static const int slashR = 13;
+
+  /// ` ` (space).
+  static const int space = 32;
+
+  /// `+` (plus).
+  static const int plus = 43;
+
+  /// `,` (comma).
+  static const int comma = 44;
+
+  /// `-` (minus).
+  static const int minus = 45;
+
+  /// `.` (period).
+  static const int period = 46;
+
+  /// 0 (the number zero).
+  static const int number0 = 48;
+
+  /// 1 (the number one).
+  static const int number1 = 49;
+
+  /// 2 (the number two).
+  static const int number2 = 50;
+
+  /// 3 (the number three).
+  static const int number3 = 51;
+
+  /// 4 (the number four).
+  static const int number4 = 52;
+
+  /// 5 (the number five).
+  static const int number5 = 53;
+
+  /// 6 (the number six).
+  static const int number6 = 54;
+
+  /// 7 (the number seven).
+  static const int number7 = 55;
+
+  /// 8 (the number eight).
+  static const int number8 = 56;
+
+  /// 9 (the number nine).
+  static const int number9 = 57;
+
+  /// A
+  static const int upperA = 65;
+
+  /// C
+  static const int upperC = 67;
+
+  /// E
+  static const int upperE = 69;
+
+  /// H
+  static const int upperH = 72;
+
+  /// L
+  static const int upperL = 76;
+
+  /// M
+  static const int upperM = 77;
+
+  /// Q
+  static const int upperQ = 81;
+
+  /// S
+  static const int upperS = 83;
+
+  /// T
+  static const int upperT = 84;
+
+  /// V
+  static const int upperV = 86;
+
+  /// Z
+  static const int upperZ = 90;
+
+  /// a
+  static const int lowerA = 97;
+
+  /// c
+  static const int lowerC = 99;
+
+  /// e
+  static const int lowerE = 101;
+
+  /// h
+  static const int lowerH = 104;
+
+  /// l
+  static const int lowerL = 108;
+
+  /// m
+  static const int lowerM = 109;
+
+  /// q
+  static const int lowerQ = 113;
+
+  /// s
+  static const int lowerS = 115;
+
+  /// t
+  static const int lowerT = 116;
+
+  /// v
+  static const int lowerV = 118;
+
+  /// x
+  static const int lowerX = 120;
+
+  /// z
+  static const int lowerZ = 122;
+
+  /// `~` (tilde)
+  static const int tilde = 126;
+}
diff --git a/third_party/packages/path_parsing/pubspec.yaml b/third_party/packages/path_parsing/pubspec.yaml
new file mode 100644
index 000000000000..49bc7b2b55ad
--- /dev/null
+++ b/third_party/packages/path_parsing/pubspec.yaml
@@ -0,0 +1,21 @@
+name: path_parsing
+description: >
+  A Dart library to help with SVG Path parsing and code generation.  Used by Flutter SVG.
+repository: https://github.com/flutter/packages/tree/main/third_party/packages/path_parsing
+issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_parsing%22
+version: 1.0.2
+
+environment:
+  sdk: ^3.3.0
+
+dependencies:
+  meta: ^1.3.0
+  vector_math: ^2.1.0
+
+dev_dependencies:
+  path: ^1.8.0
+  test: ^1.16.0
+
+topics:
+  - svg
+  - vector-graphics
diff --git a/third_party/packages/path_parsing/test/parse_path_deep_test.dart b/third_party/packages/path_parsing/test/parse_path_deep_test.dart
new file mode 100644
index 000000000000..8839f068f3e3
--- /dev/null
+++ b/third_party/packages/path_parsing/test/parse_path_deep_test.dart
@@ -0,0 +1,71 @@
+import 'package:path_parsing/path_parsing.dart';
+import 'package:test/test.dart';
+
+class DeepTestPathProxy extends PathProxy {
+  DeepTestPathProxy(this.expectedCommands);
+
+  final List expectedCommands;
+  final List actualCommands = [];
+
+  @override
+  void close() {
+    actualCommands.add('close()');
+  }
+
+  @override
+  void cubicTo(
+    double x1,
+    double y1,
+    double x2,
+    double y2,
+    double x3,
+    double y3,
+  ) {
+    actualCommands.add(
+        'cubicTo(${x1.toStringAsFixed(4)}, ${y1.toStringAsFixed(4)}, ${x2.toStringAsFixed(4)}, ${y2.toStringAsFixed(4)}, ${x3.toStringAsFixed(4)}, ${y3.toStringAsFixed(4)})');
+  }
+
+  @override
+  void lineTo(double x, double y) {
+    actualCommands
+        .add('lineTo(${x.toStringAsFixed(4)}, ${y.toStringAsFixed(4)})');
+  }
+
+  @override
+  void moveTo(double x, double y) {
+    actualCommands
+        .add('moveTo(${x.toStringAsFixed(4)}, ${y.toStringAsFixed(4)})');
+  }
+
+  void validate() {
+    expect(expectedCommands, orderedEquals(actualCommands));
+  }
+}
+
+void main() {
+  void assertValidPath(String input, List commands) {
+    final DeepTestPathProxy proxy = DeepTestPathProxy(commands);
+    writeSvgPathDataToPath(input, proxy);
+    proxy.validate();
+  }
+
+  test('Deep path validation', () {
+    assertValidPath('M20,30 Q40,5 60,30 T100,30', [
+      'moveTo(20.0000, 30.0000)',
+      'cubicTo(33.3333, 13.3333, 46.6667, 13.3333, 60.0000, 30.0000)',
+      'cubicTo(73.3333, 46.6667, 86.6667, 46.6667, 100.0000, 30.0000)'
+    ]);
+
+    assertValidPath(
+        'M5.5 5.5a.5 1.5 30 1 1-.866-.5.5 1.5 30 1 1 .866.5z', [
+      'moveTo(5.5000, 5.5000)',
+      'cubicTo(5.2319, 5.9667, 4.9001, 6.3513, 4.6307, 6.5077)',
+      'cubicTo(4.3612, 6.6640, 4.1953, 6.5683, 4.1960, 6.2567)',
+      'cubicTo(4.1967, 5.9451, 4.3638, 5.4655, 4.6340, 5.0000)',
+      'cubicTo(4.9021, 4.5333, 5.2339, 4.1487, 5.5033, 3.9923)',
+      'cubicTo(5.7728, 3.8360, 5.9387, 3.9317, 5.9380, 4.2433)',
+      'cubicTo(5.9373, 4.5549, 5.7702, 5.0345, 5.5000, 5.5000)',
+      'close()'
+    ]);
+  });
+}
diff --git a/third_party/packages/path_parsing/test/parse_path_test.dart b/third_party/packages/path_parsing/test/parse_path_test.dart
new file mode 100644
index 000000000000..0f8a5117e2aa
--- /dev/null
+++ b/third_party/packages/path_parsing/test/parse_path_test.dart
@@ -0,0 +1,248 @@
+// Test paths taken from:
+//   * https://github.com/chromium/chromium/blob/master/third_party/blink/renderer/core/svg/svg_path_parser_test.cc
+
+import 'package:path_parsing/path_parsing.dart';
+import 'package:path_parsing/src/path_segment_type.dart';
+import 'package:test/test.dart';
+
+// TODO(dnfield): a bunch of better tests could be written to track that commands are actually called with expected values/order
+// For now we just want to know that something gets emitted and no exceptions are thrown (that's all the legacy tests really did anyway).
+class TestPathProxy extends PathProxy {
+  bool called = false;
+  @override
+  void close() {
+    called = true;
+  }
+
+  @override
+  void cubicTo(
+    double x1,
+    double y1,
+    double x2,
+    double y2,
+    double x3,
+    double y3,
+  ) {
+    called = true;
+  }
+
+  @override
+  void lineTo(double x, double y) {
+    called = true;
+  }
+
+  @override
+  void moveTo(double x, double y) {
+    called = true;
+  }
+}
+
+void main() {
+  void assertValidPath(String input) {
+    final TestPathProxy proxy = TestPathProxy();
+    // these shouldn't throw or assert
+    writeSvgPathDataToPath(input, proxy);
+    expect(proxy.called, true);
+  }
+
+  void assertInvalidPath(String input) {
+    expect(
+        () => writeSvgPathDataToPath(input, TestPathProxy()), throwsStateError);
+  }
+
+  test('Valid Paths', () {
+    assertValidPath('M1,2');
+    assertValidPath('m1,2');
+    assertValidPath('M100,200 m3,4');
+    assertValidPath('M100,200 L3,4');
+    assertValidPath('M100,200 l3,4');
+    assertValidPath('M100,200 H3');
+    assertValidPath('M100,200 h3');
+    assertValidPath('M100,200 V3');
+    assertValidPath('M100,200 v3');
+    assertValidPath('M100,200 Z');
+    assertValidPath('M100,200 z');
+    assertValidPath('M100,200 C3,4,5,6,7,8');
+    assertValidPath('M100,200 c3,4,5,6,7,8');
+    assertValidPath('M100,200 S3,4,5,6');
+    assertValidPath('M100,200 s3,4,5,6');
+    assertValidPath('M100,200 Q3,4,5,6');
+    assertValidPath('M100,200 q3,4,5,6');
+    assertValidPath('M100,200 T3,4');
+    assertValidPath('M100,200 t3,4');
+    assertValidPath('M100,200 A3,4,5,0,0,6,7');
+    assertValidPath('M100,200 A3,4,5,1,0,6,7');
+    assertValidPath('M100,200 A3,4,5,0,1,6,7');
+    assertValidPath('M100,200 A3,4,5,1,1,6,7');
+    assertValidPath('M100,200 a3,4,5,0,0,6,7');
+    assertValidPath('M100,200 a3,4,5,0,1,6,7');
+    assertValidPath('M100,200 a3,4,5,1,0,6,7');
+    assertValidPath('M100,200 a3,4,5,1,1,6,7');
+    assertValidPath('M100,200 a3,4,5,006,7');
+    assertValidPath('M100,200 a3,4,5,016,7');
+    assertValidPath('M100,200 a3,4,5,106,7');
+    assertValidPath('M100,200 a3,4,5,116,7');
+    assertValidPath('''
+M19.0281,19.40466 20.7195,19.40466 20.7195,15.71439 24.11486,15.71439 24.11486,14.36762 20.7195,14.36762
+20.7195,11.68641 24.74134,11.68641 24.74134,10.34618 19.0281,10.34618 	z''');
+
+    assertValidPath(
+        'M100,200 a0,4,5,0,0,10,0 a4,0,5,0,0,0,10 a0,0,5,0,0,-10,0 z');
+
+    assertValidPath('M1,2,3,4');
+    assertValidPath('m100,200,3,4');
+
+    assertValidPath('M 100-200');
+    assertValidPath('M 0.6.5');
+
+    assertValidPath(' M1,2');
+    assertValidPath('  M1,2');
+    assertValidPath('\tM1,2');
+    assertValidPath('\nM1,2');
+    assertValidPath('\rM1,2');
+    assertValidPath('M1,2 ');
+    assertValidPath('M1,2\t');
+    assertValidPath('M1,2\n');
+    assertValidPath('M1,2\r');
+    // assertValidPath('');
+    // assertValidPath(' ');
+    assertValidPath('M.1 .2 L.3 .4 .5 .6');
+    assertValidPath('M1,1h2,3');
+    assertValidPath('M1,1H2,3');
+    assertValidPath('M1,1v2,3');
+    assertValidPath('M1,1V2,3');
+    assertValidPath('M1,1c2,3 4,5 6,7 8,9 10,11 12,13');
+    assertValidPath('M1,1C2,3 4,5 6,7 8,9 10,11 12,13');
+    assertValidPath('M1,1s2,3 4,5 6,7 8,9');
+    assertValidPath('M1,1S2,3 4,5 6,7 8,9');
+    assertValidPath('M1,1q2,3 4,5 6,7 8,9');
+    assertValidPath('M1,1Q2,3 4,5 6,7 8,9');
+    assertValidPath('M1,1t2,3 4,5');
+    assertValidPath('M1,1T2,3 4,5');
+    assertValidPath('M1,1a2,3,4,0,0,5,6 7,8,9,0,0,10,11');
+    assertValidPath('M1,1A2,3,4,0,0,5,6 7,8,9,0,0,10,11');
+    assertValidPath(
+        'M22.1595 3.80852C19.6789 1.35254 16.3807 -4.80966e-07 12.8727 '
+        '-4.80966e-07C9.36452 -4.80966e-07 6.06642 1.35254 3.58579 3.80852C1.77297 5.60333 '
+        '0.53896 7.8599 0.0171889 10.3343C-0.0738999 10.7666 0.206109 11.1901 0.64265 '
+        '11.2803C1.07908 11.3706 1.50711 11.0934 1.5982 10.661C2.05552 8.49195 3.13775 6.51338 4.72783 '
+        '4.9391C9.21893 0.492838 16.5262 0.492728 21.0173 4.9391C25.5082 9.38548 25.5082 16.6202 '
+        '21.0173 21.0667C16.5265 25.5132 9.21893 25.5133 4.72805 21.0669C3.17644 19.5307 2.10538 '
+        '17.6035 1.63081 15.4937C1.53386 15.0627 1.10252 14.7908 0.66697 14.887C0.231645 14.983 '
+        '-0.0427272 15.4103 0.0542205 15.8413C0.595668 18.2481 1.81686 20.4461 3.5859 '
+        '22.1976C6.14623 24.7325 9.50955 26 12.8727 26C16.236 26 19.5991 24.7326 22.1595 22.1976C27.2802 '
+        '17.1277 27.2802 8.87841 22.1595 3.80852Z');
+    assertValidPath(
+        'm18 11.8a.41.41 0 0 1 .24.08l.59.43h.05.72a.4.4 0 0 1 .39.28l.22.69a.08.08 0 '
+        '0 0 0 0l.58.43a.41.41 0 0 1 .15.45l-.22.68a.09.09 0 0 0 0 .07l.22.68a.4.4 0 0 1 '
+        '-.15.46l-.58.42a.1.1 0 0 0 0 0l-.22.68a.41.41 0 0 1 -.38.29h-.79l-.58.43a.41.41 0 '
+        '0 1 -.24.08.46.46 0 0 1 -.24-.08l-.58-.43h-.06-.72a.41.41 0 0 1 -.39-.28l-.22-.68a.1.1 '
+        '0 0 0 0 0l-.58-.43a.42.42 0 0 1 -.15-.46l.23-.67v-.02l-.29-.68a.43.43 0 0 1 '
+        '.15-.46l.58-.42a.1.1 0 0 0 0-.05l.27-.69a.42.42 0 0 1 .39-.28h.78l.58-.43a.43.43 0 '
+        '0 1 .25-.09m0-1a1.37 1.37 0 0 0 -.83.27l-.34.25h-.43a1.42 1.42 0 0 0 -1.34 '
+        '1l-.13.4-.35.25a1.42 1.42 0 0 0 -.51 1.58l.13.4-.13.4a1.39 1.39 0 0 0 .52 '
+        '1.59l.34.25.13.4a1.41 1.41 0 0 0 1.34 1h.43l.34.26a1.44 1.44 0 0 0 .83.27 1.38 1.38 0 0 0 '
+        '.83-.28l.35-.24h.43a1.4 1.4 0 0 0 1.33-1l.13-.4.35-.26a1.39 1.39 0 0 0 '
+        '.51-1.57l-.13-.4.13-.41a1.4 1.4 0 0 0 -.51-1.56l-.35-.25-.13-.41a1.4 1.4 0 0 0 '
+        '-1.34-1h-.42l-.34-.26a1.43 1.43 0 0 0 -.84-.28z');
+  });
+
+  test('Malformed Paths', () {
+    assertInvalidPath('M100,200 a3,4,5,2,1,6,7');
+    assertInvalidPath('M100,200 a3,4,5,1,2,6,7');
+
+    assertInvalidPath('\vM1,2');
+    assertInvalidPath('xM1,2');
+    assertInvalidPath('M1,2\v');
+    assertInvalidPath('M1,2x');
+    assertInvalidPath('M1,2 L40,0#90');
+
+    assertInvalidPath('x');
+    assertInvalidPath('L1,2');
+
+    assertInvalidPath('M');
+    assertInvalidPath('M0');
+
+    assertInvalidPath('M1,1Z0');
+    assertInvalidPath('M1,1z0');
+
+    assertInvalidPath('M1,1c2,3 4,5 6,7 8');
+    assertInvalidPath('M1,1C2,3 4,5 6,7 8');
+    assertInvalidPath('M1,1s2,3 4,5 6');
+    assertInvalidPath('M1,1S2,3 4,5 6');
+    assertInvalidPath('M1,1q2,3 4,5 6');
+    assertInvalidPath('M1,1Q2,3 4,5 6');
+    assertInvalidPath('M1,1t2,3 4');
+    assertInvalidPath('M1,1T2,3 4');
+    assertInvalidPath('M1,1a2,3,4,0,0,5,6 7');
+    assertInvalidPath('M1,1A2,3,4,0,0,5,6 7');
+  });
+
+  test('Missing commands/numbers/flags', () {
+    // Missing initial moveto.
+    assertInvalidPath(' 10 10');
+    assertInvalidPath('L 10 10');
+    // Invalid command letter.
+    assertInvalidPath('M 10 10 #');
+    assertInvalidPath('M 10 10 E 100 100');
+    // Invalid number.
+    assertInvalidPath('M 10 10 L100 ');
+    assertInvalidPath('M 10 10 L100 #');
+    assertInvalidPath('M 10 10 L100#100');
+    assertInvalidPath('M0,0 A#,10 0 0,0 20,20');
+    assertInvalidPath('M0,0 A10,# 0 0,0 20,20');
+    assertInvalidPath('M0,0 A10,10 # 0,0 20,20');
+    assertInvalidPath('M0,0 A10,10 0 0,0 #,20');
+    assertInvalidPath('M0,0 A10,10 0 0,0 20,#');
+    // Invalid arc-flag.
+    assertInvalidPath('M0,0 A10,10 0 #,0 20,20');
+    assertInvalidPath('M0,0 A10,10 0 0,# 20,20');
+    assertInvalidPath('M0,0 A10,10 0 0,2 20,20');
+  });
+
+  test('Check character constants', () {
+    expect(AsciiConstants.slashT, '\t'.codeUnitAt(0));
+    expect(AsciiConstants.slashN, '\n'.codeUnitAt(0));
+    expect(AsciiConstants.slashF, '\f'.codeUnitAt(0));
+    expect(AsciiConstants.slashR, '\r'.codeUnitAt(0));
+    expect(AsciiConstants.space, ' '.codeUnitAt(0));
+    expect(AsciiConstants.period, '.'.codeUnitAt(0));
+    expect(AsciiConstants.plus, '+'.codeUnitAt(0));
+    expect(AsciiConstants.comma, ','.codeUnitAt(0));
+    expect(AsciiConstants.minus, '-'.codeUnitAt(0));
+    expect(AsciiConstants.number0, '0'.codeUnitAt(0));
+    expect(AsciiConstants.number1, '1'.codeUnitAt(0));
+    expect(AsciiConstants.number2, '2'.codeUnitAt(0));
+    expect(AsciiConstants.number3, '3'.codeUnitAt(0));
+    expect(AsciiConstants.number4, '4'.codeUnitAt(0));
+    expect(AsciiConstants.number5, '5'.codeUnitAt(0));
+    expect(AsciiConstants.number6, '6'.codeUnitAt(0));
+    expect(AsciiConstants.number7, '7'.codeUnitAt(0));
+    expect(AsciiConstants.number8, '8'.codeUnitAt(0));
+    expect(AsciiConstants.number9, '9'.codeUnitAt(0));
+    expect(AsciiConstants.upperA, 'A'.codeUnitAt(0));
+    expect(AsciiConstants.upperC, 'C'.codeUnitAt(0));
+    expect(AsciiConstants.upperE, 'E'.codeUnitAt(0));
+    expect(AsciiConstants.upperH, 'H'.codeUnitAt(0));
+    expect(AsciiConstants.upperL, 'L'.codeUnitAt(0));
+    expect(AsciiConstants.upperM, 'M'.codeUnitAt(0));
+    expect(AsciiConstants.upperQ, 'Q'.codeUnitAt(0));
+    expect(AsciiConstants.upperS, 'S'.codeUnitAt(0));
+    expect(AsciiConstants.upperT, 'T'.codeUnitAt(0));
+    expect(AsciiConstants.upperV, 'V'.codeUnitAt(0));
+    expect(AsciiConstants.upperZ, 'Z'.codeUnitAt(0));
+    expect(AsciiConstants.lowerA, 'a'.codeUnitAt(0));
+    expect(AsciiConstants.lowerC, 'c'.codeUnitAt(0));
+    expect(AsciiConstants.lowerE, 'e'.codeUnitAt(0));
+    expect(AsciiConstants.lowerH, 'h'.codeUnitAt(0));
+    expect(AsciiConstants.lowerL, 'l'.codeUnitAt(0));
+    expect(AsciiConstants.lowerM, 'm'.codeUnitAt(0));
+    expect(AsciiConstants.lowerQ, 'q'.codeUnitAt(0));
+    expect(AsciiConstants.lowerS, 's'.codeUnitAt(0));
+    expect(AsciiConstants.lowerT, 't'.codeUnitAt(0));
+    expect(AsciiConstants.lowerV, 'v'.codeUnitAt(0));
+    expect(AsciiConstants.lowerX, 'x'.codeUnitAt(0));
+    expect(AsciiConstants.lowerZ, 'z'.codeUnitAt(0));
+    expect(AsciiConstants.tilde, '~'.codeUnitAt(0));
+  });
+}