Revert "Revert "Allow any iOS app to be added to an existing host app (#70647)" (#70739)" (#70740)

This reverts commit aab9a76ee4cd97199e9d21118a0a3cfbda80b899.
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 48cfd18..1c73a36 100644
--- a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart
+++ b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart
@@ -113,7 +113,7 @@
   final String name = 'ios-framework';
 
   @override
-  final String description = 'Produces a .framework directory for a Flutter module '
+  final String description = 'Produces .frameworks for a Flutter project '
       'and its plugins for integration into existing, plain Xcode projects.\n'
       'This can only be run on macOS hosts.';
 
@@ -144,10 +144,6 @@
   Future<void> validateCommand() async {
     await super.validateCommand();
     _project = FlutterProject.current();
-    if (!_project.isModule) {
-      throwToolExit('Building frameworks for iOS is only supported from a module.');
-    }
-
     if (!_platform.isMacOS) {
       throwToolExit('Building frameworks for iOS is only supported on the Mac.');
     }
@@ -178,7 +174,7 @@
     }
 
     if (!_project.ios.existsSync()) {
-      throwToolExit('Module does not support iOS');
+      throwToolExit('Project does not support iOS');
     }
 
     final Directory outputDirectory = globals.fs.directory(globals.fs.path.absolute(globals.fs.path.normalize(outputArgument)));
@@ -233,6 +229,23 @@
     }
 
     globals.printStatus('Frameworks written to ${outputDirectory.path}.');
+
+    if (!_project.isModule && hasPlugins(_project)) {
+      // Apps do not generate a FlutterPluginRegistrant.framework. Users will need
+      // to copy the GeneratedPluginRegistrant class to their project manually.
+      final File pluginRegistrantHeader = _project.ios.pluginRegistrantHeader;
+      final File pluginRegistrantImplementation =
+          _project.ios.pluginRegistrantImplementation;
+      pluginRegistrantHeader.copySync(
+          outputDirectory.childFile(pluginRegistrantHeader.basename).path);
+      pluginRegistrantImplementation.copySync(outputDirectory
+          .childFile(pluginRegistrantImplementation.basename)
+          .path);
+      globals.printStatus(
+          '\nCopy the ${globals.fs.path.basenameWithoutExtension(pluginRegistrantHeader.path)} class into your project.\n'
+          'See https://flutter.dev/docs/development/add-to-app/ios/add-flutter-screen#create-a-flutterengine for more information.');
+    }
+
     return FlutterCommandResult.success();
   }
 
@@ -459,6 +472,7 @@
         xcodeBuildConfiguration,
         'SYMROOT=${iPhoneBuildOutput.path}',
         'BITCODE_GENERATION_MODE=$bitcodeGenerationMode',
+        'ENABLE_BITCODE=YES', // Support host apps with bitcode enabled.
         'ONLY_ACTIVE_ARCH=NO', // No device targeted, so build all valid architectures.
         'BUILD_LIBRARY_FOR_DISTRIBUTION=YES',
       ];
@@ -483,6 +497,7 @@
           '-configuration',
           xcodeBuildConfiguration,
           'SYMROOT=${simulatorBuildOutput.path}',
+          'ENABLE_BITCODE=YES', // Support host apps with bitcode enabled.
           'ARCHS=x86_64',
           'ONLY_ACTIVE_ARCH=NO', // No device targeted, so build all valid architectures.
           'BUILD_LIBRARY_FOR_DISTRIBUTION=YES',
diff --git a/packages/flutter_tools/lib/src/plugins.dart b/packages/flutter_tools/lib/src/plugins.dart
index 543b0fa..3883862 100644
--- a/packages/flutter_tools/lib/src/plugins.dart
+++ b/packages/flutter_tools/lib/src/plugins.dart
@@ -897,36 +897,24 @@
     'framework': 'Flutter',
     'plugins': iosPlugins,
   };
-  final String registryDirectory = project.ios.pluginRegistrantHost.path;
   if (project.isModule) {
-    final String registryClassesDirectory = globals.fs.path.join(registryDirectory, 'Classes');
+    final String registryDirectory = project.ios.pluginRegistrantHost.path;
     _renderTemplateToFile(
       _pluginRegistrantPodspecTemplate,
       context,
       globals.fs.path.join(registryDirectory, 'FlutterPluginRegistrant.podspec'),
     );
-    _renderTemplateToFile(
-      _objcPluginRegistryHeaderTemplate,
-      context,
-      globals.fs.path.join(registryClassesDirectory, 'GeneratedPluginRegistrant.h'),
-    );
-    _renderTemplateToFile(
-      _objcPluginRegistryImplementationTemplate,
-      context,
-      globals.fs.path.join(registryClassesDirectory, 'GeneratedPluginRegistrant.m'),
-    );
-  } else {
-    _renderTemplateToFile(
-      _objcPluginRegistryHeaderTemplate,
-      context,
-      globals.fs.path.join(registryDirectory, 'GeneratedPluginRegistrant.h'),
-    );
-    _renderTemplateToFile(
-      _objcPluginRegistryImplementationTemplate,
-      context,
-      globals.fs.path.join(registryDirectory, 'GeneratedPluginRegistrant.m'),
-    );
   }
+  _renderTemplateToFile(
+    _objcPluginRegistryHeaderTemplate,
+    context,
+    project.ios.pluginRegistrantHeader.path,
+  );
+  _renderTemplateToFile(
+    _objcPluginRegistryImplementationTemplate,
+    context,
+    project.ios.pluginRegistrantImplementation.path,
+  );
 }
 
 /// The relative path from a project's main CMake file to the plugin symlink
diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart
index 9e36c46..1ee6b9d 100644
--- a/packages/flutter_tools/lib/src/project.dart
+++ b/packages/flutter_tools/lib/src/project.dart
@@ -665,15 +665,12 @@
       )
     );
     if (framework.existsSync()) {
-      final Directory engineDest = ephemeralDirectory
-          .childDirectory('Flutter')
-          .childDirectory('engine');
       final File podspec = framework.parent.childFile('Flutter.podspec');
       globals.fsUtils.copyDirectorySync(
         framework,
-        engineDest.childDirectory('Flutter.framework'),
+        engineCopyDirectory.childDirectory('Flutter.framework'),
       );
-      podspec.copySync(engineDest.childFile('Flutter.podspec').path);
+      podspec.copySync(engineCopyDirectory.childFile('Flutter.podspec').path);
     }
   }
 
@@ -704,6 +701,22 @@
         : hostAppRoot.childDirectory(_hostAppProjectName);
   }
 
+  File get pluginRegistrantHeader {
+    final Directory registryDirectory = isModule ? pluginRegistrantHost.childDirectory('Classes') : pluginRegistrantHost;
+    return registryDirectory.childFile('GeneratedPluginRegistrant.h');
+  }
+
+  File get pluginRegistrantImplementation {
+    final Directory registryDirectory = isModule ? pluginRegistrantHost.childDirectory('Classes') : pluginRegistrantHost;
+    return registryDirectory.childFile('GeneratedPluginRegistrant.m');
+  }
+
+  Directory get engineCopyDirectory {
+    return isModule
+        ? ephemeralDirectory.childDirectory('Flutter').childDirectory('engine')
+        : hostAppRoot.childDirectory('Flutter');
+  }
+
   Future<void> _overwriteFromTemplate(String path, Directory target) async {
     final Template template = await Template.fromName(
       path,