[native assets] Fix caching on `BuildMode` switching
diff --git a/packages/flutter_tools/bin/xcode_backend.dart b/packages/flutter_tools/bin/xcode_backend.dart
index 02a1e88..e48f874 100644
--- a/packages/flutter_tools/bin/xcode_backend.dart
+++ b/packages/flutter_tools/bin/xcode_backend.dart
@@ -482,7 +482,16 @@
       projectPath = environment['FLUTTER_APPLICATION_PATH']!;
     }
     final String flutterBuildDir = environment['FLUTTER_BUILD_DIR']!;
-    final nativeAssetsPath = '$projectPath/$flutterBuildDir/native_assets/${platform.name}/';
+    var nativeAssetsPath = '$projectPath/$flutterBuildDir/native_assets/${platform.name}/';
+    final String? builtProductsDir = environment['BUILT_PRODUCTS_DIR'];
+    if (builtProductsDir != null) {
+      final Directory nativeAssetsInBuiltProducts = directoryFromPath(
+        '$builtProductsDir/native_assets/',
+      );
+      if (nativeAssetsInBuiltProducts.existsSync()) {
+        nativeAssetsPath = '${nativeAssetsInBuiltProducts.path}/';
+      }
+    }
     final bool verbose = (environment['VERBOSE_SCRIPT_LOGGING'] ?? '').isNotEmpty;
 
     final Set<String> referencedFrameworks = {};
diff --git a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt
index 61026c0..e9d1fd6 100644
--- a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt
+++ b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt
@@ -719,10 +719,8 @@
                             into(abi ?: "null")
                         }
                         // Copy the native assets created by build.dart and placed in build/native_assets by flutter assemble.
-                        val buildDir =
-                            "${FlutterPluginUtils.getFlutterSourceDirectory(project)}/build"
                         val nativeAssetsDir =
-                            "$buildDir/native_assets/android/jniLibs/lib"
+                            "${flutterCompileTask.intermediateDir}/native_assets/jniLibs/lib"
                         from("$nativeAssetsDir/$abi") {
                             include("*.so")
                             into(abi ?: "null")
diff --git a/packages/flutter_tools/lib/src/build_system/targets/android.dart b/packages/flutter_tools/lib/src/build_system/targets/android.dart
index 76b2739..92ba6ca 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/android.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/android.dart
@@ -31,6 +31,7 @@
   @override
   List<Source> get inputs => const <Source>[
     Source.pattern('{BUILD_DIR}/app.dill'),
+    Source.pattern('{BUILD_DIR}/${DartBuild.dartHookResultFilename}'),
     ...IconTreeShaker.inputs,
   ];
 
diff --git a/packages/flutter_tools/lib/src/build_system/targets/assets.dart b/packages/flutter_tools/lib/src/build_system/targets/assets.dart
index f9ebbae..f5d896b 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/assets.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/assets.dart
@@ -247,17 +247,14 @@
   String get name => 'copy_assets';
 
   @override
-  List<Target> get dependencies => const <Target>[
-    DartBuildForNative(),
-    KernelSnapshot(),
-    InstallCodeAssets(),
-  ];
+  List<Target> get dependencies => const <Target>[DartBuildForNative(), KernelSnapshot()];
 
   @override
   List<Source> get inputs => const <Source>[
     Source.pattern(
       '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/assets.dart',
     ),
+    Source.pattern('{BUILD_DIR}/${DartBuild.dartHookResultFilename}'),
     ...IconTreeShaker.inputs,
     ...ShaderCompiler.inputs,
   ];
@@ -288,11 +285,6 @@
       targetPlatform: targetPlatform,
       buildMode: buildMode,
       flavor: environment.defines[kFlavor],
-      additionalContent: <String, DevFSContent>{
-        'NativeAssetsManifest.json': DevFSFileContent(
-          environment.buildDir.childFile('native_assets.json'),
-        ),
-      },
     );
     environment.depFileService.writeToFile(
       depfile,
diff --git a/packages/flutter_tools/lib/src/build_system/targets/common.dart b/packages/flutter_tools/lib/src/build_system/targets/common.dart
index f469540..6e54a2d 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/common.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/common.dart
@@ -39,6 +39,7 @@
     Source.artifact(Artifact.vmSnapshotData, mode: BuildMode.debug),
     Source.artifact(Artifact.isolateSnapshotData, mode: BuildMode.debug),
     Source.pattern('{BUILD_DIR}/app.dill'),
+    Source.pattern('{BUILD_DIR}/${DartBuild.dartHookResultFilename}'),
     ...IconTreeShaker.inputs,
     ...ShaderCompiler.inputs,
   ];
@@ -48,6 +49,7 @@
     Source.pattern('{OUTPUT_DIR}/vm_snapshot_data'),
     Source.pattern('{OUTPUT_DIR}/isolate_snapshot_data'),
     Source.pattern('{OUTPUT_DIR}/kernel_blob.bin'),
+    Source.pattern('{BUILD_DIR}/${DartBuild.dartHookResultFilename}'),
   ];
 
   @override
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 3d8fc92..244138e 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/ios.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/ios.dart
@@ -637,6 +637,7 @@
   List<Source> get inputs => const <Source>[
     Source.pattern('{BUILD_DIR}/App.framework/App'),
     Source.pattern('{PROJECT_DIR}/pubspec.yaml'),
+    Source.pattern('{BUILD_DIR}/${DartBuild.dartHookResultFilename}'),
     ...IconTreeShaker.inputs,
     ...ShaderCompiler.inputs,
   ];
diff --git a/packages/flutter_tools/lib/src/build_system/targets/linux.dart b/packages/flutter_tools/lib/src/build_system/targets/linux.dart
index eb346d6..da7d028 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/linux.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/linux.dart
@@ -104,6 +104,7 @@
   List<Source> get inputs => const <Source>[
     Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/linux.dart'),
     Source.pattern('{PROJECT_DIR}/pubspec.yaml'),
+    Source.pattern('{BUILD_DIR}/${DartBuild.dartHookResultFilename}'),
     ...IconTreeShaker.inputs,
   ];
 
