Skip to content

Commit 0ccbecb

Browse files
Implement catalog conversion natively and add fallback
1 parent a4e0f09 commit 0ccbecb

8 files changed

Lines changed: 99 additions & 26 deletions

File tree

-122 KB
Binary file not shown.

packages/react-native/Libraries/Image/AssetSourceResolver.js

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,6 @@ class AssetSourceResolver {
7171
return !!(this.jsbundleUrl && this.jsbundleUrl.startsWith('file://'));
7272
}
7373

74-
isCatalogAsset(): boolean {
75-
return (
76-
this.asset.__packager_asset &&
77-
(this.asset.type === 'png' ||
78-
this.asset.type === 'jpg' ||
79-
this.asset.type === 'jpeg')
80-
);
81-
}
82-
8374
defaultAsset(): ResolvedAssetSource {
8475
if (this.isLoadedFromServer()) {
8576
return this.assetServerURL();
@@ -90,9 +81,7 @@ class AssetSourceResolver {
9081
? this.drawableFolderInBundle()
9182
: this.resourceIdentifierWithoutScale();
9283
} else {
93-
return this.isCatalogAsset()
94-
? this.assetFromCatalog()
95-
: this.scaledAssetURLNearBundle();
84+
return this.scaledAssetURLNearBundle();
9685
}
9786
}
9887

@@ -134,10 +123,6 @@ class AssetSourceResolver {
134123
);
135124
}
136125

