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

Commit f93be7c

Browse files
committed
[iOS] Bundle dSYM packages in Flutter.xcframework
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 Flutter.xcframework bundle. Issue: flutter/flutter#116493
1 parent 9932f34 commit f93be7c

File tree

2 files changed

+32
-15
lines changed

2 files changed

+32
-15
lines changed

sky/tools/create_full_ios_framework.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,20 @@ def create_framework( # pylint: disable=too-many-arguments
143143
print('Cannot find iOS simulator dylib at %s' % simulator_x64_dylib)
144144
return 1
145145

146+
# Compute dsym output paths, if enabled.
147+
framework_dsym = None
148+
simulator_dsym = None
149+
if args.dsym:
150+
framework_dsym = os.path.splitext(framework)[0] + '.dSYM'
151+
simulator_dsym = os.path.splitext(simulator_framework)[0] + '.dSYM'
152+
153+
# Emit the framework for physical devices.
146154
shutil.rmtree(framework, True)
147155
shutil.copytree(arm64_framework, framework)
148156
framework_binary = os.path.join(framework, 'Flutter')
149-
process_framework(args, dst, framework, framework_binary)
157+
process_framework(args, dst, framework_binary, framework_dsym)
150158

159+
# Emit the framework for simulators.
151160
if args.simulator_arm64_out_dir is not None:
152161
shutil.rmtree(simulator_framework, True)
153162
shutil.copytree(simulator_arm64_framework, simulator_framework)
@@ -159,22 +168,23 @@ def create_framework( # pylint: disable=too-many-arguments
159168
'lipo', simulator_x64_dylib, simulator_arm64_dylib, '-create', '-output',
160169
simulator_framework_binary
161170
])
162-
process_framework(args, dst, simulator_framework, simulator_framework_binary)
171+
process_framework(args, dst, simulator_framework_binary, simulator_dsym)
163172
else:
164173
simulator_framework = simulator_x64_framework
165174

166175
# Create XCFramework from the arm-only fat framework and the arm64/x64
167176
# simulator frameworks, or just the x64 simulator framework if only that one
168177
# exists.
169178
xcframeworks = [simulator_framework, framework]
170-
create_xcframework(location=dst, name='Flutter', frameworks=xcframeworks)
179+
dsyms = [simulator_dsym, framework_dsym] if args.dsym else None
180+
create_xcframework(location=dst, name='Flutter', frameworks=xcframeworks, dsyms=dsyms)
171181

172-
# Add the x64 simulator into the fat framework
182+
# Add the x64 simulator into the fat framework.
173183
subprocess.check_call([
174184
'lipo', arm64_dylib, simulator_x64_dylib, '-create', '-output', framework_binary
175185
])
176186

177-
process_framework(args, dst, framework, framework_binary)
187+
process_framework(args, dst, framework_binary, framework_dsym)
178188
return 0
179189

180190

@@ -215,16 +225,14 @@ def zip_archive(dst):
215225
subprocess.check_call(['zip', '-r', 'extension_safe_Flutter.dSYM.zip', 'Flutter.dSYM'], cwd=dst)
216226

217227

218-
def process_framework(args, dst, framework, framework_binary):
219-
if args.dsym:
220-
dsym_out = os.path.splitext(framework)[0] + '.dSYM'
221-
subprocess.check_call([DSYMUTIL, '-o', dsym_out, framework_binary])
228+
def process_framework(args, dst, framework_binary, dsym):
229+
if dsym:
230+
subprocess.check_call([DSYMUTIL, '-o', dsym, framework_binary])
222231

223232
if args.strip:
224233
# copy unstripped
225234
unstripped_out = os.path.join(dst, 'Flutter.unstripped')
226235
shutil.copyfile(framework_binary, unstripped_out)
227-
228236
subprocess.check_call(['strip', '-x', '-S', framework_binary])
229237

230238

sky/tools/create_xcframework.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,22 @@ def main():
2222
help='The framework paths used to create the XCFramework.',
2323
required=True
2424
)
25+
parser.add_argument(
26+
'--dsyms', nargs='+', help='The dSYM paths to be bundled in the XCFramework.', required=False
27+
)
2528
parser.add_argument('--name', help='Name of the XCFramework', type=str, required=True)
2629
parser.add_argument('--location', help='Output directory', type=str, required=True)
2730

2831
args = parser.parse_args()
2932

30-
create_xcframework(args.location, args.name, args.frameworks)
33+
create_xcframework(args.location, args.name, args.frameworks, args.dsyms)
34+
3135

36+
def create_xcframework(location, name, frameworks, dsyms=None):
37+
if dsyms and len(frameworks) != len(dsyms):
38+
print('Number of --dsyms must match number of --frameworks exactly.', file=sys.stderr)
39+
sys.exit(1)
3240

33-
def create_xcframework(location, name, frameworks):
3441
output_dir = os.path.abspath(location)
3542
output_xcframework = os.path.join(output_dir, '%s.xcframework' % name)
3643

@@ -45,11 +52,13 @@ def create_xcframework(location, name, frameworks):
4552
# -framework bar/baz.framework -output output/
4653
command = ['xcrun', 'xcodebuild', '-quiet', '-create-xcframework']
4754

48-
for framework in frameworks:
49-
command.extend(['-framework', os.path.abspath(framework)])
50-
5155
command.extend(['-output', output_xcframework])
5256

57+
for i in range(len(frameworks)): # pylint: disable=consider-using-enumerate
58+
command.extend(['-framework', os.path.abspath(frameworks[i])])
59+
if dsyms:
60+
command.extend(['-debug-symbols', os.path.abspath(dsyms[i])])
61+
5362
subprocess.check_call(command, stdout=open(os.devnull, 'w'))
5463

5564

0 commit comments

Comments
 (0)