[flutter_releases] Flutter stable 2.8.1 Framework Cherrypicks (#95375)

* Build Flutter iOS plugins with all valid architectures (#95293)

* 'add branch flutter-2.8-candidate.3 to enabled_branches in .ci.yaml'

* 'Update Engine revision to 890a5fca2e34db413be624fc83aeea8e61d42ce6 for stable release 2.8.1'

Co-authored-by: Jenn Magder <magder@google.com>
diff --git a/.ci.yaml b/.ci.yaml
index e701a57..8b6f694 100755
--- a/.ci.yaml
+++ b/.ci.yaml
@@ -6,6 +6,7 @@
 # More information at:
 #  * https://github.com/flutter/cocoon/blob/main/CI_YAML.md
 enabled_branches:
+  - flutter-2.8-candidate.3
   - main
   - master
   - flutter-\d+\.\d+-candidate\.\d+
diff --git a/bin/internal/engine.version b/bin/internal/engine.version
index 19bc713..e4d51ed 100644
--- a/bin/internal/engine.version
+++ b/bin/internal/engine.version
@@ -1 +1 @@
-40a99c595137e4b2f5b2efa8ff343ea23c1e16b8
+890a5fca2e34db413be624fc83aeea8e61d42ce6
diff --git a/packages/flutter_tools/bin/podhelper.rb b/packages/flutter_tools/bin/podhelper.rb
index 6a8185e..97e073d 100644
--- a/packages/flutter_tools/bin/podhelper.rb
+++ b/packages/flutter_tools/bin/podhelper.rb
@@ -33,9 +33,6 @@
 def flutter_additional_ios_build_settings(target)
   return unless target.platform_name == :ios
 
-  # Return if it's not a Flutter plugin (transitive dependency).
-  return unless target.dependencies.any? { |dependency| dependency.name == 'Flutter' }
-
   # [target.deployment_target] is a [String] formatted as "8.0".
   inherit_deployment_target = target.deployment_target[/\d+/].to_i < 9
 
@@ -52,6 +49,14 @@
   release_framework_dir = File.expand_path(File.join(artifacts_dir, 'ios-release', 'Flutter.xcframework'), __FILE__)
 
   target.build_configurations.each do |build_configuration|
+    # Build both x86_64 and arm64 simulator archs for all dependencies. If a single plugin does not support arm64 simulators,
+    # the app and all frameworks will fall back to x86_64. Unfortunately that case is not detectable in this script.
+    # Therefore all pods must have a x86_64 slice available, or linking a x86_64 app will fail.
+    build_configuration.build_settings['ONLY_ACTIVE_ARCH'] = 'NO' if build_configuration.type == :debug
+
+    # Skip other updates if it's not a Flutter plugin (transitive dependency).
+    next unless target.dependencies.any? { |dependency| dependency.name == 'Flutter' }
+
     # Profile can't be derived from the CocoaPods build configuration. Use release framework (for linking only).
     configuration_engine_dir = build_configuration.type == :debug ? debug_framework_dir : release_framework_dir
     Dir.new(configuration_engine_dir).each_child do |xcframework_file|
diff --git a/packages/flutter_tools/test/integration.shard/ios_content_validation_test.dart b/packages/flutter_tools/test/integration.shard/ios_content_validation_test.dart
index 1d33156..e8cb730 100644
--- a/packages/flutter_tools/test/integration.shard/ios_content_validation_test.dart
+++ b/packages/flutter_tools/test/integration.shard/ios_content_validation_test.dart
@@ -16,6 +16,7 @@
 void main() {
   group('iOS app validation', () {
     String flutterRoot;
+    Directory pluginRoot;
     String projectRoot;
     String flutterBin;
     Directory tempDir;
@@ -29,18 +30,20 @@
         'flutter',
       );
 
+      // Test a plugin example app to allow plugins validation.
       processManager.runSync(<String>[
         flutterBin,
         ...getLocalEngineArguments(),
         'create',
         '--verbose',
         '--platforms=ios',
-        '-i',
-        'objc',
+        '-t',
+        'plugin',
         'hello',
       ], workingDirectory: tempDir.path);
 
-      projectRoot = tempDir.childDirectory('hello').path;
+      pluginRoot = tempDir.childDirectory('hello');
+      projectRoot = pluginRoot.childDirectory('example').path;
     });
 
     tearDownAll(() {
@@ -56,6 +59,7 @@
         File outputFlutterFrameworkBinary;
         Directory outputAppFramework;
         File outputAppFrameworkBinary;
+        File outputPluginFrameworkBinary;
 
         setUpAll(() {
           processManager.runSync(<String>[
@@ -85,11 +89,13 @@
 
           outputAppFramework = frameworkDirectory.childDirectory('App.framework');
           outputAppFrameworkBinary = outputAppFramework.childFile('App');
+
+          outputPluginFrameworkBinary = frameworkDirectory.childDirectory('hello.framework').childFile('hello');
         });
 
         testWithoutContext('flutter build ios builds a valid app', () {
-          // Should only contain Flutter.framework and App.framework.
-          expect(frameworkDirectory.listSync().length, 2);
+          expect(outputPluginFrameworkBinary, exists);
+
           expect(outputAppFrameworkBinary, exists);
           expect(outputAppFramework.childFile('Info.plist'), exists);
 
@@ -202,17 +208,61 @@
         }, skip: !platform.isMacOS || buildMode != BuildMode.release); // [intended] only makes sense on macos.
 
         testWithoutContext('validate obfuscation', () {
-          final ProcessResult grepResult = processManager.runSync(<String>[
+          // HelloPlugin class is present in project.
+          ProcessResult grepResult = processManager.runSync(<String>[
             'grep',
-            '-i',
-            'hello',
+            '-r',
+            'HelloPlugin',
+            pluginRoot.path,
+          ]);
+          // Matches exits 0.
+          expect(grepResult.exitCode, 0);
+
+          // Not present in binary.
+          grepResult = processManager.runSync(<String>[
+            'grep',
+            'HelloPlugin',
             outputAppFrameworkBinary.path,
           ]);
-          expect(grepResult.stdout, isNot(contains('matches')));
+          // Does not match exits 1.
+          expect(grepResult.exitCode, 1);
         });
       });
     }
 
+    testWithoutContext('builds all plugin architectures for simulator', () {
+      final ProcessResult buildSimulator = processManager.runSync(
+        <String>[
+          flutterBin,
+          ...getLocalEngineArguments(),
+          'build',
+          'ios',
+          '--simulator',
+          '--verbose',
+          '--no-codesign',
+        ],
+        workingDirectory: projectRoot,
+      );
+      expect(buildSimulator.exitCode, 0);
+
+      final File pluginFrameworkBinary = fileSystem.file(fileSystem.path.join(
+        projectRoot,
+        'build',
+        'ios',
+        'iphonesimulator',
+        'Runner.app',
+        'Frameworks',
+        'hello.framework',
+        'hello',
+      ));
+      expect(pluginFrameworkBinary, exists);
+      final ProcessResult archs = processManager.runSync(
+        <String>['file', pluginFrameworkBinary.path],
+      );
+      expect(archs.stdout, contains('Mach-O 64-bit dynamically linked shared library x86_64'));
+      expect(archs.stdout, contains('Mach-O 64-bit dynamically linked shared library arm64'));
+    });
+
     testWithoutContext('build for simulator with all available architectures', () {
       final ProcessResult buildSimulator = processManager.runSync(
         <String>[
@@ -250,6 +300,6 @@
       expect(archs.stdout, contains('Mach-O 64-bit dynamically linked shared library arm64'));
     });
   }, skip: !platform.isMacOS, // [intended] only makes sense for macos platform.
-     timeout: const Timeout(Duration(minutes: 5))
+     timeout: const Timeout(Duration(minutes: 7))
   );
 }