137-
assetFromCatalog(): ResolvedAssetSource {
138-
return this.fromSource(getAndroidResourceIdentifier(this.asset));
139-
}
140-
141126
/**
142127
* The default location of assets bundled with the app, located by
143128
* resource identifier

packages/react-native/Libraries/Image/__tests__/resolveAssetSource-test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ describe('resolveAssetSource', () => {
136136
__packager_asset: true,
137137
width: 100,
138138
height: 200,
139-
uri: 'module_a_logo',
139+
uri: 'file:///Path/To/Sample.app/assets/module/a/logo.png',
140140
scale: 1,
141141
},
142142
);
@@ -159,7 +159,7 @@ describe('resolveAssetSource', () => {
159159
__packager_asset: true,
160160
width: 100,
161161
height: 200,
162-
uri: '__module_a_logo',
162+
uri: 'file:///Path/To/Sample.app/assets/__module/a/logo.png',
163163
scale: 1,
164164
},
165165
);

packages/react-native/React/Base/RCTUtils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ RCT_EXTERN NSString *__nullable RCTLibraryPath(void);
135135
// (or nil, if the URL does not specify a path within the Library directory)
136136
RCT_EXTERN NSString *__nullable RCTLibraryPathForURL(NSURL *__nullable URL);
137137

138+
// Return the name of the asset in the catalog for a packager URL.
139+
RCT_EXTERN NSString *__nullable RCTAssetCatalogNameForURL(NSURL *__nullable URL);
140+
138141
// Determines if a given image URL refers to a image in bundle
139142
RCT_EXTERN BOOL RCTIsBundleAssetURL(NSURL *__nullable imageURL);
140143

packages/react-native/React/Base/RCTUtils.m

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -728,13 +728,66 @@ BOOL RCTIsGzippedData(NSData *__nullable data)
728728
return RCTRelativePathForURL(RCTHomePath(), URL);
729729
}
730730

731-
static BOOL RCTIsImageAssetsPath(NSString *path)
731+
static NSRegularExpression *RCTAssetURLScaleRegex()
732+
{
733+
static dispatch_once_t onceToken;
734+
static NSRegularExpression *regex;
735+
dispatch_once(&onceToken, ^{
736+
regex = [NSRegularExpression regularExpressionWithPattern:@"@\\dx$" options:0 error:nil];
737+
});
738+
return regex;
739+
}
740+
741+
static NSRegularExpression *RCTAssetURLCharactersRegex()
742+
{
743+
static dispatch_once_t onceToken;
744+
static NSRegularExpression *regex;
745+
dispatch_once(&onceToken, ^{
746+
regex = [NSRegularExpression regularExpressionWithPattern:@"[^a-z0-9_]" options:0 error:nil];
747+
});
748+
return regex;
749+
}
750+
751+
NSString *__nullable RCTAssetCatalogNameForURL(NSURL *__nullable URL)
732752
{
733-
if (path == nil) {
734-
return NO;
753+
NSString *path = RCTBundlePathForURL(URL);
754+
// Packager assets always start with assets/
755+
if (path == nil || ![path hasPrefix:@"assets/"]) {
756+
return nil;
735757
}
758+
759+
// Remove extension
760+
path = [path stringByDeletingPathExtension];
761+
762+
// Remove scale suffix
763+
path = [RCTAssetURLScaleRegex() stringByReplacingMatchesInString:path
764+
options:0
765+
range:NSMakeRange(0, [path length])
766+
withTemplate:@""];
767+
768+
path = [path lowercaseString];
769+
770+
// Encode folder structure in file name
771+
path = [path stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
772+
773+
// Remove illegal chars
774+
path = [RCTAssetURLCharactersRegex() stringByReplacingMatchesInString:path
775+
options:0
776+
range:NSMakeRange(0, [path length])
777+
withTemplate:@""];
778+
779+
// Remove "assets_" prefix
780+
if ([path hasPrefix:@"assets_"]) {
781+
path = [path substringFromIndex:@"assets_".length];
782+
}
783+
784+
return path;
785+
}
786+
787+
static BOOL RCTIsImageAssetsPath(NSString *path)
788+
{
736789
NSString *extension = [path pathExtension];
737-
return extension.length == 0 || [extension isEqualToString:@"png"] || [extension isEqualToString:@"jpg"];
790+
return [extension isEqualToString:@"png"] || [extension isEqualToString:@"jpg"];
738791
}
739792

740793
BOOL RCTIsBundleAssetURL(NSURL *__nullable imageURL)
@@ -803,6 +856,17 @@ BOOL RCTIsLocalAssetURL(NSURL *__nullable imageURL)
803856

804857
UIImage *__nullable RCTImageFromLocalAssetURL(NSURL *imageURL)
805858
{
859+
NSString *catalogName = RCTAssetCatalogNameForURL(imageURL);
860+
if (catalogName) {
861+
UIImage *image = [UIImage imageNamed:catalogName];
862+
if (image) {
863+
return image;
864+
} else {
865+
RCTLogWarn(
866+
@"Image %@ not found in the asset catalog. Make sure your app template is updated correctly.", catalogName);
867+
}
868+
}
869+
806870
NSString *imageName = RCTBundlePathForURL(imageURL);
807871

808872
NSBundle *bundle = nil;
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"info" : {
3-
"version" : 1,
4-
"author" : "xcode"
3+
"author" : "xcode",
4+
"version" : 1
55
}
66
}

packages/rn-tester/RNTesterUnitTests/RCTURLUtilsTests.m

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,25 @@ - (void)testIsLocalAssetsURLParam
100100
XCTAssertFalse(RCTIsLocalAssetURL(otherAssetsURL));
101101
}
102102

103+
- (void)testAssetCatalogNameForURL
104+
{
105+
NSString *validAssetPath =
106+
[NSString stringWithFormat:@"file://%@/assets/AwesomeModule/icon@2x.png", [[NSBundle mainBundle] resourcePath]];
107+
NSString *result = RCTAssetCatalogNameForURL([NSURL URLWithString:validAssetPath]);
108+
XCTAssertEqualObjects(result, @"awesomemodule_icon");
109+
110+
NSString *validAssetNoScalePath =
111+
[NSString stringWithFormat:@"file://%@/assets/AwesomeModule/icon.png", [[NSBundle mainBundle] resourcePath]];
112+
result = RCTAssetCatalogNameForURL([NSURL URLWithString:validAssetNoScalePath]);
113+
XCTAssertEqualObjects(result, @"awesomemodule_icon");
114+
115+
NSString *notPackagerAssetPath =
116+
[NSString stringWithFormat:@"file://%@/icon.png", [[NSBundle mainBundle] resourcePath]];
117+
result = RCTAssetCatalogNameForURL([NSURL URLWithString:notPackagerAssetPath]);
118+
XCTAssertNil(result);
119+
120+
result = RCTAssetCatalogNameForURL(nil);
121+
XCTAssertNil(result);
122+
}
123+
103124
@end
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"info" : {
3-
"version" : 1,
4-
"author" : "xcode"
3+
"author" : "xcode",
4+
"version" : 1
55
}
66
}

0 commit comments

Comments
 (0)