diff --git a/packages/flutter_tools/lib/src/build_system/targets/macos.dart b/packages/flutter_tools/lib/src/build_system/targets/macos.dart
index 4387c80..a2cf39a 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/macos.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/macos.dart
@@ -393,6 +393,7 @@
   @override
   List<Source> get inputs => const <Source>[
     Source.pattern('{BUILD_DIR}/App.framework/App'),
+    Source.pattern('{BUILD_DIR}/${DartBuild.dartHookResultFilename}'),
     ...IconTreeShaker.inputs,
   ];
 
diff --git a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart
index db2ba13..37e8a6d 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart
@@ -80,7 +80,8 @@
     Source.pattern(
       '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart',
     ),
-    // If different packages are resolved, different native assets might need to be built.
+    // If different packages are resolved, different native assets might need to
+    // be built.
     Source.pattern('{WORKSPACE_DIR}/.dart_tool/package_config.json'),
     // TODO(mosuem): Should consume resources.json. https://github.com/flutter/flutter/issues/146263
   ];
@@ -140,6 +141,14 @@
     // And install/copy the code assets to the right place and create a
     // native_asset.yaml that can be used by the final AOT compilation.
     final Uri nativeAssetsFileUri = environment.buildDir.childFile(nativeAssetsFilename).uri;
+
+    Uri targetUri = environment.outputDir.childDirectory('native_assets').uri;
+    final String osName = targetPlatform.osName;
+    if (osName == 'linux' || osName == 'windows') {
+      // Avoid needing migration for CMake files, keep old directory structure.
+      targetUri = targetUri.resolve('$osName/');
+    }
+
     await installCodeAssets(
       dartHookResult: dartHookResult,
       environmentDefines: environment.defines,
@@ -147,6 +156,7 @@
       projectUri: projectUri,
       fileSystem: fileSystem,
       nativeAssetsFileUri: nativeAssetsFileUri,
+      targetUri: targetUri,
     );
     assert(await fileSystem.file(nativeAssetsFileUri).exists());
 
@@ -172,7 +182,10 @@
     Source.pattern(
       '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart',
     ),
-    // If different packages are resolved, different native assets might need to be built.
+    Source.pattern('{BUILD_DIR}/${DartBuild.dartHookResultFilename}'),
+    // If different packages are resolved, different native assets might need to
+    // be built. We can't depend on the exact outputs from `DartBuild`, so
+    // depend on all the same inputs.
     Source.pattern('{WORKSPACE_DIR}/.dart_tool/package_config.json'),
   ];
 
diff --git a/packages/flutter_tools/lib/src/build_system/targets/web.dart b/packages/flutter_tools/lib/src/build_system/targets/web.dart
index 1606256..68fcc73 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/web.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/web.dart
@@ -578,6 +578,7 @@
   @override
   List<Source> get inputs => <Source>[
     const Source.pattern('{PROJECT_DIR}/pubspec.yaml'),
+    const Source.pattern('{BUILD_DIR}/${DartBuild.dartHookResultFilename}'),
     ...buildPatternStems.map((String file) => Source.pattern('{BUILD_DIR}/$file')),
   ];
 
diff --git a/packages/flutter_tools/lib/src/build_system/targets/windows.dart b/packages/flutter_tools/lib/src/build_system/targets/windows.dart
index a6e2e4b..1e057a1 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/windows.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/windows.dart
@@ -118,6 +118,7 @@
     Source.pattern(
       '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/windows.dart',
     ),
+    Source.pattern('{BUILD_DIR}/${DartBuild.dartHookResultFilename}'),
     Source.pattern('{PROJECT_DIR}/pubspec.yaml'),
     ...IconTreeShaker.inputs,
   ];
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 b594d15..541de19 100644
--- a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart
+++ b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart
@@ -320,9 +320,7 @@
 
       // Copy the native assets. The native assets have already been signed in
       // buildNativeAssetsMacOS.
