diff --git a/packages/flutter_tools/bin/xcode_backend.sh b/packages/flutter_tools/bin/xcode_backend.sh index 7f5bb868bbb..8028f563f13 100755 --- a/packages/flutter_tools/bin/xcode_backend.sh +++ b/packages/flutter_tools/bin/xcode_backend.sh @@ -202,20 +202,6 @@ BuildApp() { RunCommand cp -r -- "${app_framework}" "${derived_dir}" if [[ "${build_mode}" == "release" ]]; then - StreamOutput " ├─Generating dSYM file..." - # Xcode calls `symbols` during app store upload, which uses Spotlight to - # find dSYM files for embedded frameworks. When it finds the dSYM file for - # `App.framework` it throws an error, which aborts the app store upload. - # To avoid this, we place the dSYM files in a folder ending with ".noindex", - # which hides it from Spotlight, https://github.com/flutter/flutter/issues/22560. - RunCommand mkdir -p -- "${build_dir}/dSYMs.noindex" - RunCommand xcrun dsymutil -o "${build_dir}/dSYMs.noindex/App.framework.dSYM" "${app_framework}/App" - if [[ $? -ne 0 ]]; then - EchoError "Failed to generate debug symbols (dSYM) file for ${app_framework}/App." - exit -1 - fi - StreamOutput "done" - StreamOutput " ├─Stripping debug symbols..." RunCommand xcrun strip -x -S "${derived_dir}/App.framework/App" if [[ $? -ne 0 ]]; then diff --git a/packages/flutter_tools/lib/src/aot.dart b/packages/flutter_tools/lib/src/aot.dart index 750d20d25e4..9dd6fb2ad1e 100644 --- a/packages/flutter_tools/lib/src/aot.dart +++ b/packages/flutter_tools/lib/src/aot.dart @@ -214,7 +214,7 @@ class AotBuilder { final FlutterProject flutterProject = FlutterProject.current(); final Target target = buildMode == BuildMode.profile ? const AotAssemblyProfile() - : const AotAssemblyRelease(); + : const GenerateDebugSymbols(); final BuildResult result = await buildSystem.build(target, Environment( projectDir: flutterProject.directory, 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 9b1ede5207b..c8a71b72c85 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/ios.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/ios.dart @@ -145,6 +145,50 @@ class AotAssemblyProfile extends AotAssemblyBase { ]; } +/// Handle strip and dysm generate for iOS release. +/// +/// Xcode calls `symbols` during app store upload, which uses Spotlight to +/// find dSYM files for embedded frameworks. When it finds the dSYM file for +/// `App.framework` it throws an error, which aborts the app store upload. +/// To avoid this, we place the dSYM files in a folder ending with ".noindex", +/// which hides it from Spotlight, https://github.com/flutter/flutter/issues/22560. +class GenerateDebugSymbols extends Target { + const GenerateDebugSymbols(); + + @override + String get name => 'generate_debug_symbols'; + + @override + List get dependencies => const [ + AotAssemblyRelease() + ]; + + @override + List get inputs => const [ + Source.pattern('{OUTPUT_DIR}/App.framework/App'), + ]; + + @override + List get outputs => const [ + Source.pattern('{OUTPUT_DIR}/dSYMs.noindex/App.framework.dSYM'), + ]; + + @override + Future build(Environment environment) async { + final Directory appFramework = environment.outputDir.childDirectory('App.framework'); + final Directory noIndex = environment.outputDir.childDirectory('dSYMs.noindex') + ..createSync(); + final RunResult result = await globals.xcode.dsymutil([ + '-o', + noIndex.childFile('App.framework.dSYM').path, + appFramework.childFile('App').path, + ]); + if (result.exitCode != 0) { + throwToolExit('Failed to generate debug symbols (dSYM) file for ${appFramework.path}/App.'); + } + } +} + /// 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/macos/xcode.dart b/packages/flutter_tools/lib/src/macos/xcode.dart index 326a06f571d..af368650c95 100644 --- a/packages/flutter_tools/lib/src/macos/xcode.dart +++ b/packages/flutter_tools/lib/src/macos/xcode.dart @@ -153,6 +153,13 @@ class Xcode { ); } + Future dsymutil(List args) { + return _processUtils.run( + ['xcrun', 'dsymutil', ...args], + throwOnError: true, + ); + } + Future clang(List args) { return _processUtils.run( ['xcrun', 'clang', ...args], 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 new file mode 100644 index 00000000000..0f2d5001674 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart @@ -0,0 +1,40 @@ +// 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:flutter_tools/src/build_system/build_system.dart'; +import 'package:flutter_tools/src/build_system/targets/ios.dart'; +import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:platform/platform.dart'; + +import 'package:process/process.dart'; + +import '../../../src/common.dart'; +import '../../../src/context.dart'; +import '../../../src/testbed.dart'; + +void main() { + Testbed testbed; + + setUp(() { + testbed = Testbed(); + }); + + test('GenerateDebugSymbols uses the proper arguments', () => testbed.run(() async { + final Environment environment = Environment.test( + globals.fs.currentDirectory, + ); + await const GenerateDebugSymbols().build(environment); + }, overrides: { + Platform: () => FakePlatform(operatingSystem: 'macos'), + ProcessManager: () => FakeProcessManager.list([ + const FakeCommand(command: [ + 'xcrun', + 'dsymutil', + '-o', + '/dSYMs.noindex/App.framework.dSYM', + '/App.framework/App', + ]) + ]), + })); +}