Remove build ios-framework --universal flag (#73383)
diff --git a/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart b/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart
index 82266bc..bdfa1b5 100644
--- a/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart
+++ b/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart
@@ -10,7 +10,7 @@
import 'package:flutter_devicelab/framework/utils.dart';
import 'package:path/path.dart' as path;
-/// Tests that iOS .frameworks can be built on module projects.
+/// Tests that iOS .xcframeworks can be built.
Future<void> main() async {
await task(() async {
@@ -76,10 +76,10 @@
);
});
- // First, build the module in Debug to copy the debug version of Flutter.framework.
- // This proves "flutter build ios-framework" re-copies the relevant Flutter.framework,
+ // First, build the module in Debug to copy the debug version of Flutter.xcframework.
+ // This proves "flutter build ios-framework" re-copies the relevant Flutter.xcframework,
// otherwise building plugins with bitcode will fail linking because the debug version
- // of Flutter.framework does not contain bitcode.
+ // of Flutter.xcframework does not contain bitcode.
await inDirectory(projectDir, () async {
await flutter(
'build',
@@ -101,7 +101,6 @@
'build',
options: <String>[
'ios-framework',
- '--universal',
'--verbose',
'--output=$outputDirectoryName'
],
@@ -110,40 +109,6 @@
final String outputPath = path.join(projectDir.path, outputDirectoryName);
- section('Check debug build has Dart snapshot as asset');
-
- checkFileExists(path.join(
- outputPath,
- 'Debug',
- 'App.framework',
- 'flutter_assets',
- 'vm_snapshot_data',
- ));
-
- section('Check debug build has no Dart AOT');
-
- // There's still an App.framework with a dylib, but it's empty.
- checkFileExists(path.join(
- outputPath,
- 'Debug',
- 'App.framework',
- 'App',
- ));
-
- final String debugAppFrameworkPath = path.join(
- outputPath,
- 'Debug',
- 'App.framework',
- 'App',
- );
- final String aotSymbols = await dylibSymbols(debugAppFrameworkPath);
-
- if (aotSymbols.contains('architecture') ||
- aotSymbols.contains('_kDartVmSnapshot')) {
- throw TaskResult.failure('Debug App.framework contains AOT');
- }
- await _checkFrameworkArchs(debugAppFrameworkPath, true);
-
// Xcode changed the name of this generated directory in Xcode 12.
const String xcode11ArmDirectoryName = 'ios-armv7_arm64';
const String xcode12ArmDirectoryName = 'ios-arm64_armv7';
@@ -202,26 +167,49 @@
throw const FileSystemException('Expected Flutter.framework binary to exist.');
}
+ final String debugAppFrameworkPath = path.join(
+ outputPath,
+ 'Debug',
+ 'App.xcframework',
+ localXcodeArmDirectoryName,
+ 'App.framework',
+ 'App',
+ );
+ checkFileExists(debugAppFrameworkPath);
+
+ section('Check debug build has Dart snapshot as asset');
+
checkFileExists(path.join(
outputPath,
'Debug',
'App.xcframework',
'ios-x86_64-simulator',
'App.framework',
- 'App',
+ 'flutter_assets',
+ 'vm_snapshot_data',
));
+ section('Check debug build has no Dart AOT');
+
+ final String aotSymbols = await dylibSymbols(debugAppFrameworkPath);
+
+ if (aotSymbols.contains('architecture') ||
+ aotSymbols.contains('_kDartVmSnapshot')) {
+ throw TaskResult.failure('Debug App.framework contains AOT');
+ }
+
section('Check profile, release builds has Dart AOT dylib');
for (final String mode in <String>['Profile', 'Release']) {
final String appFrameworkPath = path.join(
outputPath,
mode,
+ 'App.xcframework',
+ localXcodeArmDirectoryName,
'App.framework',
'App',
);
- await _checkFrameworkArchs(appFrameworkPath, false);
await _checkBitcode(appFrameworkPath, mode);
final String aotSymbols = await dylibSymbols(appFrameworkPath);
@@ -233,18 +221,11 @@
checkFileNotExists(path.join(
outputPath,
mode,
- 'App.framework',
- 'flutter_assets',
- 'vm_snapshot_data',
- ));
-
- checkFileExists(path.join(
- outputPath,
- mode,
'App.xcframework',
localXcodeArmDirectoryName,
'App.framework',
- 'App',
+ 'flutter_assets',
+ 'vm_snapshot_data',
));
checkFileNotExists(path.join(
@@ -263,21 +244,14 @@
final String engineFrameworkPath = path.join(
outputPath,
mode,
- 'Flutter.framework',
- 'Flutter',
- );
-
- await _checkFrameworkArchs(engineFrameworkPath, true);
- await _checkBitcode(engineFrameworkPath, mode);
-
- checkFileExists(path.join(
- outputPath,
- mode,
'Flutter.xcframework',
builderXcodeArmDirectoryName,
'Flutter.framework',
'Flutter',
- ));
+ );
+
+ await _checkBitcode(engineFrameworkPath, mode);
+
checkFileExists(path.join(
outputPath,
mode,
@@ -286,12 +260,16 @@
'Flutter.framework',
'Flutter',
));
- }
- section("Check all modes' engine header");
-
- for (final String mode in <String>['Debug', 'Profile', 'Release']) {
- checkFileExists(path.join(outputPath, mode, 'Flutter.framework', 'Headers', 'Flutter.h'));
+ checkFileExists(path.join(
+ outputPath,
+ mode,
+ 'Flutter.xcframework',
+ 'ios-x86_64-simulator',
+ 'Flutter.framework',
+ 'Headers',
+ 'Flutter.h',
+ ));
}
section('Check all modes have plugins');
@@ -300,20 +278,12 @@
final String pluginFrameworkPath = path.join(
outputPath,
mode,
- 'device_info.framework',
- 'device_info',
- );
- await _checkFrameworkArchs(pluginFrameworkPath, mode == 'Debug');
- await _checkBitcode(pluginFrameworkPath, mode);
-
- checkFileExists(path.join(
- outputPath,
- mode,
'device_info.xcframework',
localXcodeArmDirectoryName,
'device_info.framework',
'device_info',
- ));
+ );
+ await _checkBitcode(pluginFrameworkPath, mode);
checkFileExists(path.join(
outputPath,
@@ -362,23 +332,16 @@
final String registrantFrameworkPath = path.join(
outputPath,
mode,
+ 'FlutterPluginRegistrant.xcframework',
+ localXcodeArmDirectoryName,
'FlutterPluginRegistrant.framework',
- 'FlutterPluginRegistrant'
+ 'FlutterPluginRegistrant',
);
-
- await _checkFrameworkArchs(registrantFrameworkPath, mode == 'Debug');
await _checkBitcode(registrantFrameworkPath, mode);
checkFileExists(path.join(
outputPath,
mode,
- 'FlutterPluginRegistrant.framework',
- 'Headers',
- 'GeneratedPluginRegistrant.h',
- ));
- checkFileExists(path.join(
- outputPath,
- mode,
'FlutterPluginRegistrant.xcframework',
localXcodeArmDirectoryName,
'FlutterPluginRegistrant.framework',
@@ -412,7 +375,6 @@
options: <String>[
'ios-framework',
'--cocoapods',
- '--universal',
'--force', // Allow podspec creation on master.
'--output=$cocoapodsOutputDirectoryName'
],
@@ -430,29 +392,29 @@
checkDirectoryExists(path.join(
cocoapodsOutputPath,
mode,
- 'App.framework',
+ 'App.xcframework',
));
if (Directory(path.join(
cocoapodsOutputPath,
mode,
- 'FlutterPluginRegistrant.framework',
+ 'FlutterPluginRegistrant.xcframework',
)).existsSync() !=
isModule) {
throw TaskResult.failure(
- 'Unexpected FlutterPluginRegistrant.framework.');
+ 'Unexpected FlutterPluginRegistrant.xcframework.');
}
checkDirectoryExists(path.join(
cocoapodsOutputPath,
mode,
- 'device_info.framework',
+ 'device_info.xcframework',
));
checkDirectoryExists(path.join(
cocoapodsOutputPath,
mode,
- 'package_info.framework',
+ 'package_info.xcframework',
));
}
@@ -473,27 +435,6 @@
}
}
-Future<void> _checkFrameworkArchs(String frameworkPath, bool shouldContainSimulator) async {
- checkFileExists(frameworkPath);
-
- final String archs = await fileType(frameworkPath);
- if (!archs.contains('armv7')) {
- throw TaskResult.failure('$frameworkPath armv7 architecture missing');
- }
-
- if (!archs.contains('arm64')) {
- throw TaskResult.failure('$frameworkPath arm64 architecture missing');
- }
- final bool containsSimulator = archs.contains('x86_64');
-
- // Debug should contain the simulator archs.
- // Release and Profile should not.
- if (containsSimulator != shouldContainSimulator) {
- throw TaskResult.failure(
- '$frameworkPath x86_64 architecture ${shouldContainSimulator ? 'missing' : 'present'}');
- }
-}
-
Future<void> _checkBitcode(String frameworkPath, String mode) async {
checkFileExists(frameworkPath);
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 8e580a3..2d971b6 100644
--- a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart
+++ b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart
@@ -73,14 +73,15 @@
'By default, all build configurations are built.'
)
..addFlag('universal',
- help: '(Deprecated) Produce universal frameworks that include all valid architectures. '
- 'This option will be removed in a future version of Flutter.',
+ help: '(Deprecated) Produce universal frameworks that include all valid architectures.',
negatable: true,
hide: true,
)
..addFlag('xcframework',
help: 'Produce xcframeworks that include all valid architectures.',
+ negatable: false,
defaultsTo: true,
+ hide: true,
)
..addFlag('cocoapods',
help: 'Produce a Flutter.podspec instead of an engine Flutter.xcframework (recommended if host app uses CocoaPods).',
@@ -115,7 +116,7 @@
final String name = 'ios-framework';
@override
- final String description = 'Produces .frameworks for a Flutter project '
+ final String description = 'Produces .xcframeworks for a Flutter project '
'and its plugins for integration into existing, plain Xcode projects.\n'
'This can only be run on macOS hosts.';
@@ -150,16 +151,8 @@
throwToolExit('Building frameworks for iOS is only supported on the Mac.');
}
- if (!boolArg('universal') && !boolArg('xcframework')) {
- throwToolExit('--xcframework or --universal is required.');
- }
- if (boolArg('xcframework') && globals.xcode.majorVersion < 11) {
- throwToolExit('--xcframework requires Xcode 11.');
- }
if (boolArg('universal')) {
- globals.printError('--universal has been deprecated to support Apple '
- 'Silicon ARM simulators and will be removed in a future version of '
- 'Flutter. Use --xcframework instead.');
+ throwToolExit('--universal has been deprecated, only XCFrameworks are supported.');
}
if ((await buildInfos).isEmpty) {
throwToolExit('At least one of "--debug" or "--profile", or "--release" is required.');
@@ -196,7 +189,7 @@
_flutterVersion ??= globals.flutterVersion;
produceFlutterPodspec(buildInfo.mode, modeDirectory, force: boolArg('force'));
} else {
- // Copy Flutter.framework.
+ // Copy Flutter.xcframework.
await _produceFlutterFramework(buildInfo, modeDirectory);
}
@@ -311,7 +304,7 @@
Directory modeDirectory,
) async {
final Status status = globals.logger.startProgress(
- ' ├─Populating Flutter.xcframework...',
+ ' ├─Copying Flutter.xcframework...',
);
final String engineCacheFlutterFrameworkDirectory = globals.artifacts.getArtifactPath(
Artifact.flutterXcframework,
@@ -334,8 +327,6 @@
} finally {
status.stop();
}
-
- await _produceUniversalFromXCFramework(buildInfo, flutterFrameworkCopy);
}
Future<void> _produceAppFramework(
@@ -347,7 +338,7 @@
const String appFrameworkName = 'App.framework';
final Status status = globals.logger.startProgress(
- ' ├─Building App.framework...',
+ ' ├─Building App.xcframework...',
);
final List<EnvironmentType> environmentTypes = <EnvironmentType>[
EnvironmentType.physical,
@@ -407,14 +398,13 @@
in result.exceptions.values) {
globals.printError(measurement.exception.toString());
}
- throwToolExit('The App.framework build failed.');
+ throwToolExit('The App.xcframework build failed.');
}
}
} finally {
status.stop();
}
- await _produceUniversalFramework(frameworks, 'App', outputDirectory);
await _produceXCFramework(frameworks, 'App', outputDirectory);
}
@@ -520,7 +510,6 @@
.childDirectory(podFrameworkName)
];
- await _produceUniversalFramework(frameworks, binaryName, modeDirectory);
await _produceXCFramework(frameworks, binaryName, modeDirectory);
}
}
@@ -529,37 +518,6 @@
}
}
- Future<void> _produceUniversalFromXCFramework(BuildInfo buildInfo, Directory xcframework) async {
- if (boolArg('universal')) {
- final String frameworkBinaryName =
- globals.fs.path.basenameWithoutExtension(xcframework.basename);
-
- final Status status = globals.logger.startProgress(
- ' ├─Creating $frameworkBinaryName.framework...',
- );
- try {
- final Iterable<Directory> frameworks = xcframework
- .listSync()
- .whereType<Directory>()
- .map((Directory triple) => triple
- .listSync()
- .whereType<Directory>()
- .firstWhere((Directory frameworkDirectory) =>
- frameworkDirectory.basename ==
- '$frameworkBinaryName.framework'));
-
- await _produceUniversalFramework(
- frameworks, frameworkBinaryName, xcframework.parent);
- } finally {
- status.stop();
- }
- }
-
- if (!boolArg('xcframework')) {
- xcframework.deleteSync(recursive: true);
- }
- }
-
Future<void> _produceXCFramework(Iterable<Directory> frameworks,
String frameworkBinaryName, Directory outputDirectory) async {
if (!boolArg('xcframework')) {
@@ -587,42 +545,4 @@
'Unable to create $frameworkBinaryName.xcframework: ${xcframeworkResult.stderr}');
}
}
-
- Future<void> _produceUniversalFramework(Iterable<Directory> frameworks,
- String frameworkBinaryName, Directory outputDirectory) async {
- if (!boolArg('universal')) {
- return;
- }
- final Directory outputFrameworkDirectory =
- outputDirectory.childDirectory('$frameworkBinaryName.framework');
-
- // Copy the first framework over completely to get headers, resources, etc.
- globals.fsUtils.copyDirectorySync(
- frameworks.first,
- outputFrameworkDirectory,
- );
-
- // Recreate the framework binary by lipo'ing the framework binaries together.
- final List<String> lipoCommand = <String>[
- ...globals.xcode.xcrunCommand(),
- 'lipo',
- '-create',
- for (Directory framework in frameworks) ...<String>[
- framework.childFile(frameworkBinaryName).path
- ],
- '-output',
- outputFrameworkDirectory.childFile(frameworkBinaryName).path
- ];
-
- final RunResult lipoResult = await globals.processUtils.run(
- lipoCommand,
- workingDirectory: outputDirectory.path,
- allowReentrantFlutter: false,
- );
-
- if (lipoResult.exitCode != 0) {
- throwToolExit(
- 'Unable to create $frameworkBinaryName.framework: ${lipoResult.stderr}');
- }
- }
}