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

Commit 32ac7cd

Browse files
committed
Use privateFrameworksURL, tests
1 parent 5bd89db commit 32ac7cd

File tree

3 files changed

+50
-26
lines changed

3 files changed

+50
-26
lines changed

shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -32,33 +32,46 @@
3232

3333
static const char* kApplicationKernelSnapshotFileName = "kernel_blob.bin";
3434

35-
// Finds a bundle with the named `bundleID`.
36-
//
37-
// `+[NSBundle bundleWithIdentifier:]` is slow, and can take in the order of
38-
// tens of milliseconds in a minimal flutter app, and closer to 100 milliseconds
39-
// in a medium sized Flutter app. It is likely that the slowness comes from
40-
// having to traverse and load all bundles known to the process. Using
41-
// `+[NSBundle allframeworks]` and filtering also suffers from the same problem.
35+
// Finds a bundle with the named `bundleID` within `searchURL`.
4236
//
43-
// This implementation is an optimization to limit the search space with a hint.
44-
// Callers can provide a `hintURL` for where the bundle is expected to be
45-
// located in. If the desired bundle cannot be found here, the implementation
46-
// falls back to `+[NSBundle bundleWithIdentifier:]`.
47-
static NSBundle* FLTBundleWithIdentifier(NSString* bundleID, NSURL* hintURL) {
48-
NSArray<NSURL*>* candidates = [[NSFileManager defaultManager]
49-
contentsOfDirectoryAtURL:hintURL
50-
includingPropertiesForKeys:@[]
51-
options:0
52-
// Not interested in the error as there is a fallback.
53-
error:nil];
54-
55-
for (NSURL* candidate in candidates) {
37+
// Returns `nil` if the bundle cannot be found or if errors are encountered.
38+
NSBundle* FLTFrameworkBundleInternal(NSString* bundleID, NSURL* searchURL) {
39+
NSDirectoryEnumerator<NSURL*>* frameworkEnumerator = [NSFileManager.defaultManager
40+
enumeratorAtURL:searchURL
41+
includingPropertiesForKeys:nil
42+
options:NSDirectoryEnumerationSkipsSubdirectoryDescendants |
43+
NSDirectoryEnumerationSkipsHiddenFiles
44+
// Skip directories where errors are encountered.
45+
errorHandler:nil];
46+
47+
for (NSURL* candidate in frameworkEnumerator) {
5648
NSBundle* bundle = [NSBundle bundleWithURL:candidate];
5749
if ([bundle.bundleIdentifier isEqualToString:bundleID]) {
5850
return bundle;
5951
}
6052
}
53+
return nil;
54+
}
6155

56+
// Finds a bundle with the named `bundleID`.
57+
//
58+
// `+[NSBundle bundleWithIdentifier:]` is slow, and can take in the order of
59+
// tens of milliseconds in a minimal flutter app, and closer to 100 milliseconds
60+
// in a medium sized Flutter app on an iPhone 13. It is likely that the slowness
61+
// comes from having to traverse and load all bundles known to the process.
62+
// Using `+[NSBundle allframeworks]` and filtering also suffers from the same
63+
// problem.
64+
//
65+
// This implementation is an optimization to first limit the search space to
66+
// `+[NSBundle privateFrameworksURL]` of the main bundle, which is usually where
67+
// frameworks used by this file are placed. If the desired bundle cannot be
68+
// found here, the implementation falls back to
69+
// `+[NSBundle bundleWithIdentifier:]`.
70+
NS_INLINE NSBundle* FLTFrameworkBundleWithIdentifier(NSString* bundleID) {
71+
NSBundle* bundle = FLTFrameworkBundleInternal(bundleID, NSBundle.mainBundle.privateFrameworksURL);
72+
if (bundle != nil) {
73+
return bundle;
74+
}
6275
// Fallback to slow implementation.
6376
return [NSBundle bundleWithIdentifier:bundleID];
6477
}
@@ -77,11 +90,7 @@
7790

7891
bool hasExplicitBundle = bundle != nil;
7992
if (bundle == nil) {
80-
// The default build system for Flutter places the default bundle in the
81-
// same directory as the engine bundle (as they are both frameworks).
82-
NSURL* defaultBundleHintURL = [engineBundle.bundleURL URLByDeletingLastPathComponent];
83-
bundle =
84-
FLTBundleWithIdentifier([FlutterDartProject defaultBundleIdentifier], defaultBundleHintURL);
93+
bundle = FLTFrameworkBundleWithIdentifier([FlutterDartProject defaultBundleIdentifier]);
8594
}
8695
if (bundle == nil) {
8796
bundle = mainBundle;
@@ -344,7 +353,7 @@ - (instancetype)initWithSettings:(const flutter::Settings&)settings {
344353

345354
+ (NSString*)flutterAssetsName:(NSBundle*)bundle {
346355
if (bundle == nil) {
347-
bundle = [NSBundle bundleWithIdentifier:[FlutterDartProject defaultBundleIdentifier]];
356+
bundle = FLTFrameworkBundleWithIdentifier([FlutterDartProject defaultBundleIdentifier]);
348357
}
349358
if (bundle == nil) {
350359
bundle = [NSBundle mainBundle];

shell/platform/darwin/ios/framework/Source/FlutterDartProjectTest.mm

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,19 @@ - (void)testLeakDartVMSettingsAreCorrectlyParsed {
6060
XCTAssertEqual(settings.leak_vm, NO);
6161
}
6262

63+
- (void)testFLTFrameworkBundleInternalWhenBundleIsNotPresent {
64+
NSBundle* found =
65+
FLTFrameworkBundleInternal(@"doesNotExist", NSBundle.mainBundle.privateFrameworksURL);
66+
XCTAssertNil(found);
67+
}
68+
69+
- (void)testFLTFrameworkBundleInternalWhenBundleIsPresent {
70+
NSString* presentBundleID = @"io.flutter.flutter";
71+
NSBundle* found =
72+
FLTFrameworkBundleInternal(presentBundleID, NSBundle.mainBundle.privateFrameworksURL);
73+
XCTAssertNotNil(found);
74+
}
75+
6376
- (void)testEnableImpellerSettingIsCorrectlyParsed {
6477
// The FLTEnableImpeller's value is defined in Info.plist
6578
NSBundle* mainBundle = [NSBundle mainBundle];

shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
NS_ASSUME_NONNULL_BEGIN
1414

15+
NSBundle* FLTFrameworkBundleInternal(NSString* bundleID, NSURL* searchURL);
16+
1517
flutter::Settings FLTDefaultSettingsForBundle(NSBundle* bundle = nil);
1618

1719
@interface FlutterDartProject ()

0 commit comments

Comments
 (0)