From 4d2ce7be2cd4622cede017b0fe2b8a66c821fe48 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Wed, 5 Feb 2020 15:57:49 -0800 Subject: [PATCH] Revert "[flutter_tools] Reland migrate xcode_backend.sh to flutter assemble (#50200)" (#50228) This reverts commit 868b0e6d976370cb4bcfe6a7e060b847731d99c3. --- packages/flutter_tools/bin/xcode_backend.sh | 117 ++++++++-- packages/flutter_tools/lib/src/aot.dart | 97 ++++++++ .../flutter_tools/lib/src/build_info.dart | 2 - .../lib/src/build_system/targets/ios.dart | 210 +----------------- .../lib/src/commands/assemble.dart | 3 - .../build_system/targets/dart_test.dart | 9 +- .../build_system/targets/ios_test.dart | 166 -------------- 7 files changed, 203 insertions(+), 401 deletions(-) delete mode 100644 packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart diff --git a/packages/flutter_tools/bin/xcode_backend.sh b/packages/flutter_tools/bin/xcode_backend.sh index 5181c0b620c..00229927b10 100755 --- a/packages/flutter_tools/bin/xcode_backend.sh +++ b/packages/flutter_tools/bin/xcode_backend.sh @@ -51,10 +51,6 @@ BuildApp() { derived_dir="${project_path}/.ios/Flutter" fi - RunCommand mkdir -p -- "$derived_dir" - AssertExists "$derived_dir" - RunCommand rm -rf -- "${derived_dir}/App.framework" - # Default value of assets_path is flutter_assets local assets_path="flutter_assets" # The value of assets_path can set by add FLTAssetsPath to AppFrameworkInfo.plist @@ -100,6 +96,15 @@ BuildApp() { fi local framework_path="${FLUTTER_ROOT}/bin/cache/artifacts/engine/${artifact_variant}" + + AssertExists "${framework_path}" + AssertExists "${project_path}" + + RunCommand mkdir -p -- "$derived_dir" + AssertExists "$derived_dir" + + RunCommand rm -rf -- "${derived_dir}/App.framework" + local flutter_engine_flag="" local local_engine_flag="" local flutter_framework="${framework_path}/Flutter.framework" @@ -129,10 +134,9 @@ BuildApp() { local bitcode_flag="" if [[ $ENABLE_BITCODE == "YES" ]]; then - bitcode_flag="true" + bitcode_flag="--bitcode" fi - # TODO(jonahwilliams): move engine copying to build system. if [[ -e "${project_path}/.ios" ]]; then RunCommand rm -rf -- "${derived_dir}/engine" mkdir "${derived_dir}/engine" @@ -146,29 +150,102 @@ BuildApp() { RunCommand pushd "${project_path}" > /dev/null + AssertExists "${target_path}" + local verbose_flag="" if [[ -n "$VERBOSE_SCRIPT_LOGGING" ]]; then verbose_flag="--verbose" fi + local build_dir="${FLUTTER_BUILD_DIR:-build}" + local track_widget_creation_flag="" if [[ -n "$TRACK_WIDGET_CREATION" ]]; then - track_widget_creation_flag="true" + track_widget_creation_flag="--track-widget-creation" fi - RunCommand "${FLUTTER_ROOT}/bin/flutter" --suppress-analytics \ - ${verbose_flag} \ - ${flutter_engine_flag} \ - ${local_engine_flag} \ - assemble \ - --output="${derived_dir}/" \ - -dTargetPlatform=ios \ - -dTargetFile="${target_path}" \ - -dBuildMode=${build_mode} \ - -dIosArchs="${ARCHS}" \ - -dTrackWidgetCreation="${track_widget_creation_flag}" \ - -dEnableBitcode="${bitcode_flag}" \ - "${build_mode}_ios_bundle_flutter_assets" + if [[ "${build_mode}" != "debug" ]]; then + StreamOutput " ├─Building Dart code..." + # Transform ARCHS to comma-separated list of target architectures. + local archs="${ARCHS// /,}" + if [[ $archs =~ .*i386.* || $archs =~ .*x86_64.* ]]; then + EchoError "========================================================================" + EchoError "ERROR: Flutter does not support running in profile or release mode on" + EchoError "the Simulator (this build was: '$build_mode')." + EchoError "You can ensure Flutter runs in Debug mode with your host app in release" + EchoError "mode by setting FLUTTER_BUILD_MODE=debug in the .xcconfig associated" + EchoError "with the ${CONFIGURATION} build configuration." + EchoError "========================================================================" + exit -1 + fi + + RunCommand "${FLUTTER_ROOT}/bin/flutter" --suppress-analytics \ + ${verbose_flag} \ + build aot \ + --output-dir="${build_dir}/aot" \ + --target-platform=ios \ + --target="${target_path}" \ + --${build_mode} \ + --ios-arch="${archs}" \ + ${flutter_engine_flag} \ + ${local_engine_flag} \ + ${bitcode_flag} + + if [[ $? -ne 0 ]]; then + EchoError "Failed to build ${project_path}." + exit -1 + fi + StreamOutput "done" + + local app_framework="${build_dir}/aot/App.framework" + + RunCommand cp -r -- "${app_framework}" "${derived_dir}" + + else + RunCommand mkdir -p -- "${derived_dir}/App.framework" + + # Build stub for all requested architectures. + local arch_flags="" + read -r -a archs <<< "$ARCHS" + for arch in "${archs[@]}"; do + arch_flags="${arch_flags}-arch $arch " + done + + RunCommand eval "$(echo "static const int Moo = 88;" | xcrun clang -x c \ + ${arch_flags} \ + -fembed-bitcode-marker \ + -dynamiclib \ + -Xlinker -rpath -Xlinker '@executable_path/Frameworks' \ + -Xlinker -rpath -Xlinker '@loader_path/Frameworks' \ + -install_name '@rpath/App.framework/App' \ + -o "${derived_dir}/App.framework/App" -)" + fi + + local plistPath="${project_path}/ios/Flutter/AppFrameworkInfo.plist" + if [[ -e "${project_path}/.ios" ]]; then + plistPath="${project_path}/.ios/Flutter/AppFrameworkInfo.plist" + fi + + RunCommand cp -- "$plistPath" "${derived_dir}/App.framework/Info.plist" + + local precompilation_flag="" + if [[ "$CURRENT_ARCH" != "x86_64" ]] && [[ "$build_mode" != "debug" ]]; then + precompilation_flag="--precompiled" + fi + + StreamOutput " ├─Assembling Flutter resources..." + RunCommand "${FLUTTER_ROOT}/bin/flutter" \ + ${verbose_flag} \ + build bundle \ + --target-platform=ios \ + --target="${target_path}" \ + --${build_mode} \ + --depfile="${build_dir}/snapshot_blob.bin.d" \ + --asset-dir="${derived_dir}/App.framework/${assets_path}" \ + ${precompilation_flag} \ + ${flutter_engine_flag} \ + ${local_engine_flag} \ + ${track_widget_creation_flag} if [[ $? -ne 0 ]]; then EchoError "Failed to package ${project_path}." diff --git a/packages/flutter_tools/lib/src/aot.dart b/packages/flutter_tools/lib/src/aot.dart index 24d3b84bc69..7465654f8de 100644 --- a/packages/flutter_tools/lib/src/aot.dart +++ b/packages/flutter_tools/lib/src/aot.dart @@ -12,9 +12,14 @@ import 'base/io.dart'; import 'base/logger.dart'; import 'base/process.dart'; import 'build_info.dart'; +import 'build_system/build_system.dart'; +import 'build_system/targets/dart.dart'; +import 'build_system/targets/ios.dart'; +import 'cache.dart'; import 'dart/package_map.dart'; import 'globals.dart' as globals; import 'ios/bitcode.dart'; +import 'project.dart'; /// Builds AOT snapshots given a platform, build mode and a path to a Dart /// library. @@ -37,6 +42,21 @@ class AotBuilder { throwToolExit('No AOT build platform specified'); } + if (_canUseAssemble(platform) + && extraGenSnapshotOptions?.isEmpty != false + && extraFrontEndOptions?.isEmpty != false) { + await _buildWithAssemble( + targetFile: mainDartFile, + outputDir: outputPath, + targetPlatform: platform, + buildMode: buildMode, + quiet: quiet, + iosArchs: iosBuildArchs ?? defaultIOSArchs, + bitcode: bitcode ?? kBitcodeEnabledDefault, + ); + return; + } + if (bitcode) { if (platform != TargetPlatform.ios) { throwToolExit('Bitcode is only supported on iOS (TargetPlatform is $platform).'); @@ -154,4 +174,81 @@ class AotBuilder { } return; } + + bool _canUseAssemble(TargetPlatform targetPlatform) { + switch (targetPlatform) { + case TargetPlatform.ios: + return true; + case TargetPlatform.android_arm: + case TargetPlatform.android_arm64: + case TargetPlatform.android_x86: + case TargetPlatform.darwin_x64: + case TargetPlatform.android_x64: + case TargetPlatform.linux_x64: + case TargetPlatform.windows_x64: + case TargetPlatform.fuchsia_arm64: + case TargetPlatform.fuchsia_x64: + case TargetPlatform.tester: + case TargetPlatform.web_javascript: + default: + return false; + } + } + + Future _buildWithAssemble({ + TargetPlatform targetPlatform, + BuildMode buildMode, + String targetFile, + String outputDir, + bool quiet, + Iterable iosArchs, + bool bitcode, + }) async { + Status status; + if (!quiet) { + final String typeName = globals.artifacts.getEngineType(targetPlatform, buildMode); + status = globals.logger.startProgress( + 'Building AOT snapshot in ${getFriendlyModeName(buildMode)} mode ($typeName)...', + timeout: timeoutConfiguration.slowOperation, + ); + } + final FlutterProject flutterProject = FlutterProject.current(); + final Target target = buildMode == BuildMode.profile + ? const AotAssemblyProfile() + : const AotAssemblyRelease(); + + final BuildResult result = await buildSystem.build(target, Environment( + projectDir: flutterProject.directory, + cacheDir: globals.cache.getRoot(), + flutterRootDir: globals.fs.directory(Cache.flutterRoot), + outputDir: globals.fs.directory(outputDir), + buildDir: flutterProject.directory + .childDirectory('.dart_tool') + .childDirectory('flutter_build'), + defines: { + kBuildMode: getNameForBuildMode(buildMode), + kTargetPlatform: getNameForTargetPlatform(targetPlatform), + kTargetFile: targetFile, + kIosArchs: iosArchs.map(getNameForDarwinArch).join(','), + kBitcodeFlag: bitcode.toString() + } + )); + status?.stop(); + if (!result.success) { + for (final ExceptionMeasurement measurement in result.exceptions.values) { + globals.printError('Target ${measurement.target} failed: ${measurement.exception}', + stackTrace: measurement.fatal + ? measurement.stackTrace + : null, + ); + } + throwToolExit('Failed to build aot.'); + } + final String builtMessage = 'Built to $outputDir${globals.fs.path.separator}.'; + if (quiet) { + globals.printTrace(builtMessage); + } else { + globals.printStatus(builtMessage); + } + } } diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart index 38889540bbb..545a8690b77 100644 --- a/packages/flutter_tools/lib/src/build_info.dart +++ b/packages/flutter_tools/lib/src/build_info.dart @@ -385,8 +385,6 @@ DarwinArch getIOSArchForName(String arch) { return DarwinArch.armv7; case 'arm64': return DarwinArch.arm64; - case 'x86_64': - return DarwinArch.x86_64; } assert(false); return null; 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 144196fbc76..9b1ede5207b 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/ios.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/ios.dart @@ -11,11 +11,8 @@ import '../../base/process.dart'; import '../../build_info.dart'; import '../../globals.dart' as globals; import '../../macos/xcode.dart'; -import '../../project.dart'; import '../build_system.dart'; -import '../depfile.dart'; import '../exceptions.dart'; -import 'assets.dart'; import 'dart.dart'; /// Supports compiling a dart kernel file to an assembly file. @@ -28,7 +25,7 @@ abstract class AotAssemblyBase extends Target { @override Future build(Environment environment) async { final AOTSnapshotter snapshotter = AOTSnapshotter(reportTimings: false); - final String buildOutputPath = environment.buildDir.path; + final String buildOutputPath = environment.outputDir.path; if (environment.defines[kBuildMode] == null) { throw MissingDefineException(kBuildMode, 'aot_assembly'); } @@ -38,11 +35,8 @@ abstract class AotAssemblyBase extends Target { final bool bitcode = environment.defines[kBitcodeFlag] == 'true'; final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); final TargetPlatform targetPlatform = getTargetPlatformForName(environment.defines[kTargetPlatform]); - final List iosArchs = environment.defines[kIosArchs] - ?.split(' ') - ?.map(getIOSArchForName) - ?.toList() - ?? [DarwinArch.arm64]; + final List iosArchs = environment.defines[kIosArchs]?.split(',')?.map(getIOSArchForName)?.toList() + ?? [DarwinArch.arm64]; if (targetPlatform != TargetPlatform.ios) { throw Exception('aot_assembly is only supported for iOS applications'); } @@ -66,7 +60,7 @@ abstract class AotAssemblyBase extends Target { if (results.any((int result) => result != 0)) { throw Exception('AOT snapshotter exited with code ${results.join()}'); } - final String resultPath = globals.fs.path.join(environment.buildDir.path, 'App.framework', 'App'); + final String resultPath = globals.fs.path.join(environment.outputDir.path, 'App.framework', 'App'); globals.fs.directory(resultPath).parent.createSync(recursive: true); final ProcessResult result = await globals.processManager.run([ 'lipo', @@ -151,202 +145,6 @@ class AotAssemblyProfile extends AotAssemblyBase { ]; } -/// Create a trivial App.framework file for debug iOS builds. -class DebugUniveralFramework extends Target { - const DebugUniveralFramework(); - - @override - String get name => 'debug_universal_framework'; - - @override - List get dependencies => const [ - KernelSnapshot(), - ]; - - @override - List get inputs => const [ - Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/ios.dart'), - ]; - - @override - List get outputs => const [ - Source.pattern('{BUILD_DIR}/App') - ]; - - @override - Future build(Environment environment) async { - // Generate a trivial App.framework. - final File iphoneFile = environment.buildDir.childFile('iphone_framework'); - final File simulatorFile = environment.buildDir.childFile('simulator_framework'); - final File lipoOutputFile = environment.buildDir.childFile('App'); - final RunResult iphoneResult = await createStubAppFramework( - iphoneFile, - SdkType.iPhone, - ); - final RunResult simulatorResult = await createStubAppFramework( - simulatorFile, - SdkType.iPhoneSimulator, - ); - if (iphoneResult.exitCode != 0 || simulatorResult.exitCode != 0) { - throw Exception('Failed to create App.framework.'); - } - final List lipoCommand = [ - 'xcrun', - 'lipo', - '-create', - iphoneFile.path, - simulatorFile.path, - '-output', - lipoOutputFile.path - ]; - final RunResult lipoResult = await processUtils.run( - lipoCommand, - ); - - if (lipoResult.exitCode != 0) { - throw Exception('Failed to create App.framework.'); - } - } -} - -/// The base class for all iOS bundle targets. -/// -/// This is responsible for setting up the basic App.framework structure, including: -/// * Copying the app.dill/kernel_blob.bin from the build directory to assets (debug) -/// * Copying the precompiled isolate/vm data from the engine (debug) -/// * Copying the flutter assets to App.framework/flutter_assets -/// * Copying either the stub or real App assembly file to App.framework/App -abstract class IosAssetBundle extends Target { - const IosAssetBundle(); - - @override - List get dependencies => const [ - KernelSnapshot(), - ]; - - @override - List get inputs => const [ - Source.pattern('{BUILD_DIR}/App'), - Source.pattern('{PROJECT_DIR}/pubspec.yaml'), - ]; - - @override - List get outputs => const [ - Source.pattern('{OUTPUT_DIR}/App.framework/App'), - Source.pattern('{OUTPUT_DIR}/App.framework/Info.plist') - ]; - - @override - List get depfiles => [ - 'flutter_assets.d', - ]; - - @override - Future build(Environment environment) async { - if (environment.defines[kBuildMode] == null) { - throw MissingDefineException(kBuildMode, name); - } - final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); - final Directory frameworkDirectory = environment.outputDir.childDirectory('App.framework'); - final Directory assetDirectory = frameworkDirectory.childDirectory('flutter_assets'); - frameworkDirectory.createSync(recursive: true); - assetDirectory.createSync(); - - // Only copy the prebuilt runtimes and kernel blob in debug mode. - if (buildMode == BuildMode.debug) { - // Copy the App.framework to the output directory. - environment.buildDir.childFile('App') - .copySync(frameworkDirectory.childFile('App').path); - - final String vmSnapshotData = globals.artifacts.getArtifactPath(Artifact.vmSnapshotData, mode: BuildMode.debug); - final String isolateSnapshotData = globals.artifacts.getArtifactPath(Artifact.isolateSnapshotData, mode: BuildMode.debug); - environment.buildDir.childFile('app.dill') - .copySync(assetDirectory.childFile('kernel_blob.bin').path); - globals.fs.file(vmSnapshotData) - .copySync(assetDirectory.childFile('vm_snapshot_data').path); - globals.fs.file(isolateSnapshotData) - .copySync(assetDirectory.childFile('isolate_snapshot_data').path); - } else { - environment.buildDir.childDirectory('App.framework').childFile('App') - .copySync(frameworkDirectory.childFile('App').path); - } - - // Copy the assets. - final Depfile assetDepfile = await copyAssets(environment, assetDirectory); - assetDepfile.writeToFile(environment.buildDir.childFile('flutter_assets.d')); - - - // Copy the plist from either the project or module. - // TODO(jonahwilliams): add plist to inputs - final FlutterProject flutterProject = FlutterProject.fromDirectory(environment.projectDir); - final Directory plistRoot = flutterProject.isModule - ? flutterProject.ios.ephemeralDirectory - : environment.projectDir.childDirectory('ios'); - plistRoot - .childDirectory('Flutter') - .childFile('AppFrameworkInfo.plist') - .copySync(environment.outputDir - .childDirectory('App.framework') - .childFile('Info.plist').path); - } -} - -/// Build a debug iOS application bundle. -class DebugIosApplicationBundle extends IosAssetBundle { - const DebugIosApplicationBundle(); - - @override - String get name => 'debug_ios_bundle_flutter_assets'; - - @override - List get inputs => [ - const Source.artifact(Artifact.vmSnapshotData, mode: BuildMode.debug), - const Source.artifact(Artifact.isolateSnapshotData, mode: BuildMode.debug), - const Source.pattern('{BUILD_DIR}/app.dill'), - ...super.inputs, - ]; - - @override - List get outputs => [ - const Source.pattern('{OUTPUT_DIR}/App.framework/flutter_assets/vm_snapshot_data'), - const Source.pattern('{OUTPUT_DIR}/App.framework/flutter_assets/isolate_snapshot_data'), - const Source.pattern('{OUTPUT_DIR}/App.framework/flutter_assets/kernel_blob.bin'), - ...super.outputs, - ]; - - @override - List get dependencies => [ - const DebugUniveralFramework(), - ...super.dependencies, - ]; -} - -/// Build a profile iOS application bundle. -class ProfileIosApplicationBundle extends IosAssetBundle { - const ProfileIosApplicationBundle(); - - @override - String get name => 'profile_ios_bundle_flutter_assets'; - - @override - List get dependencies => const [ - AotAssemblyProfile(), - ]; -} - -/// Build a release iOS application bundle. -class ReleaseIosApplicationBundle extends IosAssetBundle { - const ReleaseIosApplicationBundle(); - - @override - String get name => 'release_ios_bundle_flutter_assets'; - - @override - List get dependencies => const [ - AotAssemblyRelease(), - ]; -} - /// Create an App.framework for debug iOS targets. /// /// This framework needs to exist for the Xcode project to link/bundle, diff --git a/packages/flutter_tools/lib/src/commands/assemble.dart b/packages/flutter_tools/lib/src/commands/assemble.dart index 6a8ca21a5df..4d89483cdda 100644 --- a/packages/flutter_tools/lib/src/commands/assemble.dart +++ b/packages/flutter_tools/lib/src/commands/assemble.dart @@ -50,9 +50,6 @@ const List _kDefaultTargets = [ androidArmReleaseBundle, androidArm64ReleaseBundle, androidx64ReleaseBundle, - DebugIosApplicationBundle(), - ProfileIosApplicationBundle(), - ReleaseIosApplicationBundle(), ]; /// Assemble provides a low level API to interact with the flutter tool build diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/dart_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/dart_test.dart index 590887d3ae3..baa0699cef9 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/dart_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/dart_test.dart @@ -315,7 +315,7 @@ flutter_tools:lib/'''); })); test('aot_assembly_profile will lipo binaries together when multiple archs are requested', () => testbed.run(() async { - iosEnvironment.defines[kIosArchs] ='armv7 arm64'; + iosEnvironment.defines[kIosArchs] ='armv7,arm64'; when(mockProcessManager.run(any)).thenAnswer((Invocation invocation) async { globals.fs.file(globals.fs.path.join(iosEnvironment.buildDir.path, 'App.framework', 'App')) .createSync(recursive: true); @@ -360,7 +360,7 @@ flutter_tools:lib/'''); })); test('aot_assembly_profile with bitcode sends correct argument to snapshotter (mutli arch)', () => testbed.run(() async { - iosEnvironment.defines[kIosArchs] = 'armv7 arm64'; + iosEnvironment.defines[kIosArchs] = 'armv7,arm64'; iosEnvironment.defines[kBitcodeFlag] = 'true'; final FakeProcessResult fakeProcessResult = FakeProcessResult( @@ -377,8 +377,9 @@ flutter_tools:lib/'''); when(mockXcode.cc(any)).thenAnswer((_) => Future.value(fakeRunResult)); when(mockXcode.clang(any)).thenAnswer((_) => Future.value(fakeRunResult)); - await const AotAssemblyProfile().build(iosEnvironment); + final BuildResult result = await buildSystem.build(const AotAssemblyProfile(), iosEnvironment); + expect(result.success, true); verify(mockXcode.cc(argThat(contains('-fembed-bitcode')))).called(2); verify(mockXcode.clang(argThat(contains('-fembed-bitcode')))).called(2); }, overrides: { @@ -387,7 +388,7 @@ flutter_tools:lib/'''); })); test('aot_assembly_profile will lipo binaries together when multiple archs are requested', () => testbed.run(() async { - iosEnvironment.defines[kIosArchs] = 'armv7 arm64'; + iosEnvironment.defines[kIosArchs] = 'armv7,arm64'; when(mockProcessManager.run(any)).thenAnswer((Invocation invocation) async { globals.fs.file(globals.fs.path.join(iosEnvironment.buildDir.path, 'App.framework', 'App')) .createSync(recursive: true); diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart deleted file mode 100644 index 2582b5cc7ef..00000000000 --- a/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:file_testing/file_testing.dart'; -import 'package:flutter_tools/src/artifacts.dart'; -import 'package:flutter_tools/src/base/file_system.dart'; -import 'package:flutter_tools/src/build_info.dart'; -import 'package:flutter_tools/src/build_system/build_system.dart'; -import 'package:flutter_tools/src/build_system/targets/dart.dart'; -import 'package:flutter_tools/src/build_system/targets/ios.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; -import 'package:mockito/mockito.dart'; - -import '../../../src/common.dart'; -import '../../../src/fake_process_manager.dart'; -import '../../../src/testbed.dart'; - -const List _kSharedConfig = [ - '-dynamiclib', - '-fembed-bitcode-marker', - '-Xlinker', - '-rpath', - '-Xlinker', - '@executable_path/Frameworks', - '-Xlinker', - '-rpath', - '-Xlinker', - '@loader_path/Frameworks', - '-install_name', - '@rpath/App.framework/App', - '-isysroot', -]; - -void main() { - Testbed testbed; - Environment environment; - ProcessManager processManager; - - setUp(() { - testbed = Testbed(setup: () { - environment = Environment.test(globals.fs.currentDirectory, defines: { - kTargetPlatform: 'ios', - }); - }); - }); - - test('DebugUniveralFramework creates expected binary', () => testbed.run(() async { - processManager = FakeProcessManager.list([ - // Create iphone stub. - const FakeCommand(command: ['xcrun', '--sdk', 'iphoneos', '--show-sdk-path']), - FakeCommand(command: [ - 'xcrun', - 'clang', - '-x', - 'c', - // iphone gets both arm arches - '-arch', - 'armv7', - '-arch', - 'arm64', - globals.fs.path.absolute(globals.fs.path.join('.tmp_rand0', 'flutter_tools_stub_source.rand0', 'debug_app.cc')), - ..._kSharedConfig, - '', - '-o', - environment.buildDir.childFile('iphone_framework').path - ]), - // Create simulator stub. - const FakeCommand(command: ['xcrun', '--sdk', 'iphonesimulator', '--show-sdk-path']), - FakeCommand(command: [ - 'xcrun', - 'clang', - '-x', - 'c', - // Simulator only as x86_64 arch - '-arch', - 'x86_64', - globals.fs.path.absolute(globals.fs.path.join('.tmp_rand0', 'flutter_tools_stub_source.rand0', 'debug_app.cc')), - ..._kSharedConfig, - '', - '-o', - environment.buildDir.childFile('simulator_framework').path - ]), - // Lipo stubs together. - FakeCommand(command: [ - 'xcrun', - 'lipo', - '-create', - environment.buildDir.childFile('iphone_framework').path, - environment.buildDir.childFile('simulator_framework').path, - '-output', - environment.buildDir.childFile('App').path, - ]), - ]); - - await const DebugUniveralFramework().build(environment); - }, overrides: { - ProcessManager: () => processManager, - })); - - test('DebugIosApplicationBundle', () => testbed.run(() async { - environment.defines[kBuildMode] = 'debug'; - // Precompiled dart data - when(globals.artifacts.getArtifactPath(Artifact.vmSnapshotData, mode: BuildMode.debug)) - .thenReturn('vm_snapshot_data'); - when(globals.artifacts.getArtifactPath(Artifact.isolateSnapshotData, mode: BuildMode.debug)) - .thenReturn('isolate_snapshot_data'); - globals.fs.file('vm_snapshot_data').createSync(); - globals.fs.file('isolate_snapshot_data').createSync(); - // Project info - globals.fs.file('pubspec.yaml').writeAsStringSync('name: hello'); - globals.fs.file('.packages').writeAsStringSync('\n'); - // Plist file - globals.fs.file(globals.fs.path.join('ios', 'Flutter', 'AppFrameworkInfo.plist')) - ..createSync(recursive: true); - // App kernel - environment.buildDir.childFile('app.dill').createSync(recursive: true); - // Stub framework - environment.buildDir.childFile('App').createSync(); - - await const DebugIosApplicationBundle().build(environment); - - final Directory frameworkDirectory = environment.outputDir.childDirectory('App.framework'); - expect(frameworkDirectory.childFile('App'), exists); - expect(frameworkDirectory.childFile('Info.plist'), exists); - - final Directory assetDirectory = frameworkDirectory.childDirectory('flutter_assets'); - expect(assetDirectory.childFile('kernel_blob.bin'), exists); - expect(assetDirectory.childFile('AssetManifest.json'), exists); - expect(assetDirectory.childFile('vm_snapshot_data'), exists); - expect(assetDirectory.childFile('isolate_snapshot_data'), exists); - }, overrides: { - Artifacts: () => MockArtifacts(), - })); - - test('ReleaseIosApplicationBundle', () => testbed.run(() async { - environment.defines[kBuildMode] = 'release'; - - // Project info - globals.fs.file('pubspec.yaml').writeAsStringSync('name: hello'); - globals.fs.file('.packages').writeAsStringSync('\n'); - // Plist file - globals.fs.file(globals.fs.path.join('ios', 'Flutter', 'AppFrameworkInfo.plist')) - ..createSync(recursive: true); - - // Real framework - environment.buildDir - .childDirectory('App.framework') - .childFile('App') - .createSync(recursive: true); - - await const ReleaseIosApplicationBundle().build(environment); - - final Directory frameworkDirectory = environment.outputDir.childDirectory('App.framework'); - expect(frameworkDirectory.childFile('App'), exists); - expect(frameworkDirectory.childFile('Info.plist'), exists); - - final Directory assetDirectory = frameworkDirectory.childDirectory('flutter_assets'); - expect(assetDirectory.childFile('kernel_blob.bin'), isNot(exists)); - expect(assetDirectory.childFile('AssetManifest.json'), exists); - expect(assetDirectory.childFile('vm_snapshot_data'), isNot(exists)); - expect(assetDirectory.childFile('isolate_snapshot_data'), isNot(exists)); - })); -} - -class MockArtifacts extends Mock implements Artifacts {}