-      final Directory nativeAssetsDirectory = globals.fs
-          .directory(getBuildDirectory())
-          .childDirectory('native_assets/ios/');
+      final Directory nativeAssetsDirectory = iPhoneBuildOutput.childDirectory('native_assets');
       if (await nativeAssetsDirectory.exists()) {
         final ProcessResult rsyncResult = await globals.processManager.run(<Object>[
           'rsync',
@@ -333,7 +331,7 @@
           '- native_assets.yaml',
           '--filter',
           '- native_assets.json',
-          nativeAssetsDirectory.path,
+          '${nativeAssetsDirectory.path}${globals.fs.path.separator}',
           modeDirectory.path,
         ]);
         if (rsyncResult.exitCode != 0) {
diff --git a/packages/flutter_tools/lib/src/commands/build_macos_framework.dart b/packages/flutter_tools/lib/src/commands/build_macos_framework.dart
index 91ef484..9d52b96 100644
--- a/packages/flutter_tools/lib/src/commands/build_macos_framework.dart
+++ b/packages/flutter_tools/lib/src/commands/build_macos_framework.dart
@@ -119,9 +119,7 @@
       globals.logger.printStatus(' └─Moving to ${globals.fs.path.relative(modeDirectory.path)}');
 
       // Copy the native assets.
-      final Directory nativeAssetsDirectory = globals.fs
-          .directory(getBuildDirectory())
-          .childDirectory('native_assets/macos/');
+      final Directory nativeAssetsDirectory = buildOutput.childDirectory('native_assets');
       if (await nativeAssetsDirectory.exists()) {
         final ProcessResult rsyncResult = await globals.processManager.run(<Object>[
           'rsync',
@@ -132,7 +130,7 @@
           '- native_assets.yaml',
           '--filter',
           '- native_assets.json',
-          nativeAssetsDirectory.path,
+          '${nativeAssetsDirectory.path}${globals.fs.path.separator}',
           modeDirectory.path,
         ]);
         if (rsyncResult.exitCode != 0) {
diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/android/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/android/native_assets.dart
index 75572c7..6101d90 100644
--- a/packages/flutter_tools/lib/src/isolated/native_assets/android/native_assets.dart
+++ b/packages/flutter_tools/lib/src/isolated/native_assets/android/native_assets.dart
@@ -17,7 +17,7 @@
 }
 
 Future<void> copyNativeCodeAssetsAndroid(
-  Uri buildUri,
+  Uri targetUri,
   Map<FlutterCodeAsset, KernelAsset> assetTargetLocations,
   FileSystem fileSystem,
 ) async {
@@ -26,7 +26,7 @@
     for (final AndroidArch androidArch in AndroidArch.values) androidArch.archName,
   ];
   for (final jniArchDir in jniArchDirs) {
-    final Uri archUri = buildUri.resolve('jniLibs/lib/$jniArchDir/');
+    final Uri archUri = targetUri.resolve('jniLibs/lib/$jniArchDir/');
     await fileSystem.directory(archUri).create(recursive: true);
   }
   for (final MapEntry<FlutterCodeAsset, KernelAsset> assetMapping in assetTargetLocations.entries) {
@@ -34,9 +34,9 @@
     final Uri target = (assetMapping.value.path as KernelAssetAbsolutePath).uri;
     final AndroidArch androidArch = _getAndroidArch(assetMapping.value.target.architecture);
     final String jniArchDir = androidArch.archName;
-    final Uri archUri = buildUri.resolve('jniLibs/lib/$jniArchDir/');
-    final Uri targetUri = archUri.resolveUri(target);
-    final String targetFullPath = targetUri.toFilePath();
+    final Uri archUri = targetUri.resolve('jniLibs/lib/$jniArchDir/');
+    final Uri assetTargetUri = archUri.resolveUri(target);
+    final String targetFullPath = assetTargetUri.toFilePath();
     await fileSystem.file(source).copy(targetFullPath);
   }
 }
diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/ios/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/ios/native_assets.dart
index a720357..503ff9f 100644
--- a/packages/flutter_tools/lib/src/isolated/native_assets/ios/native_assets.dart
+++ b/packages/flutter_tools/lib/src/isolated/native_assets/ios/native_assets.dart
@@ -93,7 +93,7 @@
 /// Code signing is also done here, so that it doesn't have to be done in
 /// in xcode_backend.dart.
 Future<void> copyNativeCodeAssetsIOS(
-  Uri buildUri,
+  Uri targetUri,
   Map<KernelAssetPath, List<FlutterCodeAsset>> assetTargetLocations,
   String? codesignIdentity,
   BuildMode buildMode,
@@ -110,8 +110,8 @@
       for (final FlutterCodeAsset source in assetMapping.value)
         fileSystem.file(source.codeAsset.file),
     ];
-    final Uri targetUri = buildUri.resolveUri(target);
-    final File dylibFile = fileSystem.file(targetUri);
+    final Uri assetTargetUri = targetUri.resolveUri(target);
+    final File dylibFile = fileSystem.file(assetTargetUri);
     final Directory frameworkDir = dylibFile.parent;
     if (!await frameworkDir.exists()) {
       await frameworkDir.create(recursive: true);
@@ -132,7 +132,7 @@
     dylibs.add((dylibFile, newInstallName, frameworkDir));
 
     await createInfoPlist(
-      targetUri.pathSegments.last,
+      assetTargetUri.pathSegments.last,
       frameworkDir,
       minimumIOSVersion: '$targetIOSVersion.0',
     );
diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets.dart
index c41cba9..63891b6 100644
--- a/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets.dart
+++ b/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets.dart
@@ -107,7 +107,7 @@
 /// Code signing is also done here, so that it doesn't have to be done in
 /// in macos_assemble.sh.
 Future<void> copyNativeCodeAssetsMacOS(
-  Uri buildUri,
+  Uri targetUri,
   Map<KernelAssetPath, List<FlutterCodeAsset>> assetTargetLocations,
   String? codesignIdentity,
   BuildMode buildMode,
@@ -125,9 +125,9 @@
       for (final FlutterCodeAsset source in assetMapping.value)
         fileSystem.file(source.codeAsset.file),
     ];
-    final Uri targetUri = buildUri.resolveUri(target);
-    final String name = targetUri.pathSegments.last;
-    final Directory frameworkDir = fileSystem.file(targetUri).parent;
+    final Uri assetTargetUri = targetUri.resolveUri(target);
+    final String name = assetTargetUri.pathSegments.last;
+    final Directory frameworkDir = fileSystem.file(assetTargetUri).parent;
     if (await frameworkDir.exists()) {
       await frameworkDir.delete(recursive: true);
     }
@@ -205,7 +205,7 @@
 ///
 /// Code signing is also done here.
 Future<void> copyNativeCodeAssetsMacOSFlutterTester(
-  Uri buildUri,
+  Uri targetUri,
   Map<KernelAssetPath, List<FlutterCodeAsset>> assetTargetLocations,
   String? codesignIdentity,
   BuildMode buildMode,
@@ -223,8 +223,8 @@
       for (final FlutterCodeAsset source in assetMapping.value)
         fileSystem.file(source.codeAsset.file),
     ];
-    final Uri targetUri = buildUri.resolveUri(target);
-    final File dylibFile = fileSystem.file(targetUri);
+    final Uri assetTargetUri = targetUri.resolveUri(target);
+    final File dylibFile = fileSystem.file(assetTargetUri);
     final Directory targetParent = dylibFile.parent;
     if (!await targetParent.exists()) {
       await targetParent.create(recursive: true);
diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets_host.dart b/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets_host.dart
index 02113b1..8e90dea 100644
--- a/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets_host.dart
+++ b/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets_host.dart
@@ -8,7 +8,7 @@
 
 import '../../../base/common.dart';
 import '../../../base/file_system.dart';
-import '../../../base/io.dart';
+import '../../../base/process.dart';
 import '../../../build_info.dart';
 import '../../../globals.dart' as globals;
 
@@ -62,7 +62,8 @@
 /// arm64 ios simulator cannot be combined with a dylib targeting arm64
 /// ios device or macos arm64.
 Future<void> lipoDylibs(File target, List<File> sources) async {
-  final ProcessResult lipoResult = await globals.processManager.run(<String>[
+  final RunResult lipoResult = await globals.processUtils.run(<String>[
+    'xcrun',
     'lipo',
     '-create',
     '-output',
@@ -72,8 +73,6 @@
   if (lipoResult.exitCode != 0) {
     throwToolExit('Failed to create universal binary:\n${lipoResult.stderr}');
   }
-  globals.logger.printTrace(lipoResult.stdout as String);
-  globals.logger.printTrace(lipoResult.stderr as String);
 }
 
 /// Sets the install names in a dylib with a Mach-O format.
@@ -93,7 +92,8 @@
   String newInstallName,
   Map<String, String> oldToNewInstallNames,
 ) async {
-  final ProcessResult setInstallNamesResult = await globals.processManager.run(<String>[
+  final RunResult setInstallNamesResult = await globals.processUtils.run(<String>[
+    'xcrun',
     'install_name_tool',
     '-id',
     newInstallName,
@@ -115,7 +115,8 @@
 }
 
 Future<Set<String>> getInstallNamesDylib(File dylibFile) async {
-  final ProcessResult installNameResult = await globals.processManager.run(<String>[
+  final RunResult installNameResult = await globals.processUtils.run(<String>[
+    'xcrun',
     'otool',
     '-D',
     dylibFile.path,
@@ -126,7 +127,7 @@
 
   return <String>{
     for (final List<String> architectureSection in parseOtoolArchitectureSections(
-      installNameResult.stdout as String,
+      installNameResult.stdout,
     ).values)
       // For each architecture, a separate install name is reported, which are
       // not necessarily the same.
@@ -136,15 +137,14 @@
 
 /// Creates a dSYM bundle for a dylib.
 Future<void> dsymutilDylib(File dylibFile, String dsymPath) async {
-  final ProcessResult result = await globals.processManager.run(<String>[
+  final RunResult result = await globals.processUtils.run(<String>[
+    'xcrun',
     'dsymutil',
     dylibFile.path,
     '-o',
     dsymPath,
   ]);
   if (result.exitCode != 0) {
-    globals.logger.printError(result.stdout as String);
-    globals.logger.printError(result.stderr as String);
     throwToolExit('dsymutil failed with exit code ${result.exitCode}');
   }
 }
@@ -153,15 +153,16 @@
 ///
 /// This is useful for release builds to reduce binary size.
 Future<void> stripDylib(File dylibFile) async {
-  final ProcessResult result = await globals.processManager.run(<String>[
+  final RunResult result = await globals.processUtils.run(<String>[
+    'xcrun',
     'strip',
     '-x', // Remove local symbols.
     '-S', // Remove debugging symbol table.
     dylibFile.path,
   ]);
   if (result.exitCode != 0) {
-    globals.logger.printError(result.stdout as String);
-    globals.logger.printError(result.stderr as String);
+    globals.logger.printError(result.stdout);
+    globals.logger.printError(result.stderr);
     throwToolExit('strip failed with exit code ${result.exitCode}');
   }
 }
@@ -175,6 +176,7 @@
     codesignIdentity = '-';
   }
   final codesignCommand = <String>[
+    'xcrun',
     'codesign',
     '--force',
     '--sign',
@@ -185,16 +187,13 @@
     ],
     target.path,
   ];
-  globals.logger.printTrace(codesignCommand.join(' '));
-  final ProcessResult codesignResult = await globals.processManager.run(codesignCommand);
+  final RunResult codesignResult = await globals.processUtils.run(codesignCommand);
   if (codesignResult.exitCode != 0) {
     throwToolExit(
       'Failed to code sign binary: exit code: ${codesignResult.exitCode} '
       '${codesignResult.stdout} ${codesignResult.stderr}',
     );
   }
-  globals.logger.printTrace(codesignResult.stdout as String);
-  globals.logger.printTrace(codesignResult.stderr as String);
 }
 
 /// Flutter expects `xcrun` to be on the path on macOS hosts.
@@ -218,7 +217,7 @@
 
 /// Invokes `xcrun --find` to find the full path to [binaryName].
 Future<Uri?> _findXcrunBinary(String binaryName, bool throwIfNotFound) async {
-  final ProcessResult xcrunResult = await globals.processManager.run(<String>[
+  final RunResult xcrunResult = await globals.processUtils.run(<String>[
     'xcrun',
     '--find',
     binaryName,
@@ -230,7 +229,7 @@
       return null;
     }
   }
-  return Uri.file((xcrunResult.stdout as String).trim());
+  return Uri.file(xcrunResult.stdout.trim());
 }
 
 /// Converts [fileName] into a suitable framework name.
diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/native_assets.dart
index c35275a..747035e 100644
--- a/packages/flutter_tools/lib/src/isolated/native_assets/native_assets.dart
+++ b/packages/flutter_tools/lib/src/isolated/native_assets/native_assets.dart
@@ -55,14 +55,6 @@
   required bool buildCodeAssets,
   required bool buildDataAssets,
 }) async {
-  final Uri buildUri = nativeAssetsBuildUri(projectUri, targetPlatform.osName);
-  final Directory buildDir = fileSystem.directory(buildUri);
-  if (!await buildDir.exists()) {
-    // Ensure the folder exists so the native build system can copy it even
-    // if there's no native assets.
-    await buildDir.create(recursive: true);
-  }
-
   if (!await _hookRunRequired(buildRunner)) {
     return DartHooksResult.empty();
   }
@@ -105,9 +97,9 @@
   required Uri projectUri,
   required FileSystem fileSystem,
   required Uri nativeAssetsFileUri,
+  required Uri targetUri,
 }) async {
   final OS targetOS = getNativeOSFromTargetPlatform(targetPlatform);
-  final Uri buildUri = nativeAssetsBuildUri(projectUri, targetOS.name);
   final flutterTester = targetPlatform == TargetPlatform.tester;
   final BuildMode buildMode = _getBuildMode(environmentDefines, flutterTester);
 
@@ -116,11 +108,11 @@
     targetOS,
     dartHookResult.codeAssets,
     flutterTester,
-    buildUri,
+    targetUri,
   );
   await _copyNativeCodeAssetsForOS(
     targetOS,
-    buildUri,
+    targetUri,
     buildMode,
     fileSystem,
     assetTargetLocations,
@@ -364,13 +356,6 @@
   );
 }
 
-/// This should be the same for different archs, debug/release, etc.
-/// It should work for all macOS.
-Uri nativeAssetsBuildUri(Uri projectUri, String osName) {
-  final String buildDir = getBuildDirectory();
-  return projectUri.resolve('$buildDir/native_assets/$osName/');
-}
-
 Map<FlutterCodeAsset, KernelAsset> _assetTargetLocationsWindowsLinux(
   List<FlutterCodeAsset> assets,
   Uri? absolutePath,
@@ -435,7 +420,7 @@
 
 Future<void> _copyNativeCodeAssetsForOS(
   OS targetOS,
-  Uri buildUri,
+  Uri targetUri,
   BuildMode buildMode,
   FileSystem fileSystem,
   Map<FlutterCodeAsset, KernelAsset> assetTargetLocations,
@@ -452,18 +437,23 @@
         codeAsset: assetTargetLocations[codeAsset]!,
   };
 
+  final Directory targetDir = fileSystem.directory(targetUri.toFilePath());
+  if (!targetDir.existsSync()) {
+    targetDir.createSync(recursive: true);
+  }
+
   if (assetTargetLocations.isEmpty) {
     return;
   }
 
-  globals.logger.printTrace('Copying native assets to ${buildUri.toFilePath()}.');
+  globals.logger.printTrace('Copying native assets to ${targetUri.toFilePath()}.');
   final List<FlutterCodeAsset> codeAssets = assetTargetLocations.keys.toList();
   switch (targetOS) {
     case OS.windows:
     case OS.linux:
       assert(codesignIdentity == null);
       await _copyNativeCodeAssetsToBundleOnWindowsLinux(
-        buildUri,
+        targetUri,
         assetTargetLocations,
         buildMode,
         fileSystem,
@@ -471,15 +461,15 @@
     case OS.macOS:
       if (flutterTester) {
         await copyNativeCodeAssetsMacOSFlutterTester(
-          buildUri,
-          fatAssetTargetLocationsMacOS(codeAssets, buildUri),
+          targetUri,
+          fatAssetTargetLocationsMacOS(codeAssets, targetUri),
           codesignIdentity,
           buildMode,
           fileSystem,
         );
       } else {
         await copyNativeCodeAssetsMacOS(
-          buildUri,
+          targetUri,
           fatAssetTargetLocationsMacOS(codeAssets, null),
           codesignIdentity,
           buildMode,
@@ -488,7 +478,7 @@
       }
     case OS.iOS:
       await copyNativeCodeAssetsIOS(
-        buildUri,
+        targetUri,
         fatAssetTargetLocationsIOS(codeAssets),
         codesignIdentity,
         buildMode,
@@ -496,7 +486,7 @@
       );
     case OS.android:
       assert(codesignIdentity == null);
-      await copyNativeCodeAssetsAndroid(buildUri, assetTargetLocations, fileSystem);
+      await copyNativeCodeAssetsAndroid(targetUri, assetTargetLocations, fileSystem);
     default:
       throw StateError('This should be unreachable.');
   }
@@ -560,13 +550,6 @@
     dataAssets.addAll(_filterDataAssets(buildResult.encodedAssets));
     dependencies.addAll(buildResult.dependencies);
   }
-  if (codeAssets.isNotEmpty) {
-    globals.logger.printTrace(
-      'Note: You are using the dart build hooks feature which is currently '
-      'in preview. Please see '
-      'https://dart.dev/interop/c-interop#native-assets for more details.',
-    );
-  }
 
   if (dataAssets.map((DataAsset asset) => asset.id).toSet().length != dataAssets.length) {
     throwToolExit(
@@ -632,22 +615,18 @@
 }
 
 Future<void> _copyNativeCodeAssetsToBundleOnWindowsLinux(
-  Uri buildUri,
+  Uri targetUri,
   Map<FlutterCodeAsset, KernelAsset> assetTargetLocations,
   BuildMode buildMode,
   FileSystem fileSystem,
 ) async {
   assert(assetTargetLocations.isNotEmpty);
 
-  final Directory buildDir = fileSystem.directory(buildUri.toFilePath());
-  if (!buildDir.existsSync()) {
-    buildDir.createSync(recursive: true);
-  }
   for (final MapEntry<FlutterCodeAsset, KernelAsset> assetMapping in assetTargetLocations.entries) {
     final Uri source = assetMapping.key.codeAsset.file!;
     final Uri target = (assetMapping.value.path as KernelAssetAbsolutePath).uri;
-    final Uri targetUri = buildUri.resolveUri(target);
-    final String targetFullPath = targetUri.toFilePath();
+    final Uri assetTargetUri = targetUri.resolveUri(target);
+    final String targetFullPath = assetTargetUri.toFilePath();
     await fileSystem.file(source).copy(targetFullPath);
   }
 }
diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/test/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/test/native_assets.dart
index 8ad0579..d538d13 100644
--- a/packages/flutter_tools/lib/src/isolated/native_assets/test/native_assets.dart
+++ b/packages/flutter_tools/lib/src/isolated/native_assets/test/native_assets.dart
@@ -22,8 +22,10 @@
   Future<Uri?> build(BuildInfo buildInfo) => testCompilerBuildNativeAssets(buildInfo);
 
   @override
-  String windowsBuildDirectory(FlutterProject project) =>
-      nativeAssetsBuildUri(project.directory.uri, OS.windows.name).toFilePath();
+  String windowsBuildDirectory(FlutterProject project) {
+    final String buildDir = getBuildDirectory();
+    return project.directory.uri.resolve('$buildDir/native_assets/windows/').toFilePath();
+  }
 }
 
 Future<Uri?> testCompilerBuildNativeAssets(BuildInfo buildInfo) async {
@@ -61,7 +63,9 @@
   // `build/native_assets/<os>/native_assets.json` file which uses absolute
   // paths to the shared libraries.
   final OS targetOS = getNativeOSFromTargetPlatform(TargetPlatform.tester);
-  final Uri buildUri = nativeAssetsBuildUri(projectUri, targetOS.name);
+  final String buildDir = getBuildDirectory();
+  final String osName = targetOS.name;
+  final Uri buildUri = projectUri.resolve('$buildDir/native_assets/$osName/');
   final Uri nativeAssetsFileUri = buildUri.resolve('native_assets.json');
 
   final environmentDefines = <String, String>{kBuildMode: buildInfo.mode.cliName};
@@ -85,6 +89,7 @@
     projectUri: projectUri,
     fileSystem: globals.fs,
     nativeAssetsFileUri: nativeAssetsFileUri,
+    targetUri: projectUri.resolve('${getBuildDirectory()}/native_assets/$osName/'),
   );
   assert(await globals.fs.file(nativeAssetsFileUri).exists());
 
diff --git a/packages/flutter_tools/test/general.shard/isolated/android/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/android/native_assets_test.dart
index 8506c19..ed7691c 100644
--- a/packages/flutter_tools/test/general.shard/isolated/android/native_assets_test.dart
+++ b/packages/flutter_tools/test/general.shard/isolated/android/native_assets_test.dart
@@ -101,6 +101,7 @@
           projectUri: projectUri,
           fileSystem: fileSystem,
           nativeAssetsFileUri: nonFlutterTesterAssetUri,
+          targetUri: projectUri.resolve('${getBuildDirectory()}/native_assets/android/'),
         );
         expect(
           (globals.logger as BufferLogger).traceText,
diff --git a/packages/flutter_tools/test/general.shard/isolated/build_system/targets/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/build_system/targets/native_assets_test.dart
index f4661ee..9b2e943 100644
--- a/packages/flutter_tools/test/general.shard/isolated/build_system/targets/native_assets_test.dart
+++ b/packages/flutter_tools/test/general.shard/isolated/build_system/targets/native_assets_test.dart
@@ -143,32 +143,34 @@
         // Create the framework dylib.
         const FakeCommand(
           command: <Pattern>[
+            'xcrun',
             'lipo',
             '-create',
             '-output',
-            '/build/native_assets/ios/foo.framework/foo',
+            '/native_assets/foo.framework/foo',
             'foo.framework/foo',
           ],
         ),
         const FakeCommand(
           command: <Pattern>[
+            'xcrun',
             'dsymutil',
-            '/build/native_assets/ios/foo.framework/foo',
+            '/native_assets/foo.framework/foo',
             '-o',
-            '/build/native_assets/ios/foo.framework.dSYM',
+            '/native_assets/foo.framework.dSYM',
           ],
         ),
         const FakeCommand(
-          command: <Pattern>['strip', '-x', '-S', '/build/native_assets/ios/foo.framework/foo'],
+          command: <Pattern>['xcrun', 'strip', '-x', '-S', '/native_assets/foo.framework/foo'],
         ),
         // Lookup the original install names of the dylib.
         // There can be different install names for different architectures.
         FakeCommand(
-          command: const <Pattern>['otool', '-D', '/build/native_assets/ios/foo.framework/foo'],
+          command: const <Pattern>['xcrun', 'otool', '-D', '/native_assets/foo.framework/foo'],
           stdout: <String>[
-            '/build/native_assets/ios/foo.framework/foo (architecture x86_64):',
+            '/native_assets/foo.framework/foo (architecture x86_64):',
             '@rpath/libfoo.dylib',
-            '/build/native_assets/ios/foo.framework/foo (architecture arm64):',
+            '/native_assets/foo.framework/foo (architecture arm64):',
             '@rpath/libfoo.dylib',
           ].join('\n'),
         ),
@@ -178,24 +180,26 @@
         // is ignored if the dylib does not depend on the target dylib.
         const FakeCommand(
           command: <Pattern>[
+            'xcrun',
             'install_name_tool',
             '-id',
             '@rpath/foo.framework/foo',
             '-change',
             '@rpath/libfoo.dylib',
             '@rpath/foo.framework/foo',
-            '/build/native_assets/ios/foo.framework/foo',
+            '/native_assets/foo.framework/foo',
           ],
         ),
         // Only after all changes to the dylib have been made do we sign it.
         const FakeCommand(
           command: <Pattern>[
+            'xcrun',
             'codesign',
             '--force',
             '--sign',
             '-',
             '--timestamp=none',
-            '/build/native_assets/ios/foo.framework',
+            '/native_assets/foo.framework',
           ],
         ),
       ]),
diff --git a/packages/flutter_tools/test/general.shard/isolated/ios/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/ios/native_assets_test.dart
index cb5dc3f..368cb47 100644
--- a/packages/flutter_tools/test/general.shard/isolated/ios/native_assets_test.dart
+++ b/packages/flutter_tools/test/general.shard/isolated/ios/native_assets_test.dart
@@ -54,6 +54,7 @@
         ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
           const FakeCommand(
             command: <Pattern>[
+              'xcrun',
               'lipo',
               '-create',
               '-output',
@@ -65,6 +66,7 @@
           if (buildMode == BuildMode.release) ...<FakeCommand>[
             const FakeCommand(
               command: <Pattern>[
+                'xcrun',
                 'dsymutil',
                 '/build/native_assets/ios/bar.framework/bar',
                 '-o',
@@ -72,11 +74,22 @@
               ],
             ),
             const FakeCommand(
-              command: <Pattern>['strip', '-x', '-S', '/build/native_assets/ios/bar.framework/bar'],
+              command: <Pattern>[
+                'xcrun',
+                'strip',
+                '-x',
+                '-S',
+                '/build/native_assets/ios/bar.framework/bar',
+              ],
             ),
           ],
           FakeCommand(
-            command: const <Pattern>['otool', '-D', '/build/native_assets/ios/bar.framework/bar'],
+            command: const <Pattern>[
+              'xcrun',
+              'otool',
+              '-D',
+              '/build/native_assets/ios/bar.framework/bar',
+            ],
             stdout: <String>[
               '/build/native_assets/ios/bar.framework/bar (architecture x86_64):',
               '@rpath/libbar.dylib',
@@ -86,6 +99,7 @@
           ),
           const FakeCommand(
             command: <Pattern>[
+              'xcrun',
               'lipo',
               '-create',
               '-output',
@@ -97,6 +111,7 @@
           if (buildMode == BuildMode.release) ...<FakeCommand>[
             const FakeCommand(
               command: <Pattern>[
+                'xcrun',
                 'dsymutil',
                 '/build/native_assets/ios/buz.framework/buz',
                 '-o',
@@ -104,11 +119,22 @@
               ],
             ),
             const FakeCommand(
-              command: <Pattern>['strip', '-x', '-S', '/build/native_assets/ios/buz.framework/buz'],
+              command: <Pattern>[
+                'xcrun',
+                'strip',
+                '-x',
+                '-S',
+                '/build/native_assets/ios/buz.framework/buz',
+              ],
             ),
           ],
           FakeCommand(
-            command: const <Pattern>['otool', '-D', '/build/native_assets/ios/buz.framework/buz'],
+            command: const <Pattern>[
+              'xcrun',
+              'otool',
+              '-D',
+              '/build/native_assets/ios/buz.framework/buz',
+            ],
             stdout: <String>[
               '/build/native_assets/ios/buz.framework/buz (architecture x86_64):',
               '@rpath/libbuz.dylib',
@@ -118,6 +144,7 @@
           ),
           const FakeCommand(
             command: <Pattern>[
+              'xcrun',
               'install_name_tool',
               '-id',
               '@rpath/bar.framework/bar',
@@ -132,6 +159,7 @@
           ),
           FakeCommand(
             command: <Pattern>[
+              'xcrun',
               'codesign',
               '--force',
               '--sign',
@@ -142,6 +170,7 @@
           ),
           const FakeCommand(
             command: <Pattern>[
+              'xcrun',
               'install_name_tool',
               '-id',
               '@rpath/buz.framework/buz',
@@ -156,6 +185,7 @@
           ),
           FakeCommand(
             command: <Pattern>[
+              'xcrun',
               'codesign',
               '--force',
               '--sign',
@@ -227,6 +257,7 @@
           projectUri: projectUri,
           fileSystem: fileSystem,
           nativeAssetsFileUri: nonFlutterTesterAssetUri,
+          targetUri: projectUri.resolve('${getBuildDirectory()}/native_assets/ios/'),
         );
         expect(
           (globals.logger as BufferLogger).traceText,
diff --git a/packages/flutter_tools/test/general.shard/isolated/macos/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/macos/native_assets_test.dart
index e945356..6bcdfc3 100644
--- a/packages/flutter_tools/test/general.shard/isolated/macos/native_assets_test.dart
+++ b/packages/flutter_tools/test/general.shard/isolated/macos/native_assets_test.dart
@@ -82,6 +82,7 @@
             if (flutterTester) ...<FakeCommand>[
               FakeCommand(
                 command: <Pattern>[
+                  'xcrun',
                   'lipo',
                   '-create',
                   '-output',
@@ -91,12 +92,12 @@
               ),
               if (buildMode == BuildMode.release) ...<FakeCommand>[
                 FakeCommand(
-                  command: <Pattern>['dsymutil', dylibPathBar, '-o', '$signPathBar.dSYM'],
+                  command: <Pattern>['xcrun', 'dsymutil', dylibPathBar, '-o', '$signPathBar.dSYM'],
                 ),
-                FakeCommand(command: <Pattern>['strip', '-x', '-S', dylibPathBar]),
+                FakeCommand(command: <Pattern>['xcrun', 'strip', '-x', '-S', dylibPathBar]),
               ],
               FakeCommand(
-                command: <Pattern>['otool', '-D', dylibPathBar],
+                command: <Pattern>['xcrun', 'otool', '-D', dylibPathBar],
                 stdout: <String>[
                   '$dylibPathBar (architecture x86_64):',
                   '@rpath/libbar.dylib',
@@ -106,6 +107,7 @@
               ),
               FakeCommand(
                 command: <Pattern>[
+                  'xcrun',
                   'lipo',
                   '-create',
                   '-output',
@@ -115,12 +117,12 @@
               ),
               if (buildMode == BuildMode.release) ...<FakeCommand>[
                 FakeCommand(
-                  command: <Pattern>['dsymutil', dylibPathBuz, '-o', '$signPathBuz.dSYM'],
+                  command: <Pattern>['xcrun', 'dsymutil', dylibPathBuz, '-o', '$signPathBuz.dSYM'],
                 ),
-                FakeCommand(command: <Pattern>['strip', '-x', '-S', dylibPathBuz]),
+                FakeCommand(command: <Pattern>['xcrun', 'strip', '-x', '-S', dylibPathBuz]),
               ],
               FakeCommand(
-                command: <Pattern>['otool', '-D', dylibPathBuz],
+                command: <Pattern>['xcrun', 'otool', '-D', dylibPathBuz],
                 stdout: <String>[
                   '$dylibPathBuz (architecture ${isArm64 ? 'arm64' : 'x86_64'}):',
                   '@rpath/libbuz.dylib',
@@ -128,6 +130,7 @@
               ),
               FakeCommand(
                 command: <Pattern>[
+                  'xcrun',
                   'install_name_tool',
                   '-id',
                   dylibPathBar,
@@ -142,6 +145,7 @@
               ),
               FakeCommand(
                 command: <Pattern>[
+                  'xcrun',
                   'codesign',
                   '--force',
                   '--sign',
@@ -152,6 +156,7 @@
               ),
               FakeCommand(
                 command: <Pattern>[
+                  'xcrun',
                   'install_name_tool',
                   '-id',
                   dylibPathBuz,
@@ -166,6 +171,7 @@
               ),
               FakeCommand(
                 command: <Pattern>[
+                  'xcrun',
                   'codesign',
                   '--force',
                   '--sign',
@@ -177,6 +183,7 @@
             ] else ...<FakeCommand>[
               FakeCommand(
                 command: <Pattern>[
+                  'xcrun',
                   'lipo',
                   '-create',
                   '-output',
@@ -187,12 +194,12 @@
               ),
               if (buildMode == BuildMode.release) ...<FakeCommand>[
                 FakeCommand(
-                  command: <Pattern>['dsymutil', dylibPathBar, '-o', '$signPathBar.dSYM'],
+                  command: <Pattern>['xcrun', 'dsymutil', dylibPathBar, '-o', '$signPathBar.dSYM'],
                 ),
-                FakeCommand(command: <Pattern>['strip', '-x', '-S', dylibPathBar]),
+                FakeCommand(command: <Pattern>['xcrun', 'strip', '-x', '-S', dylibPathBar]),
               ],
               FakeCommand(
-                command: <Pattern>['otool', '-D', dylibPathBar],
+                command: <Pattern>['xcrun', 'otool', '-D', dylibPathBar],
                 stdout: <String>[
                   '$dylibPathBar (architecture x86_64):',
                   '@rpath/libbar.dylib',
@@ -202,6 +209,7 @@
               ),
               FakeCommand(
                 command: <Pattern>[
+                  'xcrun',
                   'lipo',
                   '-create',
                   '-output',
@@ -212,12 +220,12 @@
               ),
               if (buildMode == BuildMode.release) ...<FakeCommand>[
                 FakeCommand(
-                  command: <Pattern>['dsymutil', dylibPathBuz, '-o', '$signPathBuz.dSYM'],
+                  command: <Pattern>['xcrun', 'dsymutil', dylibPathBuz, '-o', '$signPathBuz.dSYM'],
                 ),
-                FakeCommand(command: <Pattern>['strip', '-x', '-S', dylibPathBuz]),
+                FakeCommand(command: <Pattern>['xcrun', 'strip', '-x', '-S', dylibPathBuz]),
               ],
               FakeCommand(
-                command: <Pattern>['otool', '-D', dylibPathBuz],
+                command: <Pattern>['xcrun', 'otool', '-D', dylibPathBuz],
                 stdout: <String>[
                   '$dylibPathBuz (architecture x86_64):',
                   '@rpath/libbuz.dylib',
@@ -227,6 +235,7 @@
               ),
               FakeCommand(
                 command: <Pattern>[
+                  'xcrun',
                   'install_name_tool',
                   '-id',
                   '@rpath/bar.framework/bar',
@@ -241,6 +250,7 @@
               ),
               FakeCommand(
                 command: <Pattern>[
+                  'xcrun',
                   'install_name_tool',
                   '-id',
                   '@rpath/buz.framework/buz',
@@ -336,6 +346,7 @@
             projectUri: projectUri,
             fileSystem: fileSystem,
             nativeAssetsFileUri: nativeAssetsFileUri,
+            targetUri: projectUri.resolve('${getBuildDirectory()}/native_assets/macos/'),
           );
           final expectedArchsBeingBuilt = flutterTester
               ? (isArm64 ? 'macos_arm64' : 'macos_x64')
diff --git a/packages/flutter_tools/test/general.shard/isolated/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/native_assets_test.dart
index b487ebd..14cddeb 100644
--- a/packages/flutter_tools/test/general.shard/isolated/native_assets_test.dart
+++ b/packages/flutter_tools/test/general.shard/isolated/native_assets_test.dart
@@ -89,6 +89,7 @@
         projectUri: projectUri,
         fileSystem: fileSystem,
         nativeAssetsFileUri: nonFlutterTesterAssetUri,
+        targetUri: projectUri.resolve('${getBuildDirectory()}/native_assets/test/'),
       );
       expect(testLogger.traceText, isNot(contains('Copying native assets to')));
     },
@@ -145,6 +146,7 @@
         buildCodeAssets: true,
         buildDataAssets: true,
       );
+      final Uri targetUri = environment.buildDir.uri.resolve('native_assets/');
       await installCodeAssets(
         dartHookResult: dartHookResult,
         environmentDefines: environmentDefines,
@@ -152,18 +154,13 @@
         projectUri: projectUri,
         fileSystem: fileSystem,
         nativeAssetsFileUri: nonFlutterTesterAssetUri,
+        targetUri: targetUri,
       );
       expect(
         await fileSystem.file(nonFlutterTesterAssetUri).readAsString(),
         isNot(contains('package:bar/bar.dart')),
       );
-      expect(
-        environment.projectDir
-            .childDirectory('build')
-            .childDirectory('native_assets')
-            .childDirectory('windows'),
-        exists,
-      );
+      expect(fileSystem.directory(targetUri), exists);
     },
   );
 
diff --git a/packages/flutter_tools/test/general.shard/isolated/windows/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/windows/native_assets_test.dart
index d215c73..b92ed98 100644
--- a/packages/flutter_tools/test/general.shard/isolated/windows/native_assets_test.dart
+++ b/packages/flutter_tools/test/general.shard/isolated/windows/native_assets_test.dart
@@ -117,6 +117,7 @@
             projectUri: projectUri,
             fileSystem: fileSystem,
             nativeAssetsFileUri: nativeAssetsFileUri,
+            targetUri: projectUri.resolve('${getBuildDirectory()}/native_assets/windows/'),
           );
           final expectedOS = flutterTester ? OS.current.toString() : 'windows';
           final expectedArch = flutterTester ? Architecture.current.toString() : 'x64';