Pass environment variables through to xcodebuild (#43553)

diff --git a/packages/flutter_tools/lib/src/ios/xcodeproj.dart b/packages/flutter_tools/lib/src/ios/xcodeproj.dart
index 9244719..40bdd7d 100644
--- a/packages/flutter_tools/lib/src/ios/xcodeproj.dart
+++ b/packages/flutter_tools/lib/src/ios/xcodeproj.dart
@@ -293,9 +293,10 @@
       '-target',
       target,
       '-showBuildSettings',
+      ...environmentVariablesAsXcodeBuildSettings()
     ];
     try {
-      // showBuildSettings is reported to ocassionally timeout. Here, we give it
+      // showBuildSettings is reported to occasionally timeout. Here, we give it
       // a lot of wiggle room (locally on Flutter Gallery, this takes ~1s).
       // When there is a timeout, we retry once.
       final RunResult result = await processUtils.run(
@@ -329,6 +330,7 @@
       scheme,
       '-quiet',
       'clean',
+      ...environmentVariablesAsXcodeBuildSettings()
     ], workingDirectory: fs.currentDirectory.path);
   }
 
@@ -354,6 +356,21 @@
   }
 }
 
+/// Environment variables prefixed by FLUTTER_XCODE_ will be passed as build configurations to xcodebuild.
+/// This allows developers to pass arbitrary build settings in without the tool needing to make a flag
+/// for or be aware of each one. This could be used to set code signing build settings in a CI
+/// environment without requiring settings changes in the Xcode project.
+List<String> environmentVariablesAsXcodeBuildSettings() {
+  const String xcodeBuildSettingPrefix = 'FLUTTER_XCODE_';
+  return platform.environment.entries.where((MapEntry<String, String> mapEntry) {
+    return mapEntry.key.startsWith(xcodeBuildSettingPrefix);
+  }).expand<String>((MapEntry<String, String> mapEntry) {
+    // Remove FLUTTER_XCODE_ prefix from the environment variable to get the build setting.
+    final String trimmedBuildSettingKey = mapEntry.key.substring(xcodeBuildSettingPrefix.length);
+    return <String>['$trimmedBuildSettingKey=${mapEntry.value}'];
+  }).toList();
+}
+
 Map<String, String> parseXcodeBuildSettings(String showBuildSettingsOutput) {
   final Map<String, String> settings = <String, String>{};
   for (Match match in showBuildSettingsOutput.split('\n').map<Match>(_settingExpr.firstMatch)) {