Skip to content
This repository has been archived by the owner on Feb 25, 2025. It is now read-only.

Commit

Permalink
macOS: Bundle dSYM packages in FlutterMacOS.xcframework (#54696)
Browse files Browse the repository at this point in the history
As of Xcode 16, App Store validation requires dSYMs for frameworks in app archives. Bundling dSYMs also significantly simplifies stack trace symbolification, so we should be doing this regardless.

This adds both framework and simulator framework dSYMs to the FlutterMacOS.xcframework bundle.

Issue: flutter/flutter#153879

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
  • Loading branch information
cbracken authored Aug 22, 2024
1 parent 29fb079 commit cf4507a
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 34 deletions.
6 changes: 6 additions & 0 deletions sky/tools/create_ios_framework.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,12 @@ def create_framework( # pylint: disable=too-many-arguments

def zip_archive(dst, args):
# pylint: disable=line-too-long

# When updating with_entitlements and without_entitlements,
# `binariesWithoutEntitlements` and `signedXcframeworks` should be updated in
# the framework's `verifyCodeSignedTestRunner`.
#
# See: https://github.com/flutter/flutter/blob/62382c7b83a16b3f48dc06c19a47f6b8667005a5/dev/bots/suite_runners/run_verify_binaries_codesigned_tests.dart#L82-L130
with_entitlements = ['gen_snapshot_arm64']
with_entitlements_file = os.path.join(dst, 'entitlements.txt')
sky_utils.write_codesign_config(with_entitlements_file, with_entitlements)
Expand Down
87 changes: 59 additions & 28 deletions sky/tools/create_macos_framework.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,22 @@ def main():

# Create XCFramework from the arm64 and x64 fat framework.
xcframeworks = [fat_framework]
create_xcframework(location=dst, name='FlutterMacOS', frameworks=xcframeworks)
dsyms = [fat_framework + '.dSYM'] if args.dsym else None
create_xcframework(location=dst, name='FlutterMacOS', frameworks=xcframeworks, dsyms=dsyms)

if args.zip:
zip_framework(dst)
zip_framework(dst, args)

return 0


def zip_framework(dst):
def zip_framework(dst, args):
# pylint: disable=line-too-long
# When updating with_entitlements and without_entitlements,
# `binariesWithoutEntitlements` and `signedXcframeworks` should be updated in
# the framework's `verifyCodeSignedTestRunner`.
#
# See: https://github.com/flutter/flutter/blob/62382c7b83a16b3f48dc06c19a47f6b8667005a5/dev/bots/suite_runners/run_verify_binaries_codesigned_tests.dart#L82-L130
framework_dst = os.path.join(dst, 'FlutterMacOS.framework')
sky_utils.write_codesign_config(os.path.join(framework_dst, 'entitlements.txt'), [])
sky_utils.write_codesign_config(
Expand All @@ -83,6 +90,7 @@ def zip_framework(dst):
]
)
sky_utils.create_zip(framework_dst, 'FlutterMacOS.framework.zip', ['.'])
# pylint: enable=line-too-long

# Double zip to make it consistent with legacy artifacts.
# TODO(fujino): remove this once https://github.com/flutter/flutter/issues/125067 is resolved
Expand All @@ -102,40 +110,63 @@ def zip_framework(dst):
final_dst_path = os.path.join(dst, 'FlutterMacOS.framework.zip')
shutil.move(final_src_path, final_dst_path)

zip_xcframework_archive(dst)
zip_xcframework_archive(dst, args)

# Generate Flutter.dSYM.zip for manual symbolification.
#
# Historically, the framework dSYM was named FlutterMacOS.dSYM, so in order
# to remain backward-compatible with existing instructions in docs/Crashes.md
# and existing tooling such as dart-lang/dart_ci, we rename back to that name
#
# TODO(cbracken): remove these archives and the upload steps once we bundle
# dSYMs in app archives. https://github.com/flutter/flutter/issues/153879
framework_dsym = framework_dst + '.dSYM'
if os.path.exists(framework_dsym):
renamed_dsym = framework_dsym.replace('FlutterMacOS.framework.dSYM', 'FlutterMacOS.dSYM')
os.rename(framework_dsym, renamed_dsym)

dsym_dst = os.path.join(dst, 'FlutterMacOS.dSYM')
if os.path.exists(dsym_dst):
# Create a zip of just the contents of the dSYM, then create a zip of that zip.
# TODO(cbracken): remove this once https://github.com/flutter/flutter/issues/125067 is resolved
sky_utils.create_zip(dsym_dst, 'FlutterMacOS.dSYM.zip', ['.'])
sky_utils.create_zip(dsym_dst, 'FlutterMacOS.dSYM_.zip', ['FlutterMacOS.dSYM.zip'])
sky_utils.create_zip(renamed_dsym, 'FlutterMacOS.dSYM.zip', ['.'])
sky_utils.create_zip(renamed_dsym, 'FlutterMacOS.dSYM_.zip', ['FlutterMacOS.dSYM.zip'])

# Move the double-zipped FlutterMacOS.dSYM.zip to dst.
dsym_final_src_path = os.path.join(dsym_dst, 'FlutterMacOS.dSYM_.zip')
dsym_final_src_path = os.path.join(renamed_dsym, 'FlutterMacOS.dSYM_.zip')
dsym_final_dst_path = os.path.join(dst, 'FlutterMacOS.dSYM.zip')
shutil.move(dsym_final_src_path, dsym_final_dst_path)


def zip_xcframework_archive(dst):
sky_utils.write_codesign_config(os.path.join(dst, 'entitlements.txt'), [])

sky_utils.write_codesign_config(
os.path.join(dst, 'without_entitlements.txt'), [
'FlutterMacOS.xcframework/macos-arm64_x86_64/'
'FlutterMacOS.framework/Versions/A/FlutterMacOS'
]
)

sky_utils.create_zip(
dst,
'framework.zip',
[
'FlutterMacOS.xcframework',
'entitlements.txt',
'without_entitlements.txt',
],
)
def zip_xcframework_archive(dst, args):
# pylint: disable=line-too-long

# When updating with_entitlements and without_entitlements,
# `binariesWithoutEntitlements` and `signedXcframeworks` should be updated in
# the framework's `verifyCodeSignedTestRunner`.
#
# See: https://github.com/flutter/flutter/blob/62382c7b83a16b3f48dc06c19a47f6b8667005a5/dev/bots/suite_runners/run_verify_binaries_codesigned_tests.dart#L82-L130
with_entitlements = []
with_entitlements_file = os.path.join(dst, 'entitlements.txt')
sky_utils.write_codesign_config(with_entitlements_file, with_entitlements)

without_entitlements = [
'FlutterMacOS.xcframework/macos-arm64_x86_64/FlutterMacOS.framework/Versions/A/FlutterMacOS',
]
if args.dsym:
without_entitlements.extend([
'FlutterMacOS.xcframework/macos-arm64_x86_64/dSYMs/FlutterMacOS.framework.dSYM/Contents/Resources/DWARF/FlutterMacOS',
])

without_entitlements_file = os.path.join(dst, 'without_entitlements.txt')
sky_utils.write_codesign_config(without_entitlements_file, without_entitlements)
# pylint: enable=line-too-long

zip_contents = [
'FlutterMacOS.xcframework',
'entitlements.txt',
'without_entitlements.txt',
]
sky_utils.assert_valid_codesign_config(dst, zip_contents, with_entitlements, without_entitlements)
sky_utils.create_zip(dst, 'framework.zip', zip_contents)


if __name__ == '__main__':
Expand Down
8 changes: 2 additions & 6 deletions sky/tools/sky_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def _contains_duplicates(strings):

def _is_macho_binary(filename):
"""Returns True if the specified path is file and a Mach-O binary."""
if not os.path.isfile(filename):
if os.path.islink(filename) or not os.path.isfile(filename):
return False

with open(filename, 'rb') as file:
Expand Down Expand Up @@ -128,11 +128,7 @@ def create_fat_macos_framework(args, dst, fat_framework, arm64_framework, x64_fr
get_mac_framework_dylib_path(x64_framework)], framework_dylib)
_set_framework_permissions(fat_framework)

# Compute dsym output path, if enabled.
framework_dsym = None
if args.dsym:
framework_dsym = os.path.join(dst, get_framework_name(fat_framework) + '.dSYM')

framework_dsym = fat_framework + '.dSYM' if args.dsym else None
_process_macos_framework(args, dst, framework_dylib, framework_dsym)


Expand Down

0 comments on commit cf4507a

Please sign in to comment.