Change the way macOS app names are located (#32706)

Instead of requiring a name_output.sh, expect a file called
.app_filename in the macos/Flutter directory containing just the name of
the application. The expectation is that the Xcode build will create
that file with a script.

This is not intended as a long-term solution, but it's a substantial
improvement over name_output.sh:
- name_output.sh required constructing the full build output path; this
  made sense when it was coupled with build.sh, but now that the
  decision for where build output goes lives in flutter_tool, that logic
  should as well.
- Changing the name of the application required also updating
  name_output.sh, which is error-prone. With .app_filename, it can be
  created using $PRODUCT_NAME, which means that the usual way of setting
  the application name will automatically update this flow as well.

Part of #30706
diff --git a/packages/flutter_tools/lib/src/macos/application_package.dart b/packages/flutter_tools/lib/src/macos/application_package.dart
index 90220a3..cfa4abc 100644
--- a/packages/flutter_tools/lib/src/macos/application_package.dart
+++ b/packages/flutter_tools/lib/src/macos/application_package.dart
@@ -6,8 +6,6 @@
 
 import '../application_package.dart';
 import '../base/file_system.dart';
-import '../base/io.dart';
-import '../base/process_manager.dart';
 import '../build_info.dart';
 import '../globals.dart';
 import '../ios/plist_utils.dart' as plist;
@@ -123,21 +121,25 @@
 
   @override
   String applicationBundle(BuildMode buildMode) {
-    final ProcessResult result = processManager.runSync(<String>[
-      project.nameScript.path,
-      buildMode == BuildMode.debug ? 'debug' : 'release'
-    ], runInShell: true);
-    final String directory = result.stdout.toString().trim();
-    return directory;
+    final File appBundleNameFile = project.nameFile;
+    if (!appBundleNameFile.existsSync()) {
+      printError('Unable to find app name. ${appBundleNameFile.path} does not exist');
+      return null;
+    }
+    return fs.path.join(
+        getMacOSBuildDirectory(),
+        'Build',
+        'Products',
+        buildMode == BuildMode.debug ? 'Debug' : 'Release',
+        appBundleNameFile.readAsStringSync().trim());
   }
 
   @override
   String executable(BuildMode buildMode) {
-    final ProcessResult result = processManager.runSync(<String>[
-      project.nameScript.path,
-      buildMode == BuildMode.debug ? 'debug' : 'release'
-    ], runInShell: true);
-    final String directory = result.stdout.toString().trim();
+    final String directory = applicationBundle(buildMode);
+    if (directory == null) {
+      return null;
+    }
     final _ExecutableAndId executableAndId = MacOSApp._executableFromBundle(fs.directory(directory));
     return executableAndId.executable;
   }
diff --git a/packages/flutter_tools/lib/src/macos/macos_device.dart b/packages/flutter_tools/lib/src/macos/macos_device.dart
index 450aeb9..db1375a 100644
--- a/packages/flutter_tools/lib/src/macos/macos_device.dart
+++ b/packages/flutter_tools/lib/src/macos/macos_device.dart
@@ -77,10 +77,18 @@
       Cache.releaseLockEarly();
       await buildMacOS(FlutterProject.current(), debuggingOptions?.buildInfo);
     }
+
+    // Ensure that the executable is locatable.
+    final String executable = package.executable(debuggingOptions?.buildInfo?.mode);
+    if (executable == null) {
+      printError('Unable to find executable to run');
+      return LaunchResult.failed();
+    }
+
     // Make sure to call stop app after we've built.
     await stopApp(package);
     final Process process = await processManager.start(<String>[
-      package.executable(debuggingOptions?.buildInfo?.mode)
+      executable
     ]);
     if (debuggingOptions?.buildInfo?.isRelease == true) {
       return LaunchResult.succeeded();
diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart
index 0032d10..8fec10a 100644
--- a/packages/flutter_tools/lib/src/project.dart
+++ b/packages/flutter_tools/lib/src/project.dart
@@ -575,15 +575,20 @@
 
   Directory get _editableDirectory => project.directory.childDirectory('macos');
 
+  Directory get _cacheDirectory => _editableDirectory.childDirectory('Flutter');
+
   /// Contains definitions for FLUTTER_ROOT, LOCAL_ENGINE, and more flags for
   /// the Xcode build.
-  File get generatedXcodePropertiesFile => _editableDirectory.childDirectory('Flutter').childFile('Generated.xcconfig');
+  File get generatedXcodePropertiesFile => _cacheDirectory.childFile('Generated.xcconfig');
 
   /// The Xcode project file.
   Directory get xcodeProjectFile => _editableDirectory.childDirectory('Runner.xcodeproj');
 
-  // Note: The name script file exists as a temporary shim.
-  File get nameScript => project.directory.childDirectory('macos').childFile('name_output.sh');
+  /// The file where the Xcode build will write the name of the built app.
+  ///
+  /// Ideally this will be replaced in the future with inpection of the Runner
+  /// scheme's target.
+  File get nameFile => _cacheDirectory.childFile('.app_filename');
 }
 
 /// The Windows sub project