Unverified Commit d4150d3f authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Adopt Flutter.xcframework in tool (#71495)

parent f67b94bd
...@@ -102,6 +102,7 @@ Future<void> _testBuildIosFramework(Directory projectDir, { bool isModule = fals ...@@ -102,6 +102,7 @@ Future<void> _testBuildIosFramework(Directory projectDir, { bool isModule = fals
options: <String>[ options: <String>[
'ios-framework', 'ios-framework',
'--universal', '--universal',
'--verbose',
'--output=$outputDirectoryName' '--output=$outputDirectoryName'
], ],
); );
...@@ -164,16 +165,43 @@ Future<void> _testBuildIosFramework(Directory projectDir, { bool isModule = fals ...@@ -164,16 +165,43 @@ Future<void> _testBuildIosFramework(Directory projectDir, { bool isModule = fals
'App', 'App',
); );
// This seemed easier than an explicit Xcode version check. // Based on the locally installed version of Xcode.
String xcodeArmDirectoryName; String localXcodeArmDirectoryName;
if (exists(File(xcode11AppFrameworkDirectory))) { if (exists(File(xcode11AppFrameworkDirectory))) {
xcodeArmDirectoryName = xcode11ArmDirectoryName; localXcodeArmDirectoryName = xcode11ArmDirectoryName;
} else if (exists(File(xcode12AppFrameworkDirectory))) { } else if (exists(File(xcode12AppFrameworkDirectory))) {
xcodeArmDirectoryName = xcode12ArmDirectoryName; localXcodeArmDirectoryName = xcode12ArmDirectoryName;
} else { } else {
throw const FileSystemException('Expected App.framework binary to exist.'); throw const FileSystemException('Expected App.framework binary to exist.');
} }
final String xcode11FlutterFrameworkDirectory = path.join(
outputPath,
'Debug',
'Flutter.xcframework',
xcode11ArmDirectoryName,
'Flutter.framework',
'Flutter',
);
final String xcode12FlutterFrameworkDirectory = path.join(
outputPath,
'Debug',
'Flutter.xcframework',
xcode12ArmDirectoryName,
'Flutter.framework',
'Flutter',
);
// Based on the version of Xcode installed on the engine builder.
String builderXcodeArmDirectoryName;
if (exists(File(xcode11FlutterFrameworkDirectory))) {
builderXcodeArmDirectoryName = xcode11ArmDirectoryName;
} else if (exists(File(xcode12FlutterFrameworkDirectory))) {
builderXcodeArmDirectoryName = xcode12ArmDirectoryName;
} else {
throw const FileSystemException('Expected Flutter.framework binary to exist.');
}
checkFileExists(path.join( checkFileExists(path.join(
outputPath, outputPath,
'Debug', 'Debug',
...@@ -214,7 +242,7 @@ Future<void> _testBuildIosFramework(Directory projectDir, { bool isModule = fals ...@@ -214,7 +242,7 @@ Future<void> _testBuildIosFramework(Directory projectDir, { bool isModule = fals
outputPath, outputPath,
mode, mode,
'App.xcframework', 'App.xcframework',
xcodeArmDirectoryName, localXcodeArmDirectoryName,
'App.framework', 'App.framework',
'App', 'App',
)); ));
...@@ -239,30 +267,25 @@ Future<void> _testBuildIosFramework(Directory projectDir, { bool isModule = fals ...@@ -239,30 +267,25 @@ Future<void> _testBuildIosFramework(Directory projectDir, { bool isModule = fals
'Flutter', 'Flutter',
); );
await _checkFrameworkArchs(engineFrameworkPath, mode == 'Debug'); await _checkFrameworkArchs(engineFrameworkPath, true);
await _checkBitcode(engineFrameworkPath, mode); await _checkBitcode(engineFrameworkPath, mode);
checkFileExists(path.join( checkFileExists(path.join(
outputPath, outputPath,
mode, mode,
'Flutter.xcframework', 'Flutter.xcframework',
xcodeArmDirectoryName, builderXcodeArmDirectoryName,
'Flutter.framework', 'Flutter.framework',
'Flutter', 'Flutter',
)); ));
final String simulatorFrameworkPath = path.join( checkFileExists(path.join(
outputPath, outputPath,
mode, mode,
'Flutter.xcframework', 'Flutter.xcframework',
'ios-x86_64-simulator', 'ios-x86_64-simulator',
'Flutter.framework', 'Flutter.framework',
'Flutter', 'Flutter',
); ));
if (mode == 'Debug') {
checkFileExists(simulatorFrameworkPath);
} else {
checkFileNotExists(simulatorFrameworkPath);
}
} }
section("Check all modes' engine header"); section("Check all modes' engine header");
...@@ -287,7 +310,7 @@ Future<void> _testBuildIosFramework(Directory projectDir, { bool isModule = fals ...@@ -287,7 +310,7 @@ Future<void> _testBuildIosFramework(Directory projectDir, { bool isModule = fals
outputPath, outputPath,
mode, mode,
'device_info.xcframework', 'device_info.xcframework',
xcodeArmDirectoryName, localXcodeArmDirectoryName,
'device_info.framework', 'device_info.framework',
'device_info', 'device_info',
)); ));
...@@ -296,7 +319,7 @@ Future<void> _testBuildIosFramework(Directory projectDir, { bool isModule = fals ...@@ -296,7 +319,7 @@ Future<void> _testBuildIosFramework(Directory projectDir, { bool isModule = fals
outputPath, outputPath,
mode, mode,
'device_info.xcframework', 'device_info.xcframework',
xcodeArmDirectoryName, localXcodeArmDirectoryName,
'device_info.framework', 'device_info.framework',
'Headers', 'Headers',
'DeviceInfoPlugin.h', 'DeviceInfoPlugin.h',
...@@ -357,7 +380,7 @@ Future<void> _testBuildIosFramework(Directory projectDir, { bool isModule = fals ...@@ -357,7 +380,7 @@ Future<void> _testBuildIosFramework(Directory projectDir, { bool isModule = fals
outputPath, outputPath,
mode, mode,
'FlutterPluginRegistrant.xcframework', 'FlutterPluginRegistrant.xcframework',
xcodeArmDirectoryName, localXcodeArmDirectoryName,
'FlutterPluginRegistrant.framework', 'FlutterPluginRegistrant.framework',
'Headers', 'Headers',
'GeneratedPluginRegistrant.h', 'GeneratedPluginRegistrant.h',
......
...@@ -22,6 +22,8 @@ Future<bool> containsBitcode(String pathToBinary) async { ...@@ -22,6 +22,8 @@ Future<bool> containsBitcode(String pathToBinary) async {
// See: https://stackoverflow.com/questions/32755775/how-to-check-a-static-library-is-built-contain-bitcode // See: https://stackoverflow.com/questions/32755775/how-to-check-a-static-library-is-built-contain-bitcode
final String loadCommands = await eval('otool', <String>[ final String loadCommands = await eval('otool', <String>[
'-l', '-l',
'-arch',
'arm64',
pathToBinary, pathToBinary,
]); ]);
if (!loadCommands.contains('__LLVM')) { if (!loadCommands.contains('__LLVM')) {
......
...@@ -35,13 +35,27 @@ def flutter_additional_ios_build_settings(target) ...@@ -35,13 +35,27 @@ def flutter_additional_ios_build_settings(target)
# This podhelper script is at $FLUTTER_ROOT/packages/flutter_tools/bin. # This podhelper script is at $FLUTTER_ROOT/packages/flutter_tools/bin.
# Add search paths from $FLUTTER_ROOT/bin/cache/artifacts/engine. # Add search paths from $FLUTTER_ROOT/bin/cache/artifacts/engine.
artifacts_dir = File.join('..', '..', '..', '..', 'bin', 'cache', 'artifacts', 'engine') artifacts_dir = File.join('..', '..', '..', '..', 'bin', 'cache', 'artifacts', 'engine')
debug_framework_dir = File.expand_path(File.join(artifacts_dir, 'ios'), __FILE__) debug_framework_dir = File.expand_path(File.join(artifacts_dir, 'ios', 'Flutter.xcframework'), __FILE__)
release_framework_dir = File.expand_path(File.join(artifacts_dir, 'ios-release'), __FILE__)
unless Dir.exist?(debug_framework_dir)
# iOS artifacts have not been downloaded.
raise "#{debug_framework_dir} must exist. If you're running pod install manually, make sure flutter build ios is executed first"
end
release_framework_dir = File.expand_path(File.join(artifacts_dir, 'ios-release', 'Flutter.xcframework'), __FILE__)
target.build_configurations.each do |build_configuration| target.build_configurations.each do |build_configuration|
# Profile can't be derived from the CocoaPods build configuration. Use release framework (for linking only). # Profile can't be derived from the CocoaPods build configuration. Use release framework (for linking only).
configuration_engine_dir = build_configuration.type == :debug ? debug_framework_dir : release_framework_dir configuration_engine_dir = build_configuration.type == :debug ? debug_framework_dir : release_framework_dir
build_configuration.build_settings['FRAMEWORK_SEARCH_PATHS'] = "\"#{configuration_engine_dir}\" $(inherited)" Dir.new(configuration_engine_dir).each_child do |xcframework_file|
if xcframework_file.end_with?("-simulator") # ios-x86_64-simulator
build_configuration.build_settings['FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]'] = "\"#{configuration_engine_dir}/#{xcframework_file}\" $(inherited)"
elsif xcframework_file.start_with?("ios-") # ios-armv7_arm64
build_configuration.build_settings['FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]'] = "\"#{configuration_engine_dir}/#{xcframework_file}\" $(inherited)"
else
# Info.plist or another platform.
end
end
build_configuration.build_settings['OTHER_LDFLAGS'] = '$(inherited) -framework Flutter' build_configuration.build_settings['OTHER_LDFLAGS'] = '$(inherited) -framework Flutter'
build_configuration.build_settings['CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER'] = 'NO' build_configuration.build_settings['CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER'] = 'NO'
......
...@@ -115,7 +115,7 @@ is set to release or run \"flutter build ios --release\", then re-run Archive fr ...@@ -115,7 +115,7 @@ is set to release or run \"flutter build ios --release\", then re-run Archive fr
local framework_path="${FLUTTER_ROOT}/bin/cache/artifacts/engine/${artifact_variant}" local framework_path="${FLUTTER_ROOT}/bin/cache/artifacts/engine/${artifact_variant}"
local flutter_engine_flag="" local flutter_engine_flag=""
local local_engine_flag="" local local_engine_flag=""
local flutter_framework="${framework_path}/Flutter.framework" local flutter_framework="${framework_path}/Flutter.xcframework"
if [[ -n "$FLUTTER_ENGINE" ]]; then if [[ -n "$FLUTTER_ENGINE" ]]; then
flutter_engine_flag="--local-engine-src-path=${FLUTTER_ENGINE}" flutter_engine_flag="--local-engine-src-path=${FLUTTER_ENGINE}"
...@@ -135,7 +135,7 @@ is set to release or run \"flutter build ios --release\", then re-run Archive fr ...@@ -135,7 +135,7 @@ is set to release or run \"flutter build ios --release\", then re-run Archive fr
exit -1 exit -1
fi fi
local_engine_flag="--local-engine=${LOCAL_ENGINE}" local_engine_flag="--local-engine=${LOCAL_ENGINE}"
flutter_framework="${FLUTTER_ENGINE}/out/${LOCAL_ENGINE}/Flutter.framework" flutter_framework="${FLUTTER_ENGINE}/out/${LOCAL_ENGINE}/Flutter.xcframework"
fi fi
local bitcode_flag="" local bitcode_flag=""
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
import 'base/common.dart';
import 'base/file_system.dart'; import 'base/file_system.dart';
import 'base/platform.dart'; import 'base/platform.dart';
import 'base/utils.dart'; import 'base/utils.dart';
...@@ -305,12 +306,14 @@ class CachedArtifacts implements Artifacts { ...@@ -305,12 +306,14 @@ class CachedArtifacts implements Artifacts {
BuildMode mode, EnvironmentType environmentType) { BuildMode mode, EnvironmentType environmentType) {
switch (artifact) { switch (artifact) {
case Artifact.genSnapshot: case Artifact.genSnapshot:
case Artifact.flutterFramework:
case Artifact.flutterXcframework: case Artifact.flutterXcframework:
case Artifact.frontendServerSnapshotForEngineDartSdk: case Artifact.frontendServerSnapshotForEngineDartSdk:
final String artifactFileName = _artifactToFileName(artifact); final String artifactFileName = _artifactToFileName(artifact);
final String engineDir = _getEngineArtifactsPath(platform, mode); final String engineDir = _getEngineArtifactsPath(platform, mode);
return _fileSystem.path.join(engineDir, artifactFileName); return _fileSystem.path.join(engineDir, artifactFileName);
case Artifact.flutterFramework:
final String engineDir = _getEngineArtifactsPath(platform, mode);
return _getIosEngineArtifactPath(engineDir, environmentType, _fileSystem);
case Artifact.idevicescreenshot: case Artifact.idevicescreenshot:
case Artifact.idevicesyslog: case Artifact.idevicesyslog:
final String artifactFileName = _artifactToFileName(artifact); final String artifactFileName = _artifactToFileName(artifact);
...@@ -527,6 +530,38 @@ HostPlatform _currentHostPlatformAsHost(Platform platform) { ...@@ -527,6 +530,38 @@ HostPlatform _currentHostPlatformAsHost(Platform platform) {
throw UnimplementedError('Host OS not supported.'); throw UnimplementedError('Host OS not supported.');
} }
String _getIosEngineArtifactPath(String engineDirectory,
EnvironmentType environmentType, FileSystem fileSystem) {
final Directory xcframeworkDirectory = fileSystem
.directory(engineDirectory)
.childDirectory(_artifactToFileName(Artifact.flutterXcframework));
if (!xcframeworkDirectory.existsSync()) {
throwToolExit('No xcframework found at ${xcframeworkDirectory.path}. Try running "flutter build ios".');
}
Directory flutterFrameworkSource;
for (final Directory platformDirectory
in xcframeworkDirectory.listSync().whereType<Directory>()) {
if (!platformDirectory.basename.startsWith('ios-')) {
continue;
}
// ios-x86_64-simulator, ios-armv7_arm64 (Xcode 11), or ios-arm64_armv7 (Xcode 12).
final bool simulatorDirectory =
platformDirectory.basename.endsWith('-simulator');
if ((environmentType == EnvironmentType.simulator && simulatorDirectory) ||
(environmentType == EnvironmentType.physical && !simulatorDirectory)) {
flutterFrameworkSource = platformDirectory;
}
}
if (flutterFrameworkSource == null) {
throwToolExit('No iOS frameworks found in ${xcframeworkDirectory.path}');
}
return flutterFrameworkSource
.childDirectory(_artifactToFileName(Artifact.flutterFramework))
.path;
}
/// Manages the artifacts of a locally built engine. /// Manages the artifacts of a locally built engine.
class LocalEngineArtifacts implements Artifacts { class LocalEngineArtifacts implements Artifacts {
LocalEngineArtifacts( LocalEngineArtifacts(
...@@ -578,7 +613,8 @@ class LocalEngineArtifacts implements Artifacts { ...@@ -578,7 +613,8 @@ class LocalEngineArtifacts implements Artifacts {
case Artifact.platformLibrariesJson: case Artifact.platformLibrariesJson:
return _fileSystem.path.join(_getFlutterPatchedSdkPath(mode), 'lib', artifactFileName); return _fileSystem.path.join(_getFlutterPatchedSdkPath(mode), 'lib', artifactFileName);
case Artifact.flutterFramework: case Artifact.flutterFramework:
return _fileSystem.path.join(engineOutPath, artifactFileName); return _getIosEngineArtifactPath(
engineOutPath, environmentType, _fileSystem);
case Artifact.flutterPatchedSdkPath: case Artifact.flutterPatchedSdkPath:
// When using local engine always use [BuildMode.debug] regardless of // When using local engine always use [BuildMode.debug] regardless of
// what was specified in [mode] argument because local engine will // what was specified in [mode] argument because local engine will
......
...@@ -249,7 +249,7 @@ abstract class UnpackIOS extends Target { ...@@ -249,7 +249,7 @@ abstract class UnpackIOS extends Target {
const Source.pattern( const Source.pattern(
'{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/ios.dart'), '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/ios.dart'),
Source.artifact( Source.artifact(
Artifact.flutterFramework, Artifact.flutterXcframework,
platform: TargetPlatform.ios, platform: TargetPlatform.ios,
mode: buildMode, mode: buildMode,
), ),
......
...@@ -924,14 +924,11 @@ abstract class EngineCachedArtifact extends CachedArtifact { ...@@ -924,14 +924,11 @@ abstract class EngineCachedArtifact extends CachedArtifact {
_makeFilesExecutable(dir, operatingSystemUtils); _makeFilesExecutable(dir, operatingSystemUtils);
const List<String> frameworkNames = <String>['Flutter', 'FlutterMacOS']; final File frameworkZip = fileSystem.file(fileSystem.path.join(dir.path, 'FlutterMacOS.framework.zip'));
for (final String frameworkName in frameworkNames) { if (frameworkZip.existsSync()) {
final File frameworkZip = fileSystem.file(fileSystem.path.join(dir.path, '$frameworkName.framework.zip')); final Directory framework = fileSystem.directory(fileSystem.path.join(dir.path, 'FlutterMacOS.framework'));
if (frameworkZip.existsSync()) { framework.createSync();
final Directory framework = fileSystem.directory(fileSystem.path.join(dir.path, '$frameworkName.framework')); operatingSystemUtils.unzip(frameworkZip, framework);
framework.createSync();
operatingSystemUtils.unzip(frameworkZip, framework);
}
} }
} }
......
...@@ -295,10 +295,7 @@ LICENSE ...@@ -295,10 +295,7 @@ LICENSE
s.source = { :http => '${_cache.storageBaseUrl}/flutter_infra/flutter/${_cache.engineRevision}/$artifactsMode/artifacts.zip' } s.source = { :http => '${_cache.storageBaseUrl}/flutter_infra/flutter/${_cache.engineRevision}/$artifactsMode/artifacts.zip' }
s.documentation_url = 'https://flutter.dev/docs' s.documentation_url = 'https://flutter.dev/docs'
s.platform = :ios, '8.0' s.platform = :ios, '8.0'
s.vendored_frameworks = 'Flutter.framework' s.vendored_frameworks = 'Flutter.xcframework'
s.prepare_command = <<-CMD
unzip Flutter.framework -d Flutter.framework
CMD
end end
'''; ''';
...@@ -314,56 +311,31 @@ end ...@@ -314,56 +311,31 @@ end
Directory modeDirectory, Directory modeDirectory,
) async { ) async {
final Status status = globals.logger.startProgress( final Status status = globals.logger.startProgress(
' ├─Populating Flutter.framework...', ' ├─Populating Flutter.xcframework...',
); );
final String engineCacheFlutterFrameworkDirectory = globals.artifacts.getArtifactPath( final String engineCacheFlutterFrameworkDirectory = globals.artifacts.getArtifactPath(
Artifact.flutterFramework, Artifact.flutterXcframework,
platform: TargetPlatform.ios, platform: TargetPlatform.ios,
mode: buildInfo.mode, mode: buildInfo.mode,
); );
final String flutterFrameworkFileName = globals.fs.path.basename( final String flutterFrameworkFileName = globals.fs.path.basename(
engineCacheFlutterFrameworkDirectory, engineCacheFlutterFrameworkDirectory,
); );
final Directory fatFlutterFrameworkCopy = modeDirectory.childDirectory( final Directory flutterFrameworkCopy = modeDirectory.childDirectory(
flutterFrameworkFileName, flutterFrameworkFileName,
); );
try { try {
// Copy universal engine cache framework to mode directory. // Copy xcframework engine cache framework to mode directory.
globals.fsUtils.copyDirectorySync( globals.fsUtils.copyDirectorySync(
globals.fs.directory(engineCacheFlutterFrameworkDirectory), globals.fs.directory(engineCacheFlutterFrameworkDirectory),
fatFlutterFrameworkCopy, flutterFrameworkCopy,
); );
if (buildInfo.mode != BuildMode.debug) {
final File fatFlutterFrameworkBinary = fatFlutterFrameworkCopy.childFile('Flutter');
// Remove simulator architecture in profile and release mode.
final List<String> lipoCommand = <String>[
...globals.xcode.xcrunCommand(),
'lipo',
fatFlutterFrameworkBinary.path,
'-remove',
'x86_64',
'-output',
fatFlutterFrameworkBinary.path
];
final RunResult lipoResult = await globals.processUtils.run(
lipoCommand,
allowReentrantFlutter: false,
);
if (lipoResult.exitCode != 0) {
throwToolExit(
'Unable to remove simulator architecture in ${buildInfo.mode}: ${lipoResult.stderr}',
);
}
}
} finally { } finally {
status.stop(); status.stop();
} }
await _produceXCFrameworkFromUniversal(buildInfo, fatFlutterFrameworkCopy); await _produceUniversalFromXCFramework(buildInfo, flutterFrameworkCopy);
} }
Future<void> _produceAppFramework( Future<void> _produceAppFramework(
...@@ -558,112 +530,34 @@ end ...@@ -558,112 +530,34 @@ end
} }
} }
Future<void> _produceXCFrameworkFromUniversal(BuildInfo buildInfo, Directory fatFramework) async { Future<void> _produceUniversalFromXCFramework(BuildInfo buildInfo, Directory xcframework) async {
if (boolArg('xcframework')) { if (boolArg('universal')) {
final String frameworkBinaryName = globals.fs.path.basenameWithoutExtension( final String frameworkBinaryName =
fatFramework.basename); globals.fs.path.basenameWithoutExtension(xcframework.basename);
final Status status = globals.logger.startProgress( final Status status = globals.logger.startProgress(
' ├─Creating $frameworkBinaryName.xcframework...', ' ├─Creating $frameworkBinaryName.framework...',
); );
try { try {
if (buildInfo.mode == BuildMode.debug) { final Iterable<Directory> frameworks = xcframework
await _produceDebugXCFramework(fatFramework, frameworkBinaryName); .listSync()
} else { .whereType<Directory>()
await _produceXCFramework( .map((Directory triple) => triple
<Directory>[fatFramework], frameworkBinaryName, .listSync()
fatFramework.parent); .whereType<Directory>()
} .firstWhere((Directory frameworkDirectory) =>
frameworkDirectory.basename ==
'$frameworkBinaryName.framework'));
await _produceUniversalFramework(
frameworks, frameworkBinaryName, xcframework.parent);
} finally { } finally {
status.stop(); status.stop();
} }
} }
if (!boolArg('universal')) { if (!boolArg('xcframework')) {
fatFramework.deleteSync(recursive: true); xcframework.deleteSync(recursive: true);
}
}
Future<void> _produceDebugXCFramework(Directory fatFramework, String frameworkBinaryName) async {
final String frameworkFileName = fatFramework.basename;
final File fatFlutterFrameworkBinary = fatFramework.childFile(
frameworkBinaryName,
);
final Directory temporaryOutput = globals.fs.systemTempDirectory.createTempSync(
'flutter_tool_build_ios_framework.',
);
try {
// Copy universal framework to variant directory.
final Directory iPhoneBuildOutput = temporaryOutput.childDirectory(
'ios',
)..createSync(recursive: true);
final Directory simulatorBuildOutput = temporaryOutput.childDirectory(
'simulator',
)..createSync(recursive: true);
final Directory armFlutterFrameworkDirectory = iPhoneBuildOutput
.childDirectory(frameworkFileName);
final File armFlutterFrameworkBinary = armFlutterFrameworkDirectory
.childFile(frameworkBinaryName);
globals.fsUtils.copyDirectorySync(fatFramework, armFlutterFrameworkDirectory);
// Create iOS framework.
List<String> lipoCommand = <String>[
...globals.xcode.xcrunCommand(),
'lipo',
fatFlutterFrameworkBinary.path,
'-remove',
'x86_64',
'-output',
armFlutterFrameworkBinary.path
];
RunResult lipoResult = await globals.processUtils.run(
lipoCommand,
allowReentrantFlutter: false,
);
if (lipoResult.exitCode != 0) {
throwToolExit('Unable to create ARM framework: ${lipoResult.stderr}');
}
// Create simulator framework.
final Directory simulatorFlutterFrameworkDirectory = simulatorBuildOutput
.childDirectory(frameworkFileName);
final File simulatorFlutterFrameworkBinary = simulatorFlutterFrameworkDirectory
.childFile(frameworkBinaryName);
globals.fsUtils.copyDirectorySync(fatFramework, simulatorFlutterFrameworkDirectory);
lipoCommand = <String>[
...globals.xcode.xcrunCommand(),
'lipo',
fatFlutterFrameworkBinary.path,
'-thin',
'x86_64',
'-output',
simulatorFlutterFrameworkBinary.path
];
lipoResult = await globals.processUtils.run(
lipoCommand,
allowReentrantFlutter: false,
);
if (lipoResult.exitCode != 0) {
throwToolExit(
'Unable to create simulator framework: ${lipoResult.stderr}');
}
// Create XCFramework from iOS and simulator frameworks.
await _produceXCFramework(
<Directory>[
armFlutterFrameworkDirectory,
simulatorFlutterFrameworkDirectory
],
frameworkBinaryName,
fatFramework.parent,
);
} finally {
temporaryOutput.deleteSync(recursive: true);
} }
} }
......
...@@ -13,16 +13,14 @@ import '../macos/xcode.dart'; ...@@ -13,16 +13,14 @@ import '../macos/xcode.dart';
const bool kBitcodeEnabledDefault = false; const bool kBitcodeEnabledDefault = false;
Future<void> validateBitcode(BuildMode buildMode, TargetPlatform targetPlatform) async { Future<void> validateBitcode(BuildMode buildMode, TargetPlatform targetPlatform, EnvironmentType environmentType) async {
final Artifacts localArtifacts = globals.artifacts; final Artifacts localArtifacts = globals.artifacts;
final String flutterFrameworkPath = localArtifacts.getArtifactPath( final String flutterFrameworkPath = localArtifacts.getArtifactPath(
Artifact.flutterFramework, Artifact.flutterFramework,
mode: buildMode, mode: buildMode,
platform: targetPlatform, platform: targetPlatform,
environmentType: environmentType,
); );
if (!globals.fs.isDirectorySync(flutterFrameworkPath)) {
throwToolExit('Flutter.framework not found at $flutterFrameworkPath');
}
final Xcode xcode = context.get<Xcode>(); final Xcode xcode = context.get<Xcode>();
final RunResult clangResult = await xcode.clang(<String>['--version']); final RunResult clangResult = await xcode.clang(<String>['--version']);
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import '../base/fingerprint.dart'; import '../base/fingerprint.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../cache.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import '../plugins.dart'; import '../plugins.dart';
import '../project.dart'; import '../project.dart';
...@@ -28,6 +29,13 @@ Future<void> processPodsIfNeeded( ...@@ -28,6 +29,13 @@ Future<void> processPodsIfNeeded(
xcodeProject.xcodeProjectInfoFile.path, xcodeProject.xcodeProjectInfoFile.path,
xcodeProject.podfile.path, xcodeProject.podfile.path,
xcodeProject.generatedXcodePropertiesFile.path, xcodeProject.generatedXcodePropertiesFile.path,
globals.fs.path.join(
Cache.flutterRoot,
'packages',
'flutter_tools',
'bin',
'podhelper.rb',
),
], ],
fileSystem: globals.fs, fileSystem: globals.fs,
logger: globals.logger, logger: globals.logger,
......
...@@ -659,7 +659,7 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject { ...@@ -659,7 +659,7 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject {
// to be in this location. // to be in this location.
final Directory framework = globals.fs.directory( final Directory framework = globals.fs.directory(
globals.artifacts.getArtifactPath( globals.artifacts.getArtifactPath(
Artifact.flutterFramework, Artifact.flutterXcframework,
platform: TargetPlatform.ios, platform: TargetPlatform.ios,
mode: mode, mode: mode,
environmentType: environmentType, environmentType: environmentType,
...@@ -668,7 +668,7 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject { ...@@ -668,7 +668,7 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject {
if (framework.existsSync()) { if (framework.existsSync()) {
globals.fsUtils.copyDirectorySync( globals.fsUtils.copyDirectorySync(
framework, framework,
engineCopyDirectory.childDirectory('Flutter.framework'), engineCopyDirectory.childDirectory('Flutter.xcframework'),
); );
} }
} }
......
...@@ -14,5 +14,5 @@ Flutter provides an easy and productive way to build and deploy high-performance ...@@ -14,5 +14,5 @@ Flutter provides an easy and productive way to build and deploy high-performance
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
s.ios.deployment_target = '8.0' s.ios.deployment_target = '8.0'
s.vendored_frameworks = 'Flutter.framework' s.vendored_frameworks = 'Flutter.xcframework'
end end
...@@ -30,7 +30,7 @@ end ...@@ -30,7 +30,7 @@ end
def install_flutter_engine_pod def install_flutter_engine_pod
current_directory = File.expand_path('..', __FILE__) current_directory = File.expand_path('..', __FILE__)
engine_dir = File.expand_path('engine', current_directory) engine_dir = File.expand_path('engine', current_directory)
framework_name = 'Flutter.framework' framework_name = 'Flutter.xcframework'
copied_engine = File.expand_path(framework_name, engine_dir) copied_engine = File.expand_path(framework_name, engine_dir)
if !File.exist?(copied_engine) if !File.exist?(copied_engine)
# Copy the debug engine to have something to link against if the xcode backend script has not run yet. # Copy the debug engine to have something to link against if the xcode backend script has not run yet.
......
...@@ -42,9 +42,67 @@ void main() { ...@@ -42,9 +42,67 @@ void main() {
}); });
testWithoutContext('getArtifactPath', () { testWithoutContext('getArtifactPath', () {
final String xcframeworkPath = artifacts.getArtifactPath(
Artifact.flutterXcframework,
platform: TargetPlatform.ios,
mode: BuildMode.release,
);
expect(
xcframeworkPath,
fileSystem.path.join(
'root',
'bin',
'cache',
'artifacts',
'engine',
'ios-release',
'Flutter.xcframework',
),
);
expect( expect(
artifacts.getArtifactPath(Artifact.flutterFramework, platform: TargetPlatform.ios, mode: BuildMode.release), () => artifacts.getArtifactPath(
fileSystem.path.join('root', 'bin', 'cache', 'artifacts', 'engine', 'ios-release', 'Flutter.framework'), Artifact.flutterFramework,
platform: TargetPlatform.ios,
mode: BuildMode.release,
environmentType: EnvironmentType.simulator,
),
throwsToolExit(
message:
'No xcframework found at $xcframeworkPath. Try running "flutter build ios".'),
);
fileSystem.directory(xcframeworkPath).createSync(recursive: true);
expect(
() => artifacts.getArtifactPath(
Artifact.flutterFramework,
platform: TargetPlatform.ios,
mode: BuildMode.release,
environmentType: EnvironmentType.simulator,
),
throwsToolExit(message: 'No iOS frameworks found in $xcframeworkPath'),
);
fileSystem
.directory(xcframeworkPath)
.childDirectory('ios-x86_64-simulator')
.childDirectory('Flutter.framework')
.createSync(recursive: true);
fileSystem
.directory(xcframeworkPath)
.childDirectory('ios-armv7_arm64')
.childDirectory('Flutter.framework')
.createSync(recursive: true);
expect(
artifacts.getArtifactPath(Artifact.flutterFramework,
platform: TargetPlatform.ios,
mode: BuildMode.release,
environmentType: EnvironmentType.simulator),
fileSystem.path
.join(xcframeworkPath, 'ios-x86_64-simulator', 'Flutter.framework'),
);
expect(
artifacts.getArtifactPath(Artifact.flutterFramework,
platform: TargetPlatform.ios, mode: BuildMode.release, environmentType: EnvironmentType.physical),
fileSystem.path.join(xcframeworkPath, 'ios-armv7_arm64', 'Flutter.framework'),
); );
expect( expect(
artifacts.getArtifactPath(Artifact.flutterXcframework, platform: TargetPlatform.ios, mode: BuildMode.release), artifacts.getArtifactPath(Artifact.flutterXcframework, platform: TargetPlatform.ios, mode: BuildMode.release),
...@@ -136,13 +194,78 @@ void main() { ...@@ -136,13 +194,78 @@ void main() {
}); });
testWithoutContext('getArtifactPath', () { testWithoutContext('getArtifactPath', () {
final String xcframeworkPath = artifacts.getArtifactPath(
Artifact.flutterXcframework,
platform: TargetPlatform.ios,
mode: BuildMode.release,
);
expect( expect(
artifacts.getArtifactPath(Artifact.flutterFramework, platform: TargetPlatform.ios, mode: BuildMode.release), xcframeworkPath,
fileSystem.path.join('/out', 'android_debug_unopt', 'Flutter.framework'), fileSystem.path
.join('/out', 'android_debug_unopt', 'Flutter.xcframework'),
); );
expect( expect(
artifacts.getArtifactPath(Artifact.flutterXcframework, platform: TargetPlatform.ios, mode: BuildMode.release), () => artifacts.getArtifactPath(
fileSystem.path.join('/out', 'android_debug_unopt', 'Flutter.xcframework'), Artifact.flutterFramework,
platform: TargetPlatform.ios,
mode: BuildMode.release,
environmentType: EnvironmentType.simulator,
),
throwsToolExit(
message:
'No xcframework found at /out/android_debug_unopt/Flutter.xcframework. Try running "flutter build ios".'),
);
fileSystem.directory(xcframeworkPath).createSync(recursive: true);
expect(
() => artifacts.getArtifactPath(
Artifact.flutterFramework,
platform: TargetPlatform.ios,
mode: BuildMode.release,
environmentType: EnvironmentType.simulator,
),
throwsToolExit(
message:
'No iOS frameworks found in /out/android_debug_unopt/Flutter.xcframework'),
);
fileSystem
.directory(xcframeworkPath)
.childDirectory('ios-x86_64-simulator')
.childDirectory('Flutter.framework')
.createSync(recursive: true);
fileSystem
.directory(xcframeworkPath)
.childDirectory('ios-armv7_arm64')
.childDirectory('Flutter.framework')
.createSync(recursive: true);
expect(
artifacts.getArtifactPath(
Artifact.flutterFramework,
platform: TargetPlatform.ios,
mode: BuildMode.release,
environmentType: EnvironmentType.simulator,
),
fileSystem.path
.join(xcframeworkPath, 'ios-x86_64-simulator', 'Flutter.framework'),
);
expect(
artifacts.getArtifactPath(
Artifact.flutterFramework,
platform: TargetPlatform.ios,
mode: BuildMode.release,
environmentType: EnvironmentType.physical,
),
fileSystem.path
.join(xcframeworkPath, 'ios-armv7_arm64', 'Flutter.framework'),
);
expect(
artifacts.getArtifactPath(
Artifact.flutterXcframework,
platform: TargetPlatform.ios,
mode: BuildMode.release,
),
fileSystem.path
.join('/out', 'android_debug_unopt', 'Flutter.xcframework'),
); );
expect( expect(
artifacts.getArtifactPath(Artifact.flutterTester), artifacts.getArtifactPath(Artifact.flutterTester),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment