Build macOS engine as an xcframework (#50300)

Creates and adds FlutterMacOS.xcframework to out/mac or out/host.

Creates and archives FlutterMacOS.xcframework when building mac_host_engine. Archives the xcframework in a new zipped folder at `darwin-x64/framework.zip`, `darwin-x64-profile/framework.zip`, `darwin-x64-release/framework.zip`.

The FlutterMacOS.framework is also still archived currently - I thought it'd be better to keep it archived so we don't have to worry about the tool breaking until we're ready to remove it.

Part of https://github.com/flutter/flutter/issues/126016.

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
diff --git a/ci/builders/mac_host_engine.json b/ci/builders/mac_host_engine.json
index e6f5ff0..8998f67 100644
--- a/ci/builders/mac_host_engine.json
+++ b/ci/builders/mac_host_engine.json
@@ -476,6 +476,21 @@
             "source": "out/release/snapshot/gen_snapshot.zip",
             "destination": "darwin-x64-release/gen_snapshot.zip",
             "realm": "production"
+        },
+        {
+            "source": "out/debug/framework/framework.zip",
+            "destination": "darwin-x64/framework.zip",
+            "realm": "production"
+        },
+        {
+            "source": "out/profile/framework/framework.zip",
+            "destination": "darwin-x64-profile/framework.zip",
+            "realm": "production"
+        },
+        {
+            "source": "out/release/framework/framework.zip",
+            "destination": "darwin-x64-release/framework.zip",
+            "realm": "production"
         }
     ]
 }
diff --git a/shell/platform/darwin/macos/BUILD.gn b/shell/platform/darwin/macos/BUILD.gn
index b29d51e..aae1e51 100644
--- a/shell/platform/darwin/macos/BUILD.gn
+++ b/shell/platform/darwin/macos/BUILD.gn
@@ -304,7 +304,17 @@
   }
 }
 
-group("flutter_framework") {
+action("flutter_framework") {
+  script = "//flutter/sky/tools/create_xcframework.py"
+  outputs = [ "$root_out_dir/FlutterMacOS.xcframework" ]
+  args = [
+    "--frameworks",
+    rebase_path(_flutter_framework_dir),
+    "--name",
+    "FlutterMacOS",
+    "--location",
+    rebase_path(root_out_dir),
+  ]
   deps = [ ":_generate_symlinks_and_verify_framework_module" ]
 }
 
diff --git a/sky/tools/create_macos_framework.py b/sky/tools/create_macos_framework.py
index bf4b0bb..457a67e 100755
--- a/sky/tools/create_macos_framework.py
+++ b/sky/tools/create_macos_framework.py
@@ -11,6 +11,8 @@
 import sys
 import os
 
+from create_xcframework import create_xcframework  # pylint: disable=import-error
+
 buildroot_dir = os.path.abspath(os.path.join(os.path.realpath(__file__), '..', '..', '..', '..'))
 
 ARCH_SUBPATH = 'mac-arm64' if platform.processor() == 'arm' else 'mac-x64'
@@ -23,7 +25,9 @@
 
 
 def main():
-  parser = argparse.ArgumentParser(description='Creates FlutterMacOS.framework for macOS')
+  parser = argparse.ArgumentParser(
+      description='Creates FlutterMacOS.framework and FlutterMacOS.xcframework for macOS'
+  )
 
   parser.add_argument('--dst', type=str, required=True)
   parser.add_argument('--arm64-out-dir', type=str, required=True)
@@ -96,6 +100,10 @@
   find_subprocess.wait()
   xargs_subprocess.wait()
 
+  # Create XCFramework from the arm64 and x64 fat framework.
+  xcframeworks = [fat_framework]
+  create_xcframework(location=dst, name='FlutterMacOS', frameworks=xcframeworks)
+
   process_framework(dst, args, fat_framework, fat_framework_binary)
 
   return 0
@@ -202,6 +210,32 @@
     final_dst_path = os.path.join(dst, 'FlutterMacOS.framework.zip')
     shutil.move(final_src_path, final_dst_path)
 
+    zip_xcframework_archive(dst)
+
+
+def zip_xcframework_archive(dst):
+  filepath_with_entitlements = ''
+  filepath_without_entitlements = (
+      'FlutterMacOS.xcframework/macos-arm64_x84_64/'
+      'FlutterMacOS.framework/Versions/A/FlutterMacOS'
+  )
+  embed_codesign_configuration(os.path.join(dst, 'entitlements.txt'), filepath_with_entitlements)
+
+  embed_codesign_configuration(
+      os.path.join(dst, 'without_entitlements.txt'), filepath_without_entitlements
+  )
+
+  subprocess.check_call([
+      'zip',
+      '-r',
+      '-y',
+      'framework.zip',
+      'FlutterMacOS.xcframework',
+      'entitlements.txt',
+      'without_entitlements.txt',
+  ],
+                        cwd=dst)
+
 
 if __name__ == '__main__':
   sys.exit(main())