Write FLUTTER_BUILD_MODE when using a local engine (#51687)
diff --git a/packages/flutter_tools/lib/src/ios/xcodeproj.dart b/packages/flutter_tools/lib/src/ios/xcodeproj.dart
index dc9bbbb..92673b0 100644
--- a/packages/flutter_tools/lib/src/ios/xcodeproj.dart
+++ b/packages/flutter_tools/lib/src/ios/xcodeproj.dart
@@ -209,9 +209,20 @@
if (globals.artifacts is LocalEngineArtifacts) {
final LocalEngineArtifacts localEngineArtifacts = globals.artifacts as LocalEngineArtifacts;
- final String engineOutPath = localEngineArtifacts.engineOutPath;
+ final String engineOutPath = globals.fs.path.basename(localEngineArtifacts.engineOutPath);
+ String engineBuildMode = 'release';
+ if (engineOutPath.toLowerCase().contains('debug')) {
+ engineBuildMode = 'debug';
+ } else if (engineOutPath.toLowerCase().contains('profile')) {
+ engineBuildMode = 'profile';
+ }
xcodeBuildSettings.add('FLUTTER_ENGINE=${globals.fs.path.dirname(globals.fs.path.dirname(engineOutPath))}');
- xcodeBuildSettings.add('LOCAL_ENGINE=${globals.fs.path.basename(engineOutPath)}');
+ xcodeBuildSettings.add('LOCAL_ENGINE=$engineOutPath');
+ // Only write this or local engines, where it is supposed to be sticky to
+ // match the engine configuration. Avoid writing it otherwise so that it
+ // does not stick the user with the wrong build mode, particularly for
+ // existing app use cases.
+ xcodeBuildSettings.add('FLUTTER_BUILD_MODE=$engineBuildMode');
// Tell Xcode not to build universal binaries for local engines, which are
// single-architecture.
diff --git a/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart b/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart
index 233e9d0..0e990a8 100644
--- a/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart
+++ b/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart
@@ -433,22 +433,24 @@
});
group('updateGeneratedXcodeProperties', () {
- MockLocalEngineArtifacts mockArtifacts;
+ MockLocalEngineArtifacts mockEngineArtifacts;
+ MockArtifacts mockArtifacts;
MockProcessManager mockProcessManager;
FakePlatform macOS;
FileSystem fs;
setUp(() {
fs = MemoryFileSystem();
- mockArtifacts = MockLocalEngineArtifacts();
+ mockEngineArtifacts = MockLocalEngineArtifacts();
+ mockArtifacts = MockArtifacts();
mockProcessManager = MockProcessManager();
macOS = fakePlatform('macos');
fs.file(xcodebuild).createSync(recursive: true);
});
- void testUsingOsxContext(String description, dynamic testMethod()) {
+ void testUsingOsxContext(String description, dynamic testMethod(), {bool isLocalEngine = true}) {
testUsingContext(description, testMethod, overrides: <Type, Generator>{
- Artifacts: () => mockArtifacts,
+ Artifacts: () => isLocalEngine ? mockEngineArtifacts : mockArtifacts,
Platform: () => macOS,
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
@@ -507,9 +509,9 @@
});
testUsingOsxContext('sets ARCHS=armv7 when armv7 local engine is set', () async {
- when(mockArtifacts.getArtifactPath(Artifact.flutterFramework,
+ when(mockEngineArtifacts.getArtifactPath(Artifact.flutterFramework,
platform: TargetPlatform.ios, mode: anyNamed('mode'))).thenReturn('engine');
- when(mockArtifacts.engineOutPath).thenReturn(fs.path.join('out', 'ios_profile_arm'));
+ when(mockEngineArtifacts.engineOutPath).thenReturn(fs.path.join('out', 'ios_profile_arm'));
const BuildInfo buildInfo = BuildInfo(BuildMode.debug, null, treeShakeIcons: false);
final FlutterProject project = FlutterProject.fromPath('path/to/project');
@@ -531,10 +533,59 @@
expect(buildPhaseScriptContents.contains('ARCHS=armv7'), isTrue);
});
- testUsingOsxContext('sets TRACK_WIDGET_CREATION=true when trackWidgetCreation is true', () async {
+ testUsingOsxContext('sets FLUTTER_BUILD_MODE local engine is set', () async {
+ when(mockEngineArtifacts.getArtifactPath(Artifact.flutterFramework,
+ platform: TargetPlatform.ios, mode: anyNamed('mode'))).thenReturn('engine');
+ when(mockEngineArtifacts.engineOutPath).thenReturn(fs.path.join('out', 'ios_profile_arm'));
+
+ const BuildInfo buildInfo = BuildInfo(BuildMode.profile, null, treeShakeIcons: false);
+ final FlutterProject project = FlutterProject.fromPath('path/to/project');
+ await updateGeneratedXcodeProperties(
+ project: project,
+ buildInfo: buildInfo,
+ );
+
+ final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig');
+ expect(config.existsSync(), isTrue);
+
+ final String contents = config.readAsStringSync();
+ expect(contents, contains('FLUTTER_BUILD_MODE=profile'));
+
+ final File buildPhaseScript = fs.file('path/to/project/ios/Flutter/flutter_export_environment.sh');
+ expect(buildPhaseScript.existsSync(), isTrue);
+
+ final String buildPhaseScriptContents = buildPhaseScript.readAsStringSync();
+ expect(buildPhaseScriptContents, contains('FLUTTER_BUILD_MODE=profile'));
+ });
+
+ testUsingOsxContext('does not set FLUTTER_BUILD_MODE without local engine', () async {
when(mockArtifacts.getArtifactPath(Artifact.flutterFramework,
platform: TargetPlatform.ios, mode: anyNamed('mode'))).thenReturn('engine');
- when(mockArtifacts.engineOutPath).thenReturn(fs.path.join('out', 'ios_profile_arm'));
+
+ const BuildInfo buildInfo = BuildInfo(BuildMode.profile, null, treeShakeIcons: false);
+ final FlutterProject project = FlutterProject.fromPath('path/to/project');
+ await updateGeneratedXcodeProperties(
+ project: project,
+ buildInfo: buildInfo,
+ );
+
+ final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig');
+ expect(config.existsSync(), isTrue);
+
+ final String contents = config.readAsStringSync();
+ expect(contents, isNot(contains('FLUTTER_BUILD_MODE=')));
+
+ final File buildPhaseScript = fs.file('path/to/project/ios/Flutter/flutter_export_environment.sh');
+ expect(buildPhaseScript.existsSync(), isTrue);
+
+ final String buildPhaseScriptContents = buildPhaseScript.readAsStringSync();
+ expect(buildPhaseScriptContents, isNot(contains('FLUTTER_BUILD_MODE=')));
+ }, isLocalEngine: false);
+
+ testUsingOsxContext('sets TRACK_WIDGET_CREATION=true when trackWidgetCreation is true', () async {
+ when(mockEngineArtifacts.getArtifactPath(Artifact.flutterFramework,
+ platform: TargetPlatform.ios, mode: anyNamed('mode'))).thenReturn('engine');
+ when(mockEngineArtifacts.engineOutPath).thenReturn(fs.path.join('out', 'ios_profile_arm'));
const BuildInfo buildInfo = BuildInfo(BuildMode.debug, null, trackWidgetCreation: true, treeShakeIcons: false);
final FlutterProject project = FlutterProject.fromPath('path/to/project');
await updateGeneratedXcodeProperties(
@@ -556,9 +607,9 @@
});
testUsingOsxContext('does not set TRACK_WIDGET_CREATION when trackWidgetCreation is false', () async {
- when(mockArtifacts.getArtifactPath(Artifact.flutterFramework,
+ when(mockEngineArtifacts.getArtifactPath(Artifact.flutterFramework,
platform: TargetPlatform.ios, mode: anyNamed('mode'))).thenReturn('engine');
- when(mockArtifacts.engineOutPath).thenReturn(fs.path.join('out', 'ios_profile_arm'));
+ when(mockEngineArtifacts.engineOutPath).thenReturn(fs.path.join('out', 'ios_profile_arm'));
const BuildInfo buildInfo = BuildInfo(BuildMode.debug, null, treeShakeIcons: false);
final FlutterProject project = FlutterProject.fromPath('path/to/project');
await updateGeneratedXcodeProperties(
@@ -580,9 +631,9 @@
});
testUsingOsxContext('sets ARCHS=armv7 when armv7 local engine is set', () async {
- when(mockArtifacts.getArtifactPath(Artifact.flutterFramework,
+ when(mockEngineArtifacts.getArtifactPath(Artifact.flutterFramework,
platform: TargetPlatform.ios, mode: anyNamed('mode'))).thenReturn('engine');
- when(mockArtifacts.engineOutPath).thenReturn(fs.path.join('out', 'ios_profile'));
+ when(mockEngineArtifacts.engineOutPath).thenReturn(fs.path.join('out', 'ios_profile'));
const BuildInfo buildInfo = BuildInfo(BuildMode.debug, null, treeShakeIcons: false);
final FlutterProject project = FlutterProject.fromPath('path/to/project');
@@ -613,9 +664,9 @@
String expectedBuildName,
String expectedBuildNumber,
}) async {
- when(mockArtifacts.getArtifactPath(Artifact.flutterFramework,
+ when(mockEngineArtifacts.getArtifactPath(Artifact.flutterFramework,
platform: TargetPlatform.ios, mode: anyNamed('mode'))).thenReturn('engine');
- when(mockArtifacts.engineOutPath).thenReturn(fs.path.join('out', 'ios'));
+ when(mockEngineArtifacts.engineOutPath).thenReturn(fs.path.join('out', 'ios'));
final File manifestFile = fs.file('path/to/project/pubspec.yaml');
manifestFile.createSync(recursive: true);
@@ -809,3 +860,4 @@
@override
bool get supportsColor => false;
}
+class MockArtifacts extends Mock implements Artifacts {}