diff --git a/packages/flutter_tools/bin/xcode_backend.sh b/packages/flutter_tools/bin/xcode_backend.sh index b8b007d8464..f5242fa4881 100755 --- a/packages/flutter_tools/bin/xcode_backend.sh +++ b/packages/flutter_tools/bin/xcode_backend.sh @@ -56,7 +56,6 @@ BuildApp() { 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" @@ -104,11 +103,8 @@ BuildApp() { exit -1 fi - 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_podspec="${framework_path}/Flutter.podspec" if [[ -n "$FLUTTER_ENGINE" ]]; then flutter_engine_flag="--local-engine-src-path=${FLUTTER_ENGINE}" @@ -128,29 +124,15 @@ BuildApp() { exit -1 fi local_engine_flag="--local-engine=${LOCAL_ENGINE}" - flutter_framework="${FLUTTER_ENGINE}/out/${LOCAL_ENGINE}/Flutter.framework" - flutter_podspec="${FLUTTER_ENGINE}/out/${LOCAL_ENGINE}/Flutter.podspec" fi + RunCommand pushd "${project_path}" > /dev/null + local bitcode_flag="" if [[ $ENABLE_BITCODE == "YES" ]]; then bitcode_flag="true" 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" - RunCommand cp -r -- "${flutter_podspec}" "${derived_dir}/engine" - RunCommand cp -r -- "${flutter_framework}" "${derived_dir}/engine" - else - RunCommand rm -rf -- "${derived_dir}/Flutter.framework" - RunCommand cp -- "${flutter_podspec}" "${derived_dir}" - RunCommand cp -r -- "${flutter_framework}" "${derived_dir}" - fi - - RunCommand pushd "${project_path}" > /dev/null - local verbose_flag="" if [[ -n "$VERBOSE_SCRIPT_LOGGING" ]]; then verbose_flag="--verbose" 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 990716cf8af..5152a7e343b 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/ios.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/ios.dart @@ -19,6 +19,75 @@ import 'assets.dart'; import 'dart.dart'; import 'icon_tree_shaker.dart'; +/// Copy the Flutter.framework and podspec from the engine cache. +class UnpackIOSEngine extends Target { + const UnpackIOSEngine(); + + @override + List get depfiles => ['ios_engine.d']; + + @override + List get dependencies => const []; + + @override + List get inputs => const []; + + @override + String get name => 'unpack_ios_engine'; + + @override + List get outputs => []; + + @override + Future build(Environment environment) async { + if (environment.defines[kBuildMode] == null) { + throw MissingDefineException(kBuildMode, 'aot_assembly'); + } + final FlutterProject flutterProject = FlutterProject.current(); + final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); + final String iosFramework = globals.artifacts + .getArtifactPath(Artifact.flutterFramework, mode: buildMode, platform: TargetPlatform.ios); + final String iosPodfile = globals.fs.directory(iosFramework) + .parent.childFile('Flutter.podspec').path; + final List inputs = globals.fs.directory(iosFramework) + .listSync(recursive: true) + .whereType() + .toList()..add(globals.fs.file(iosPodfile)); + Directory outputDirectory = environment.outputDir; + if (flutterProject.isModule) { + outputDirectory = environment.outputDir.childDirectory('engine') + ..createSync(recursive: true); + } + + await globals.processManager.run([ + 'cp', + '-r', + '--', + iosFramework, + outputDirectory.path, + ]); + await globals.processManager.run([ + 'cp', + '-r', + '--', + iosPodfile, + outputDirectory.path, + ]); + final List outputs = outputDirectory + .listSync(recursive: true) + .whereType() + .toList(); + final DepfileService depfileService = DepfileService( + logger: globals.logger, + fileSystem: globals.fs, + platform: globals.platform, + ); + final Depfile depfile = Depfile(inputs, outputs); + depfileService.writeToFile(depfile, + environment.buildDir.childFile('ios_engine.d')); + } +} + /// Supports compiling a dart kernel file to an assembly file. /// /// If more than one iOS arch is provided, then this rule will @@ -234,6 +303,7 @@ abstract class IosAssetBundle extends Target { @override List get dependencies => const [ KernelSnapshot(), + UnpackIOSEngine(), ]; @override 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 index 0aa67390007..3bf558d5589 100644 --- 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 @@ -7,10 +7,12 @@ 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/exceptions.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 'package:platform/platform.dart'; import '../../../src/common.dart'; import '../../../src/fake_process_manager.dart'; @@ -42,6 +44,8 @@ void main() { environment = Environment.test(globals.fs.currentDirectory, defines: { kTargetPlatform: 'ios', }); + }, overrides: { + Platform: () => FakePlatform(operatingSystem: 'macos', environment: const {}), }); }); @@ -160,6 +164,76 @@ void main() { expect(assetDirectory.childFile('vm_snapshot_data'), isNot(exists)); expect(assetDirectory.childFile('isolate_snapshot_data'), isNot(exists)); })); + + test('UnpackIOSEngine throws without build mode', () => testbed.run(() async { + expect(const UnpackIOSEngine().build(environment), + throwsA(isA())); + })); + + test('UnpackIOSEngine for regular project', () => testbed.run(() async { + environment.defines[kBuildMode] = getNameForBuildMode(BuildMode.profile); + environment.outputDir.createSync(); + environment.buildDir.createSync(recursive: true); + globals.fs.directory('bin/cache/artifacts/engine/ios-profile/Flutter.framework') + .createSync(recursive: true); + processManager = FakeProcessManager.list([ + const FakeCommand(command: [ + 'cp', + '-r', + '--', + 'bin/cache/artifacts/engine/ios-profile/Flutter.framework', + '/', + ]), + const FakeCommand(command: [ + 'cp', + '-r', + '--', + 'bin/cache/artifacts/engine/ios-profile/Flutter.podspec', + '/', + ]), + ]); + + await const UnpackIOSEngine().build(environment); + }, overrides: { + ProcessManager: () => processManager, + Platform: () => FakePlatform(operatingSystem: 'macos'), + })); + + test('UnpackIOSEngine for module', () => testbed.run(() async { + environment.defines[kBuildMode] = getNameForBuildMode(BuildMode.profile); + environment.outputDir.createSync(); + environment.buildDir.createSync(recursive: true); + globals.fs.file('bin/cache/artifacts/engine/ios-profile/Flutter.framework/a') + ..createSync(recursive: true) + ..writeAsStringSync('A'); + globals.fs.file('pubspec.yaml') + .writeAsStringSync(''' +flutter: + module: + androidPackage: com.example.iosadd2appflutter + iosBundleIdentifier: com.example.iosAdd2appFlutter +'''); + processManager = FakeProcessManager.list([ + const FakeCommand(command: [ + 'cp', + '-r', + '--', + 'bin/cache/artifacts/engine/ios-profile/Flutter.framework', + '/engine', + ]), + const FakeCommand(command: [ + 'cp', + '-r', + '--', + 'bin/cache/artifacts/engine/ios-profile/Flutter.podspec', + '/engine', + ]), + ]); + + await const UnpackIOSEngine().build(environment); + }, overrides: { + ProcessManager: () => processManager, + })); } class MockArtifacts extends Mock implements Artifacts {}