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 8f8a7d90209..82266bc6603 100644 --- a/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart +++ b/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart @@ -102,6 +102,7 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals options: [ 'ios-framework', '--universal', + '--verbose', '--output=$outputDirectoryName' ], ); @@ -164,16 +165,43 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals 'App', ); - // This seemed easier than an explicit Xcode version check. - String xcodeArmDirectoryName; + // Based on the locally installed version of Xcode. + String localXcodeArmDirectoryName; if (exists(File(xcode11AppFrameworkDirectory))) { - xcodeArmDirectoryName = xcode11ArmDirectoryName; + localXcodeArmDirectoryName = xcode11ArmDirectoryName; } else if (exists(File(xcode12AppFrameworkDirectory))) { - xcodeArmDirectoryName = xcode12ArmDirectoryName; + localXcodeArmDirectoryName = xcode12ArmDirectoryName; } else { 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( outputPath, 'Debug', @@ -214,7 +242,7 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals outputPath, mode, 'App.xcframework', - xcodeArmDirectoryName, + localXcodeArmDirectoryName, 'App.framework', 'App', )); @@ -239,30 +267,25 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals 'Flutter', ); - await _checkFrameworkArchs(engineFrameworkPath, mode == 'Debug'); + await _checkFrameworkArchs(engineFrameworkPath, true); await _checkBitcode(engineFrameworkPath, mode); checkFileExists(path.join( outputPath, mode, 'Flutter.xcframework', - xcodeArmDirectoryName, + builderXcodeArmDirectoryName, 'Flutter.framework', 'Flutter', )); - final String simulatorFrameworkPath = path.join( + checkFileExists(path.join( outputPath, mode, 'Flutter.xcframework', 'ios-x86_64-simulator', 'Flutter.framework', 'Flutter', - ); - if (mode == 'Debug') { - checkFileExists(simulatorFrameworkPath); - } else { - checkFileNotExists(simulatorFrameworkPath); - } + )); } section("Check all modes' engine header"); @@ -287,7 +310,7 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals outputPath, mode, 'device_info.xcframework', - xcodeArmDirectoryName, + localXcodeArmDirectoryName, 'device_info.framework', 'device_info', )); @@ -296,7 +319,7 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals outputPath, mode, 'device_info.xcframework', - xcodeArmDirectoryName, + localXcodeArmDirectoryName, 'device_info.framework', 'Headers', 'DeviceInfoPlugin.h', @@ -357,7 +380,7 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals outputPath, mode, 'FlutterPluginRegistrant.xcframework', - xcodeArmDirectoryName, + localXcodeArmDirectoryName, 'FlutterPluginRegistrant.framework', 'Headers', 'GeneratedPluginRegistrant.h', diff --git a/dev/devicelab/lib/framework/ios.dart b/dev/devicelab/lib/framework/ios.dart index fc19f07f4eb..da5b71777a9 100644 --- a/dev/devicelab/lib/framework/ios.dart +++ b/dev/devicelab/lib/framework/ios.dart @@ -22,6 +22,8 @@ Future containsBitcode(String pathToBinary) async { // See: https://stackoverflow.com/questions/32755775/how-to-check-a-static-library-is-built-contain-bitcode final String loadCommands = await eval('otool', [ '-l', + '-arch', + 'arm64', pathToBinary, ]); if (!loadCommands.contains('__LLVM')) { diff --git a/packages/flutter_tools/bin/podhelper.rb b/packages/flutter_tools/bin/podhelper.rb index 87b495cf8d2..c1c7022c065 100644 --- a/packages/flutter_tools/bin/podhelper.rb +++ b/packages/flutter_tools/bin/podhelper.rb @@ -35,13 +35,27 @@ def flutter_additional_ios_build_settings(target) # This podhelper script is at $FLUTTER_ROOT/packages/flutter_tools/bin. # Add search paths from $FLUTTER_ROOT/bin/cache/artifacts/engine. artifacts_dir = File.join('..', '..', '..', '..', 'bin', 'cache', 'artifacts', 'engine') - debug_framework_dir = File.expand_path(File.join(artifacts_dir, 'ios'), __FILE__) - release_framework_dir = File.expand_path(File.join(artifacts_dir, 'ios-release'), __FILE__) + debug_framework_dir = File.expand_path(File.join(artifacts_dir, 'ios', 'Flutter.xcframework'), __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| # 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 - 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['CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER'] = 'NO' diff --git a/packages/flutter_tools/bin/xcode_backend.sh b/packages/flutter_tools/bin/xcode_backend.sh index 3ca63507713..c4df0b5cc0f 100755 --- a/packages/flutter_tools/bin/xcode_backend.sh +++ b/packages/flutter_tools/bin/xcode_backend.sh @@ -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 flutter_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 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 exit -1 fi 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 local bitcode_flag="" diff --git a/packages/flutter_tools/lib/src/artifacts.dart b/packages/flutter_tools/lib/src/artifacts.dart index e540acbd15c..9386b088bbb 100644 --- a/packages/flutter_tools/lib/src/artifacts.dart +++ b/packages/flutter_tools/lib/src/artifacts.dart @@ -5,6 +5,7 @@ import 'package:meta/meta.dart'; import 'package:process/process.dart'; +import 'base/common.dart'; import 'base/file_system.dart'; import 'base/platform.dart'; import 'base/utils.dart'; @@ -305,12 +306,14 @@ class CachedArtifacts implements Artifacts { BuildMode mode, EnvironmentType environmentType) { switch (artifact) { case Artifact.genSnapshot: - case Artifact.flutterFramework: case Artifact.flutterXcframework: case Artifact.frontendServerSnapshotForEngineDartSdk: final String artifactFileName = _artifactToFileName(artifact); final String engineDir = _getEngineArtifactsPath(platform, mode); 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.idevicesyslog: final String artifactFileName = _artifactToFileName(artifact); @@ -527,6 +530,38 @@ HostPlatform _currentHostPlatformAsHost(Platform platform) { 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()) { + 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. class LocalEngineArtifacts implements Artifacts { LocalEngineArtifacts( @@ -578,7 +613,8 @@ class LocalEngineArtifacts implements Artifacts { case Artifact.platformLibrariesJson: return _fileSystem.path.join(_getFlutterPatchedSdkPath(mode), 'lib', artifactFileName); case Artifact.flutterFramework: - return _fileSystem.path.join(engineOutPath, artifactFileName); + return _getIosEngineArtifactPath( + engineOutPath, environmentType, _fileSystem); case Artifact.flutterPatchedSdkPath: // When using local engine always use [BuildMode.debug] regardless of // what was specified in [mode] argument because local engine will 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 1d75ec2fab9..e26ee1d6dba 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/ios.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/ios.dart @@ -249,7 +249,7 @@ abstract class UnpackIOS extends Target { const Source.pattern( '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/ios.dart'), Source.artifact( - Artifact.flutterFramework, + Artifact.flutterXcframework, platform: TargetPlatform.ios, mode: buildMode, ), diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart index 9a79ba51164..e6d96e69671 100644 --- a/packages/flutter_tools/lib/src/cache.dart +++ b/packages/flutter_tools/lib/src/cache.dart @@ -924,14 +924,11 @@ abstract class EngineCachedArtifact extends CachedArtifact { _makeFilesExecutable(dir, operatingSystemUtils); - const List frameworkNames = ['Flutter', 'FlutterMacOS']; - for (final String frameworkName in frameworkNames) { - final File frameworkZip = fileSystem.file(fileSystem.path.join(dir.path, '$frameworkName.framework.zip')); - if (frameworkZip.existsSync()) { - final Directory framework = fileSystem.directory(fileSystem.path.join(dir.path, '$frameworkName.framework')); - framework.createSync(); - operatingSystemUtils.unzip(frameworkZip, framework); - } + final File frameworkZip = fileSystem.file(fileSystem.path.join(dir.path, 'FlutterMacOS.framework.zip')); + if (frameworkZip.existsSync()) { + final Directory framework = fileSystem.directory(fileSystem.path.join(dir.path, 'FlutterMacOS.framework')); + framework.createSync(); + operatingSystemUtils.unzip(frameworkZip, framework); } } 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 4e3dcfedfea..74172609003 100644 --- a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart +++ b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart @@ -295,10 +295,7 @@ LICENSE s.source = { :http => '${_cache.storageBaseUrl}/flutter_infra/flutter/${_cache.engineRevision}/$artifactsMode/artifacts.zip' } s.documentation_url = 'https://flutter.dev/docs' s.platform = :ios, '8.0' - s.vendored_frameworks = 'Flutter.framework' - s.prepare_command = <<-CMD -unzip Flutter.framework -d Flutter.framework -CMD + s.vendored_frameworks = 'Flutter.xcframework' end '''; @@ -314,56 +311,31 @@ end Directory modeDirectory, ) async { final Status status = globals.logger.startProgress( - ' ├─Populating Flutter.framework...', + ' ├─Populating Flutter.xcframework...', ); final String engineCacheFlutterFrameworkDirectory = globals.artifacts.getArtifactPath( - Artifact.flutterFramework, + Artifact.flutterXcframework, platform: TargetPlatform.ios, mode: buildInfo.mode, ); final String flutterFrameworkFileName = globals.fs.path.basename( engineCacheFlutterFrameworkDirectory, ); - final Directory fatFlutterFrameworkCopy = modeDirectory.childDirectory( + final Directory flutterFrameworkCopy = modeDirectory.childDirectory( flutterFrameworkFileName, ); try { - // Copy universal engine cache framework to mode directory. + // Copy xcframework engine cache framework to mode directory. globals.fsUtils.copyDirectorySync( 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 lipoCommand = [ - ...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 { status.stop(); } - await _produceXCFrameworkFromUniversal(buildInfo, fatFlutterFrameworkCopy); + await _produceUniversalFromXCFramework(buildInfo, flutterFrameworkCopy); } Future _produceAppFramework( @@ -558,112 +530,34 @@ end } } - Future _produceXCFrameworkFromUniversal(BuildInfo buildInfo, Directory fatFramework) async { - if (boolArg('xcframework')) { - final String frameworkBinaryName = globals.fs.path.basenameWithoutExtension( - fatFramework.basename); + Future _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.xcframework...', + ' ├─Creating $frameworkBinaryName.framework...', ); try { - if (buildInfo.mode == BuildMode.debug) { - await _produceDebugXCFramework(fatFramework, frameworkBinaryName); - } else { - await _produceXCFramework( - [fatFramework], frameworkBinaryName, - fatFramework.parent); - } + final Iterable frameworks = xcframework + .listSync() + .whereType() + .map((Directory triple) => triple + .listSync() + .whereType() + .firstWhere((Directory frameworkDirectory) => + frameworkDirectory.basename == + '$frameworkBinaryName.framework')); + + await _produceUniversalFramework( + frameworks, frameworkBinaryName, xcframework.parent); } finally { status.stop(); } } - if (!boolArg('universal')) { - fatFramework.deleteSync(recursive: true); - } - } - - Future _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 lipoCommand = [ - ...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 = [ - ...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( - [ - armFlutterFrameworkDirectory, - simulatorFlutterFrameworkDirectory - ], - frameworkBinaryName, - fatFramework.parent, - ); - } finally { - temporaryOutput.deleteSync(recursive: true); + if (!boolArg('xcframework')) { + xcframework.deleteSync(recursive: true); } } diff --git a/packages/flutter_tools/lib/src/ios/bitcode.dart b/packages/flutter_tools/lib/src/ios/bitcode.dart index ec0054505e4..fec5a376b7c 100644 --- a/packages/flutter_tools/lib/src/ios/bitcode.dart +++ b/packages/flutter_tools/lib/src/ios/bitcode.dart @@ -13,16 +13,14 @@ import '../macos/xcode.dart'; const bool kBitcodeEnabledDefault = false; -Future validateBitcode(BuildMode buildMode, TargetPlatform targetPlatform) async { +Future validateBitcode(BuildMode buildMode, TargetPlatform targetPlatform, EnvironmentType environmentType) async { final Artifacts localArtifacts = globals.artifacts; final String flutterFrameworkPath = localArtifacts.getArtifactPath( Artifact.flutterFramework, mode: buildMode, platform: targetPlatform, + environmentType: environmentType, ); - if (!globals.fs.isDirectorySync(flutterFrameworkPath)) { - throwToolExit('Flutter.framework not found at $flutterFrameworkPath'); - } final Xcode xcode = context.get(); final RunResult clangResult = await xcode.clang(['--version']); diff --git a/packages/flutter_tools/lib/src/macos/cocoapod_utils.dart b/packages/flutter_tools/lib/src/macos/cocoapod_utils.dart index 14ff38d8b35..bfa7c1d1679 100644 --- a/packages/flutter_tools/lib/src/macos/cocoapod_utils.dart +++ b/packages/flutter_tools/lib/src/macos/cocoapod_utils.dart @@ -4,6 +4,7 @@ import '../base/fingerprint.dart'; import '../build_info.dart'; +import '../cache.dart'; import '../globals.dart' as globals; import '../plugins.dart'; import '../project.dart'; @@ -28,6 +29,13 @@ Future processPodsIfNeeded( xcodeProject.xcodeProjectInfoFile.path, xcodeProject.podfile.path, xcodeProject.generatedXcodePropertiesFile.path, + globals.fs.path.join( + Cache.flutterRoot, + 'packages', + 'flutter_tools', + 'bin', + 'podhelper.rb', + ), ], fileSystem: globals.fs, logger: globals.logger, diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index 29a0a2c729f..064c10bd1c3 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart @@ -659,7 +659,7 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject { // to be in this location. final Directory framework = globals.fs.directory( globals.artifacts.getArtifactPath( - Artifact.flutterFramework, + Artifact.flutterXcframework, platform: TargetPlatform.ios, mode: mode, environmentType: environmentType, @@ -668,7 +668,7 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject { if (framework.existsSync()) { globals.fsUtils.copyDirectorySync( framework, - engineCopyDirectory.childDirectory('Flutter.framework'), + engineCopyDirectory.childDirectory('Flutter.xcframework'), ); } } diff --git a/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Flutter/engine/Flutter.podspec.tmpl b/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Flutter/engine/Flutter.podspec.tmpl index 5ca30416bac..3a6ef67db2d 100644 --- a/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Flutter/engine/Flutter.podspec.tmpl +++ b/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Flutter/engine/Flutter.podspec.tmpl @@ -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.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } s.ios.deployment_target = '8.0' - s.vendored_frameworks = 'Flutter.framework' + s.vendored_frameworks = 'Flutter.xcframework' end diff --git a/packages/flutter_tools/templates/module/ios/library/Flutter.tmpl/podhelper.rb.tmpl b/packages/flutter_tools/templates/module/ios/library/Flutter.tmpl/podhelper.rb.tmpl index b6b078c8d33..fd1ecb6e31c 100644 --- a/packages/flutter_tools/templates/module/ios/library/Flutter.tmpl/podhelper.rb.tmpl +++ b/packages/flutter_tools/templates/module/ios/library/Flutter.tmpl/podhelper.rb.tmpl @@ -30,7 +30,7 @@ end def install_flutter_engine_pod current_directory = File.expand_path('..', __FILE__) 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) if !File.exist?(copied_engine) # Copy the debug engine to have something to link against if the xcode backend script has not run yet. diff --git a/packages/flutter_tools/test/general.shard/artifacts_test.dart b/packages/flutter_tools/test/general.shard/artifacts_test.dart index fc1bdf5cfc2..2ca82bcb9a4 100644 --- a/packages/flutter_tools/test/general.shard/artifacts_test.dart +++ b/packages/flutter_tools/test/general.shard/artifacts_test.dart @@ -42,9 +42,67 @@ void main() { }); testWithoutContext('getArtifactPath', () { + final String xcframeworkPath = artifacts.getArtifactPath( + Artifact.flutterXcframework, + platform: TargetPlatform.ios, + mode: BuildMode.release, + ); expect( - artifacts.getArtifactPath(Artifact.flutterFramework, platform: TargetPlatform.ios, mode: BuildMode.release), - fileSystem.path.join('root', 'bin', 'cache', 'artifacts', 'engine', 'ios-release', 'Flutter.framework'), + xcframeworkPath, + fileSystem.path.join( + 'root', + 'bin', + 'cache', + 'artifacts', + 'engine', + 'ios-release', + 'Flutter.xcframework', + ), + ); + expect( + () => artifacts.getArtifactPath( + 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( artifacts.getArtifactPath(Artifact.flutterXcframework, platform: TargetPlatform.ios, mode: BuildMode.release), @@ -136,13 +194,78 @@ void main() { }); testWithoutContext('getArtifactPath', () { - expect( - artifacts.getArtifactPath(Artifact.flutterFramework, platform: TargetPlatform.ios, mode: BuildMode.release), - fileSystem.path.join('/out', 'android_debug_unopt', 'Flutter.framework'), + final String xcframeworkPath = artifacts.getArtifactPath( + Artifact.flutterXcframework, + platform: TargetPlatform.ios, + mode: BuildMode.release, ); expect( - artifacts.getArtifactPath(Artifact.flutterXcframework, platform: TargetPlatform.ios, mode: BuildMode.release), - fileSystem.path.join('/out', 'android_debug_unopt', 'Flutter.xcframework'), + xcframeworkPath, + fileSystem.path + .join('/out', 'android_debug_unopt', 'Flutter.xcframework'), + ); + expect( + () => artifacts.getArtifactPath( + 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( artifacts.getArtifactPath(Artifact.flutterTester),