Adopt Flutter.xcframework in tool (#71495)

diff --git a/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart b/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart
index 8f8a7d9..82266bc 100644
--- a/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart
+++ b/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart
@@ -102,6 +102,7 @@
       options: <String>[
         'ios-framework',
         '--universal',
+        '--verbose',
         '--output=$outputDirectoryName'
       ],
     );
@@ -164,16 +165,43 @@
     'App',
   );
 
-  // This seemed easier than an explicit Xcode version check.
-  String xcodeArmDirectoryName;
+  // Based on the locally installed version of Xcode.
+  String localXcodeArmDirectoryName;
   if (exists(File(xcode11AppFrameworkDirectory))) {
-    xcodeArmDirectoryName = xcode11ArmDirectoryName;
+    localXcodeArmDirectoryName = xcode11ArmDirectoryName;
   } else if (exists(File(xcode12AppFrameworkDirectory))) {
-    xcodeArmDirectoryName = xcode12ArmDirectoryName;
+    localXcodeArmDirectoryName = xcode12ArmDirectoryName;
   } else {
     throw const FileSystemException('Expected App.framework binary to exist.');
   }
 
+  final String xcode11FlutterFrameworkDirectory = path.join(
+    outputPath,
+    'Debug',
+    'Flutter.xcframework',
+    xcode11ArmDirectoryName,
+    'Flutter.framework',
+    'Flutter',
+  );
+  final String xcode12FlutterFrameworkDirectory = path.join(
+    outputPath,
+    'Debug',
+    'Flutter.xcframework',
+    xcode12ArmDirectoryName,
+    'Flutter.framework',
+    'Flutter',
+  );
+
+  // Based on the version of Xcode installed on the engine builder.
+  String builderXcodeArmDirectoryName;
+  if (exists(File(xcode11FlutterFrameworkDirectory))) {
+    builderXcodeArmDirectoryName = xcode11ArmDirectoryName;
+  } else if (exists(File(xcode12FlutterFrameworkDirectory))) {
+    builderXcodeArmDirectoryName = xcode12ArmDirectoryName;
+  } else {
+    throw const FileSystemException('Expected Flutter.framework binary to exist.');
+  }
+
   checkFileExists(path.join(
     outputPath,
     'Debug',
@@ -214,7 +242,7 @@
       outputPath,
       mode,
       'App.xcframework',
-      xcodeArmDirectoryName,
+      localXcodeArmDirectoryName,
       'App.framework',
       'App',
     ));
@@ -239,30 +267,25 @@
       'Flutter',
     );
 
-    await _checkFrameworkArchs(engineFrameworkPath, mode == 'Debug');
+    await _checkFrameworkArchs(engineFrameworkPath, true);
     await _checkBitcode(engineFrameworkPath, mode);
 
     checkFileExists(path.join(
       outputPath,
       mode,
       'Flutter.xcframework',
-      xcodeArmDirectoryName,
+      builderXcodeArmDirectoryName,
       'Flutter.framework',
       'Flutter',
     ));
-    final String simulatorFrameworkPath = path.join(
+    checkFileExists(path.join(
       outputPath,
       mode,
       'Flutter.xcframework',
       'ios-x86_64-simulator',
       'Flutter.framework',
       'Flutter',
-    );
-    if (mode == 'Debug') {
-      checkFileExists(simulatorFrameworkPath);
-    } else {
-      checkFileNotExists(simulatorFrameworkPath);
-    }
+    ));
   }
 
   section("Check all modes' engine header");
@@ -287,7 +310,7 @@
       outputPath,
       mode,
       'device_info.xcframework',
-      xcodeArmDirectoryName,
+      localXcodeArmDirectoryName,
       'device_info.framework',
       'device_info',
     ));
@@ -296,7 +319,7 @@
       outputPath,
       mode,
       'device_info.xcframework',
-      xcodeArmDirectoryName,
+      localXcodeArmDirectoryName,
       'device_info.framework',
       'Headers',
       'DeviceInfoPlugin.h',
@@ -357,7 +380,7 @@
       outputPath,
       mode,
       'FlutterPluginRegistrant.xcframework',
-      xcodeArmDirectoryName,
+      localXcodeArmDirectoryName,
       'FlutterPluginRegistrant.framework',
       'Headers',
       'GeneratedPluginRegistrant.h',
diff --git a/dev/devicelab/lib/framework/ios.dart b/dev/devicelab/lib/framework/ios.dart
index fc19f07..da5b717 100644
--- a/dev/devicelab/lib/framework/ios.dart
+++ b/dev/devicelab/lib/framework/ios.dart
@@ -22,6 +22,8 @@
   // See: https://stackoverflow.com/questions/32755775/how-to-check-a-static-library-is-built-contain-bitcode
   final String loadCommands = await eval('otool', <String>[
     '-l',
+    '-arch',
+    'arm64',
     pathToBinary,
   ]);
   if (!loadCommands.contains('__LLVM')) {
diff --git a/packages/flutter_tools/bin/podhelper.rb b/packages/flutter_tools/bin/podhelper.rb
index 87b495c..c1c7022 100644
--- a/packages/flutter_tools/bin/podhelper.rb
+++ b/packages/flutter_tools/bin/podhelper.rb
@@ -35,13 +35,27 @@
   # This podhelper script is at $FLUTTER_ROOT/packages/flutter_tools/bin.
   # Add search paths from $FLUTTER_ROOT/bin/cache/artifacts/engine.
   artifacts_dir = File.join('..', '..', '..', '..', 'bin', 'cache', 'artifacts', 'engine')
-  debug_framework_dir = File.expand_path(File.join(artifacts_dir, 'ios'), __FILE__)
-  release_framework_dir = File.expand_path(File.join(artifacts_dir, 'ios-release'), __FILE__)
+  debug_framework_dir = File.expand_path(File.join(artifacts_dir, 'ios', 'Flutter.xcframework'), __FILE__)
+
+  unless Dir.exist?(debug_framework_dir)
+    # iOS artifacts have not been downloaded.
+    raise "#{debug_framework_dir} must exist. If you're running pod install manually, make sure flutter build ios is executed first"
+  end
+
+  release_framework_dir = File.expand_path(File.join(artifacts_dir, 'ios-release', 'Flutter.xcframework'), __FILE__)
 
   target.build_configurations.each do |build_configuration|
     # 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
-    build_configuration.build_settings['FRAMEWORK_SEARCH_PATHS'] = "\"#{configuration_engine_dir}\" $(inherited)"
+    Dir.new(configuration_engine_dir).each_child do |xcframework_file|
+      if xcframework_file.end_with?("-simulator") # ios-x86_64-simulator
+        build_configuration.build_settings['FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]'] = "\"#{configuration_engine_dir}/#{xcframework_file}\" $(inherited)"
+      elsif xcframework_file.start_with?("ios-") # ios-armv7_arm64
+        build_configuration.build_settings['FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]'] = "\"#{configuration_engine_dir}/#{xcframework_file}\" $(inherited)"
+      else
+        # Info.plist or another platform.
+      end
+    end
     build_configuration.build_settings['OTHER_LDFLAGS'] = '$(inherited) -framework Flutter'
 
     build_configuration.build_settings['CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER'] = 'NO'
diff --git a/packages/flutter_tools/bin/xcode_backend.sh b/packages/flutter_tools/bin/xcode_backend.sh
index 3ca6350..c4df0b5 100755
--- a/packages/flutter_tools/bin/xcode_backend.sh
+++ b/packages/flutter_tools/bin/xcode_backend.sh
@@ -115,7 +115,7 @@
   local framework_path="${FLUTTER_ROOT}/bin/cache/artifacts/engine/${artifact_variant}"
   local flutter_engine_flag=""
   local local_engine_flag=""
-  local flutter_framework="${framework_path}/Flutter.framework"
+  local flutter_framework="${framework_path}/Flutter.xcframework"
 
   if [[ -n "$FLUTTER_ENGINE" ]]; then
     flutter_engine_flag="--local-engine-src-path=${FLUTTER_ENGINE}"
@@ -135,7 +135,7 @@
       exit -1
     fi
     local_engine_flag="--local-engine=${LOCAL_ENGINE}"
-    flutter_framework="${FLUTTER_ENGINE}/out/${LOCAL_ENGINE}/Flutter.framework"
+    flutter_framework="${FLUTTER_ENGINE}/out/${LOCAL_ENGINE}/Flutter.xcframework"
   fi
 
   local bitcode_flag=""
diff --git a/packages/flutter_tools/lib/src/artifacts.dart b/packages/flutter_tools/lib/src/artifacts.dart
index e540acb..9386b08 100644
--- a/packages/flutter_tools/lib/src/artifacts.dart
+++ b/packages/flutter_tools/lib/src/artifacts.dart
@@ -5,6 +5,7 @@
 import 'package:meta/meta.dart';
 import 'package:process/process.dart';
 
+import 'base/common.dart';
 import 'base/file_system.dart';
 import 'base/platform.dart';
 import 'base/utils.dart';
@@ -305,12 +306,14 @@
       BuildMode mode, EnvironmentType environmentType) {
     switch (artifact) {
       case Artifact.genSnapshot:
-      case Artifact.flutterFramework:
       case Artifact.flutterXcframework:
       case Artifact.frontendServerSnapshotForEngineDartSdk:
         final String artifactFileName = _artifactToFileName(artifact);
         final String engineDir = _getEngineArtifactsPath(platform, mode);
         return _fileSystem.path.join(engineDir, artifactFileName);
+      case Artifact.flutterFramework:
+        final String engineDir = _getEngineArtifactsPath(platform, mode);
+        return _getIosEngineArtifactPath(engineDir, environmentType, _fileSystem);
       case Artifact.idevicescreenshot:
       case Artifact.idevicesyslog:
         final String artifactFileName = _artifactToFileName(artifact);
@@ -527,6 +530,38 @@
   throw UnimplementedError('Host OS not supported.');
 }
 
+String _getIosEngineArtifactPath(String engineDirectory,
+    EnvironmentType environmentType, FileSystem fileSystem) {
+  final Directory xcframeworkDirectory = fileSystem
+      .directory(engineDirectory)
+      .childDirectory(_artifactToFileName(Artifact.flutterXcframework));
+
+  if (!xcframeworkDirectory.existsSync()) {
+    throwToolExit('No xcframework found at ${xcframeworkDirectory.path}. Try running "flutter build ios".');
+  }
+  Directory flutterFrameworkSource;
+  for (final Directory platformDirectory
+      in xcframeworkDirectory.listSync().whereType<Directory>()) {
+    if (!platformDirectory.basename.startsWith('ios-')) {
+      continue;
+    }
+    // ios-x86_64-simulator, ios-armv7_arm64 (Xcode 11), or ios-arm64_armv7 (Xcode 12).
+    final bool simulatorDirectory =
+        platformDirectory.basename.endsWith('-simulator');
+    if ((environmentType == EnvironmentType.simulator && simulatorDirectory) ||
+        (environmentType == EnvironmentType.physical && !simulatorDirectory)) {
+      flutterFrameworkSource = platformDirectory;
+    }
+  }
+  if (flutterFrameworkSource == null) {
+    throwToolExit('No iOS frameworks found in ${xcframeworkDirectory.path}');
+  }
+
+  return flutterFrameworkSource
+      .childDirectory(_artifactToFileName(Artifact.flutterFramework))
+      .path;
+}
+
 /// Manages the artifacts of a locally built engine.
 class LocalEngineArtifacts implements Artifacts {
   LocalEngineArtifacts(
@@ -578,7 +613,8 @@
       case Artifact.platformLibrariesJson:
         return _fileSystem.path.join(_getFlutterPatchedSdkPath(mode), 'lib', artifactFileName);
       case Artifact.flutterFramework:
-        return _fileSystem.path.join(engineOutPath, artifactFileName);
+        return _getIosEngineArtifactPath(
+            engineOutPath, environmentType, _fileSystem);
       case Artifact.flutterPatchedSdkPath:
         // When using local engine always use [BuildMode.debug] regardless of
         // what was specified in [mode] argument because local engine will
diff --git a/packages/flutter_tools/lib/src/build_system/targets/ios.dart b/packages/flutter_tools/lib/src/build_system/targets/ios.dart
index 1d75ec2..e26ee1d 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/ios.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/ios.dart
@@ -249,7 +249,7 @@
         const Source.pattern(
             '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/ios.dart'),
         Source.artifact(
-          Artifact.flutterFramework,
+          Artifact.flutterXcframework,
           platform: TargetPlatform.ios,
           mode: buildMode,
         ),
diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart
index 9a79ba5..e6d96e6 100644
--- a/packages/flutter_tools/lib/src/cache.dart
+++ b/packages/flutter_tools/lib/src/cache.dart
@@ -924,14 +924,11 @@
 
       _makeFilesExecutable(dir, operatingSystemUtils);
 
-      const List<String> frameworkNames = <String>['Flutter', 'FlutterMacOS'];
-      for (final String frameworkName in frameworkNames) {
-        final File frameworkZip = fileSystem.file(fileSystem.path.join(dir.path, '$frameworkName.framework.zip'));
-        if (frameworkZip.existsSync()) {
-          final Directory framework = fileSystem.directory(fileSystem.path.join(dir.path, '$frameworkName.framework'));
-          framework.createSync();
-          operatingSystemUtils.unzip(frameworkZip, framework);
-        }
+      final File frameworkZip = fileSystem.file(fileSystem.path.join(dir.path, 'FlutterMacOS.framework.zip'));
+      if (frameworkZip.existsSync()) {
+        final Directory framework = fileSystem.directory(fileSystem.path.join(dir.path, 'FlutterMacOS.framework'));
+        framework.createSync();
+        operatingSystemUtils.unzip(frameworkZip, framework);
       }
     }
 
diff --git a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart
index 4e3dcfe..7417260 100644
--- a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart
+++ b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart
@@ -295,10 +295,7 @@
   s.source                = { :http => '${_cache.storageBaseUrl}/flutter_infra/flutter/${_cache.engineRevision}/$artifactsMode/artifacts.zip' }
   s.documentation_url     = 'https://flutter.dev/docs'
   s.platform              = :ios, '8.0'
-  s.vendored_frameworks   = 'Flutter.framework'
-  s.prepare_command       = <<-CMD
-unzip Flutter.framework -d Flutter.framework
-CMD
+  s.vendored_frameworks   = 'Flutter.xcframework'
 end
 ''';
 
@@ -314,56 +311,31 @@
     Directory modeDirectory,
   ) async {
     final Status status = globals.logger.startProgress(
-      ' ├─Populating Flutter.framework...',
+      ' ├─Populating Flutter.xcframework...',
     );
     final String engineCacheFlutterFrameworkDirectory = globals.artifacts.getArtifactPath(
-      Artifact.flutterFramework,
+      Artifact.flutterXcframework,
       platform: TargetPlatform.ios,
       mode: buildInfo.mode,
     );
     final String flutterFrameworkFileName = globals.fs.path.basename(
       engineCacheFlutterFrameworkDirectory,
     );
-    final Directory fatFlutterFrameworkCopy = modeDirectory.childDirectory(
+    final Directory flutterFrameworkCopy = modeDirectory.childDirectory(
       flutterFrameworkFileName,
     );
 
     try {
-      // Copy universal engine cache framework to mode directory.
+      // Copy xcframework engine cache framework to mode directory.
       globals.fsUtils.copyDirectorySync(
         globals.fs.directory(engineCacheFlutterFrameworkDirectory),
-        fatFlutterFrameworkCopy,
+        flutterFrameworkCopy,
       );
-
-      if (buildInfo.mode != BuildMode.debug) {
-        final File fatFlutterFrameworkBinary = fatFlutterFrameworkCopy.childFile('Flutter');
-
-        // Remove simulator architecture in profile and release mode.
-        final List<String> lipoCommand = <String>[
-          ...globals.xcode.xcrunCommand(),
-          'lipo',
-          fatFlutterFrameworkBinary.path,
-          '-remove',
-          'x86_64',
-          '-output',
-          fatFlutterFrameworkBinary.path
-        ];
-        final RunResult lipoResult = await globals.processUtils.run(
-          lipoCommand,
-          allowReentrantFlutter: false,
-        );
-
-        if (lipoResult.exitCode != 0) {
-          throwToolExit(
-            'Unable to remove simulator architecture in ${buildInfo.mode}: ${lipoResult.stderr}',
-          );
-        }
-      }
     } finally {
       status.stop();
     }
 
-    await _produceXCFrameworkFromUniversal(buildInfo, fatFlutterFrameworkCopy);
+    await _produceUniversalFromXCFramework(buildInfo, flutterFrameworkCopy);
   }
 
   Future<void> _produceAppFramework(
@@ -558,112 +530,34 @@
     }
   }
 
-  Future<void> _produceXCFrameworkFromUniversal(BuildInfo buildInfo, Directory fatFramework) async {
-    if (boolArg('xcframework')) {
-      final String frameworkBinaryName = globals.fs.path.basenameWithoutExtension(
-          fatFramework.basename);
+  Future<void> _produceUniversalFromXCFramework(BuildInfo buildInfo, Directory xcframework) async {
+    if (boolArg('universal')) {
+      final String frameworkBinaryName =
+          globals.fs.path.basenameWithoutExtension(xcframework.basename);
 
       final Status status = globals.logger.startProgress(
-        ' ├─Creating $frameworkBinaryName.xcframework...',
+        ' ├─Creating $frameworkBinaryName.framework...',
       );
       try {
-        if (buildInfo.mode == BuildMode.debug) {
-          await _produceDebugXCFramework(fatFramework, frameworkBinaryName);
-        } else {
-          await _produceXCFramework(
-              <Directory>[fatFramework], frameworkBinaryName,
-              fatFramework.parent);
-        }
+        final Iterable<Directory> frameworks = xcframework
+            .listSync()
+            .whereType<Directory>()
+            .map((Directory triple) => triple
+                .listSync()
+                .whereType<Directory>()
+                .firstWhere((Directory frameworkDirectory) =>
+                    frameworkDirectory.basename ==
+                    '$frameworkBinaryName.framework'));
+
+        await _produceUniversalFramework(
+            frameworks, frameworkBinaryName, xcframework.parent);
       } finally {
         status.stop();
       }
     }
 
-    if (!boolArg('universal')) {
-      fatFramework.deleteSync(recursive: true);
-    }
-  }
-
-  Future<void> _produceDebugXCFramework(Directory fatFramework, String frameworkBinaryName) async {
-    final String frameworkFileName = fatFramework.basename;
-    final File fatFlutterFrameworkBinary = fatFramework.childFile(
-      frameworkBinaryName,
-    );
-    final Directory temporaryOutput = globals.fs.systemTempDirectory.createTempSync(
-      'flutter_tool_build_ios_framework.',
-    );
-    try {
-      // Copy universal framework to variant directory.
-      final Directory iPhoneBuildOutput = temporaryOutput.childDirectory(
-        'ios',
-      )..createSync(recursive: true);
-      final Directory simulatorBuildOutput = temporaryOutput.childDirectory(
-        'simulator',
-      )..createSync(recursive: true);
-      final Directory armFlutterFrameworkDirectory = iPhoneBuildOutput
-        .childDirectory(frameworkFileName);
-      final File armFlutterFrameworkBinary = armFlutterFrameworkDirectory
-        .childFile(frameworkBinaryName);
-      globals.fsUtils.copyDirectorySync(fatFramework, armFlutterFrameworkDirectory);
-
-      // Create iOS framework.
-      List<String> lipoCommand = <String>[
-        ...globals.xcode.xcrunCommand(),
-        'lipo',
-        fatFlutterFrameworkBinary.path,
-        '-remove',
-        'x86_64',
-        '-output',
-        armFlutterFrameworkBinary.path
-      ];
-
-      RunResult lipoResult = await globals.processUtils.run(
-        lipoCommand,
-        allowReentrantFlutter: false,
-      );
-
-      if (lipoResult.exitCode != 0) {
-        throwToolExit('Unable to create ARM framework: ${lipoResult.stderr}');
-      }
-
-      // Create simulator framework.
-      final Directory simulatorFlutterFrameworkDirectory = simulatorBuildOutput
-        .childDirectory(frameworkFileName);
-      final File simulatorFlutterFrameworkBinary = simulatorFlutterFrameworkDirectory
-        .childFile(frameworkBinaryName);
-      globals.fsUtils.copyDirectorySync(fatFramework, simulatorFlutterFrameworkDirectory);
-
-      lipoCommand = <String>[
-        ...globals.xcode.xcrunCommand(),
-        'lipo',
-        fatFlutterFrameworkBinary.path,
-        '-thin',
-        'x86_64',
-        '-output',
-        simulatorFlutterFrameworkBinary.path
-      ];
-
-      lipoResult = await globals.processUtils.run(
-        lipoCommand,
-        allowReentrantFlutter: false,
-      );
-
-      if (lipoResult.exitCode != 0) {
-        throwToolExit(
-            'Unable to create simulator framework: ${lipoResult.stderr}');
-      }
-
-      // Create XCFramework from iOS and simulator frameworks.
-      await _produceXCFramework(
-        <Directory>[
-          armFlutterFrameworkDirectory,
-          simulatorFlutterFrameworkDirectory
-        ],
-        frameworkBinaryName,
-        fatFramework.parent,
-      );
-    } finally {
-      temporaryOutput.deleteSync(recursive: true);
+    if (!boolArg('xcframework')) {
+      xcframework.deleteSync(recursive: true);
     }
   }
 
diff --git a/packages/flutter_tools/lib/src/ios/bitcode.dart b/packages/flutter_tools/lib/src/ios/bitcode.dart
index ec00545..fec5a37 100644
--- a/packages/flutter_tools/lib/src/ios/bitcode.dart
+++ b/packages/flutter_tools/lib/src/ios/bitcode.dart
@@ -13,16 +13,14 @@
 
 const bool kBitcodeEnabledDefault = false;
 
-Future<void> validateBitcode(BuildMode buildMode, TargetPlatform targetPlatform) async {
+Future<void> validateBitcode(BuildMode buildMode, TargetPlatform targetPlatform, EnvironmentType environmentType) async {
   final Artifacts localArtifacts = globals.artifacts;
   final String flutterFrameworkPath = localArtifacts.getArtifactPath(
     Artifact.flutterFramework,
     mode: buildMode,
     platform: targetPlatform,
+    environmentType: environmentType,
   );
-  if (!globals.fs.isDirectorySync(flutterFrameworkPath)) {
-    throwToolExit('Flutter.framework not found at $flutterFrameworkPath');
-  }
   final Xcode xcode = context.get<Xcode>();
 
   final RunResult clangResult = await xcode.clang(<String>['--version']);
diff --git a/packages/flutter_tools/lib/src/macos/cocoapod_utils.dart b/packages/flutter_tools/lib/src/macos/cocoapod_utils.dart
index 14ff38d..bfa7c1d 100644
--- a/packages/flutter_tools/lib/src/macos/cocoapod_utils.dart
+++ b/packages/flutter_tools/lib/src/macos/cocoapod_utils.dart
@@ -4,6 +4,7 @@
 
 import '../base/fingerprint.dart';
 import '../build_info.dart';
+import '../cache.dart';
 import '../globals.dart' as globals;
 import '../plugins.dart';
 import '../project.dart';
@@ -28,6 +29,13 @@
       xcodeProject.xcodeProjectInfoFile.path,
       xcodeProject.podfile.path,
       xcodeProject.generatedXcodePropertiesFile.path,
+      globals.fs.path.join(
+        Cache.flutterRoot,
+        'packages',
+        'flutter_tools',
+        'bin',
+        'podhelper.rb',
+      ),
     ],
     fileSystem: globals.fs,
     logger: globals.logger,
diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart
index 29a0a2c..064c10b 100644
--- a/packages/flutter_tools/lib/src/project.dart
+++ b/packages/flutter_tools/lib/src/project.dart
@@ -659,7 +659,7 @@
     // to be in this location.
     final Directory framework = globals.fs.directory(
       globals.artifacts.getArtifactPath(
-        Artifact.flutterFramework,
+        Artifact.flutterXcframework,
         platform: TargetPlatform.ios,
         mode: mode,
         environmentType: environmentType,
@@ -668,7 +668,7 @@
     if (framework.existsSync()) {
       globals.fsUtils.copyDirectorySync(
         framework,
-        engineCopyDirectory.childDirectory('Flutter.framework'),
+        engineCopyDirectory.childDirectory('Flutter.xcframework'),
       );
     }
   }
diff --git a/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Flutter/engine/Flutter.podspec.tmpl b/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Flutter/engine/Flutter.podspec.tmpl
index 5ca3041..3a6ef67 100644
--- a/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Flutter/engine/Flutter.podspec.tmpl
+++ b/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Flutter/engine/Flutter.podspec.tmpl
@@ -14,5 +14,5 @@
   s.author           = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
   s.source           = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
   s.ios.deployment_target = '8.0'
-  s.vendored_frameworks = 'Flutter.framework'
+  s.vendored_frameworks = 'Flutter.xcframework'
 end
diff --git a/packages/flutter_tools/templates/module/ios/library/Flutter.tmpl/podhelper.rb.tmpl b/packages/flutter_tools/templates/module/ios/library/Flutter.tmpl/podhelper.rb.tmpl
index b6b078c..fd1ecb6 100644
--- a/packages/flutter_tools/templates/module/ios/library/Flutter.tmpl/podhelper.rb.tmpl
+++ b/packages/flutter_tools/templates/module/ios/library/Flutter.tmpl/podhelper.rb.tmpl
@@ -30,7 +30,7 @@
 def install_flutter_engine_pod
   current_directory = File.expand_path('..', __FILE__)
   engine_dir = File.expand_path('engine', current_directory)
-  framework_name = 'Flutter.framework'
+  framework_name = 'Flutter.xcframework'
   copied_engine = File.expand_path(framework_name, engine_dir)
   if !File.exist?(copied_engine)
     # Copy the debug engine to have something to link against if the xcode backend script has not run yet.
diff --git a/packages/flutter_tools/test/general.shard/artifacts_test.dart b/packages/flutter_tools/test/general.shard/artifacts_test.dart
index fc1bdf5..2ca82bc 100644
--- a/packages/flutter_tools/test/general.shard/artifacts_test.dart
+++ b/packages/flutter_tools/test/general.shard/artifacts_test.dart
@@ -42,9 +42,67 @@
     });
 
     testWithoutContext('getArtifactPath', () {
+      final String xcframeworkPath = artifacts.getArtifactPath(
+        Artifact.flutterXcframework,
+        platform: TargetPlatform.ios,
+        mode: BuildMode.release,
+      );
       expect(
-        artifacts.getArtifactPath(Artifact.flutterFramework, platform: TargetPlatform.ios, mode: BuildMode.release),
-        fileSystem.path.join('root', 'bin', 'cache', 'artifacts', 'engine', 'ios-release', 'Flutter.framework'),
+        xcframeworkPath,
+        fileSystem.path.join(
+          'root',
+          'bin',
+          'cache',
+          'artifacts',
+          'engine',
+          'ios-release',
+          'Flutter.xcframework',
+        ),
+      );
+      expect(
+        () => artifacts.getArtifactPath(
+          Artifact.flutterFramework,
+          platform: TargetPlatform.ios,
+          mode: BuildMode.release,
+          environmentType: EnvironmentType.simulator,
+        ),
+        throwsToolExit(
+            message:
+                'No xcframework found at $xcframeworkPath. Try running "flutter build ios".'),
+      );
+      fileSystem.directory(xcframeworkPath).createSync(recursive: true);
+      expect(
+        () => artifacts.getArtifactPath(
+          Artifact.flutterFramework,
+          platform: TargetPlatform.ios,
+          mode: BuildMode.release,
+          environmentType: EnvironmentType.simulator,
+        ),
+        throwsToolExit(message: 'No iOS frameworks found in $xcframeworkPath'),
+      );
+
+      fileSystem
+          .directory(xcframeworkPath)
+          .childDirectory('ios-x86_64-simulator')
+          .childDirectory('Flutter.framework')
+          .createSync(recursive: true);
+      fileSystem
+          .directory(xcframeworkPath)
+          .childDirectory('ios-armv7_arm64')
+          .childDirectory('Flutter.framework')
+          .createSync(recursive: true);
+      expect(
+        artifacts.getArtifactPath(Artifact.flutterFramework,
+            platform: TargetPlatform.ios,
+            mode: BuildMode.release,
+            environmentType: EnvironmentType.simulator),
+        fileSystem.path
+            .join(xcframeworkPath, 'ios-x86_64-simulator', 'Flutter.framework'),
+      );
+      expect(
+        artifacts.getArtifactPath(Artifact.flutterFramework,
+            platform: TargetPlatform.ios, mode: BuildMode.release, environmentType: EnvironmentType.physical),
+        fileSystem.path.join(xcframeworkPath, 'ios-armv7_arm64', 'Flutter.framework'),
       );
       expect(
         artifacts.getArtifactPath(Artifact.flutterXcframework, platform: TargetPlatform.ios, mode: BuildMode.release),
@@ -136,13 +194,78 @@
     });
 
     testWithoutContext('getArtifactPath', () {
-      expect(
-        artifacts.getArtifactPath(Artifact.flutterFramework, platform: TargetPlatform.ios, mode: BuildMode.release),
-        fileSystem.path.join('/out', 'android_debug_unopt', 'Flutter.framework'),
+      final String xcframeworkPath = artifacts.getArtifactPath(
+        Artifact.flutterXcframework,
+        platform: TargetPlatform.ios,
+        mode: BuildMode.release,
       );
       expect(
-        artifacts.getArtifactPath(Artifact.flutterXcframework, platform: TargetPlatform.ios, mode: BuildMode.release),
-        fileSystem.path.join('/out', 'android_debug_unopt', 'Flutter.xcframework'),
+        xcframeworkPath,
+        fileSystem.path
+            .join('/out', 'android_debug_unopt', 'Flutter.xcframework'),
+      );
+      expect(
+        () => artifacts.getArtifactPath(
+          Artifact.flutterFramework,
+          platform: TargetPlatform.ios,
+          mode: BuildMode.release,
+          environmentType: EnvironmentType.simulator,
+        ),
+        throwsToolExit(
+            message:
+                'No xcframework found at /out/android_debug_unopt/Flutter.xcframework. Try running "flutter build ios".'),
+      );
+      fileSystem.directory(xcframeworkPath).createSync(recursive: true);
+      expect(
+        () => artifacts.getArtifactPath(
+          Artifact.flutterFramework,
+          platform: TargetPlatform.ios,
+          mode: BuildMode.release,
+          environmentType: EnvironmentType.simulator,
+        ),
+        throwsToolExit(
+            message:
+                'No iOS frameworks found in /out/android_debug_unopt/Flutter.xcframework'),
+      );
+
+      fileSystem
+          .directory(xcframeworkPath)
+          .childDirectory('ios-x86_64-simulator')
+          .childDirectory('Flutter.framework')
+          .createSync(recursive: true);
+      fileSystem
+          .directory(xcframeworkPath)
+          .childDirectory('ios-armv7_arm64')
+          .childDirectory('Flutter.framework')
+          .createSync(recursive: true);
+      expect(
+        artifacts.getArtifactPath(
+          Artifact.flutterFramework,
+          platform: TargetPlatform.ios,
+          mode: BuildMode.release,
+          environmentType: EnvironmentType.simulator,
+        ),
+        fileSystem.path
+            .join(xcframeworkPath, 'ios-x86_64-simulator', 'Flutter.framework'),
+      );
+      expect(
+        artifacts.getArtifactPath(
+          Artifact.flutterFramework,
+          platform: TargetPlatform.ios,
+          mode: BuildMode.release,
+          environmentType: EnvironmentType.physical,
+        ),
+        fileSystem.path
+            .join(xcframeworkPath, 'ios-armv7_arm64', 'Flutter.framework'),
+      );
+      expect(
+        artifacts.getArtifactPath(
+          Artifact.flutterXcframework,
+          platform: TargetPlatform.ios,
+          mode: BuildMode.release,
+        ),
+        fileSystem.path
+            .join('/out', 'android_debug_unopt', 'Flutter.xcframework'),
       );
       expect(
         artifacts.getArtifactPath(Artifact.flutterTester),