Skip to content

Commit

Permalink
[ios] Fix app extension not able to find assets from unloaded bundle (#…
Browse files Browse the repository at this point in the history
…46283)

Directly use "flutter_assets" as the default path to find the asset path, this works for app extension when the bundle is unloaded.

This PR also adds integration tests for app extensions, which also tests the asset path. 

Fixes flutter/flutter#124292

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
  • Loading branch information
Chris Yang committed Sep 26, 2023
1 parent 8bbf25e commit 8225b56
Show file tree
Hide file tree
Showing 32 changed files with 1,163 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
FLUTTER_ASSERT_ARC

const NSString* kDefaultAssetPath = @"Frameworks/App.framework/flutter_assets";
static NSString* GetFlutterAssetPathFromBundle(NSBundle* bundle);

NSBundle* FLTFrameworkBundleInternal(NSString* flutterFrameworkBundleID, NSURL* searchURL) {
NSDirectoryEnumerator<NSURL*>* frameworkEnumerator = [NSFileManager.defaultManager
Expand All @@ -29,7 +30,7 @@
}

NSBundle* FLTGetApplicationBundle() {
NSBundle* mainBundle = [NSBundle mainBundle];
NSBundle* mainBundle = NSBundle.mainBundle;
// App extension bundle is in <AppName>.app/PlugIns/Extension.appex.
if ([mainBundle.bundleURL.pathExtension isEqualToString:@"appex"]) {
// Up two levels.
Expand All @@ -48,7 +49,7 @@
flutterFrameworkBundle = [NSBundle bundleWithIdentifier:flutterFrameworkBundleID];
}
if (flutterFrameworkBundle == nil) {
flutterFrameworkBundle = [NSBundle mainBundle];
flutterFrameworkBundle = NSBundle.mainBundle;
}
return flutterFrameworkBundle;
}
Expand All @@ -58,13 +59,23 @@
}

NSString* FLTAssetsPathFromBundle(NSBundle* bundle) {
NSString* flutterAssetsPath = GetFlutterAssetPathFromBundle(bundle);
if (flutterAssetsPath.length == 0) {
flutterAssetsPath = GetFlutterAssetPathFromBundle(NSBundle.mainBundle);
}
return flutterAssetsPath;
}

static NSString* GetFlutterAssetPathFromBundle(NSBundle* bundle) {
NSString* flutterAssetsPath = FLTAssetPath(bundle);
// Use the raw path solution so that asset path can be returned from unloaded bundles.
// See https://github.com/flutter/engine/pull/46073
NSString* assetsPath = [bundle pathForResource:flutterAssetsPath ofType:@""];

NSString* assetsPath = [bundle pathForResource:flutterAssetsPath ofType:nil];
if (assetsPath.length == 0) {
assetsPath = [[NSBundle mainBundle] pathForResource:flutterAssetsPath ofType:@""];
// In app extension, using full relative path (kDefaultAssetPath)
// returns nil when the app bundle is not loaded. Try to use
// the sub folder name, which can successfully return a valid path.
assetsPath = [bundle pathForResource:@"flutter_assets" ofType:nil];
}
return assetsPath;
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ - (void)testFLTAssetsURLFromBundle {
id mockBundle = OCMClassMock([NSBundle class]);
OCMStub([mockBundle objectForInfoDictionaryKey:@"FLTAssetsPath"]).andReturn(@"foo/assets");
NSString* resultAssetsPath = @"path/to/foo/assets";
OCMStub([mockBundle pathForResource:@"foo/assets" ofType:@""]).andReturn(resultAssetsPath);
OCMStub([mockBundle pathForResource:@"foo/assets" ofType:nil]).andReturn(resultAssetsPath);
NSString* path = FLTAssetsPathFromBundle(mockBundle);
XCTAssertEqualObjects(path, @"path/to/foo/assets");
}
Expand All @@ -102,9 +102,9 @@ - (void)testFLTAssetsURLFromBundle {
id mockBundle = OCMClassMock([NSBundle class]);
id mockMainBundle = OCMPartialMock([NSBundle mainBundle]);
NSString* resultAssetsPath = @"path/to/foo/assets";
OCMStub([mockBundle pathForResource:@"Frameworks/App.framework/flutter_assets" ofType:@""])
OCMStub([mockBundle pathForResource:@"Frameworks/App.framework/flutter_assets" ofType:nil])
.andReturn(nil);
OCMStub([mockMainBundle pathForResource:@"Frameworks/App.framework/flutter_assets" ofType:@""])
OCMStub([mockMainBundle pathForResource:@"Frameworks/App.framework/flutter_assets" ofType:nil])
.andReturn(resultAssetsPath);
NSString* path = FLTAssetsPathFromBundle(mockBundle);
XCTAssertEqualObjects(path, @"path/to/foo/assets");
Expand Down

0 comments on commit 8225b56

Please sign in to comment.