Skip to content

Commit

Permalink
Use asset catalog for ios images
Browse files Browse the repository at this point in the history
  • Loading branch information
janicduplessis committed Nov 22, 2023
1 parent 27c5b3a commit 6f971b9
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ package-lock.json
!/packages/rn-tester/Pods/__offline_mirrors_hermes__
!/packages/rn-tester/Pods/__offline_mirrors_jsc__

# Generated asset catalog
/packages/rn-tester/RNTester/RNAssets.xcassets/*.imageset

# @react-native/codegen
/packages/react-native/React/FBReactNativeSpec/FBReactNativeSpec
/packages/react-native-codegen/lib
Expand Down
3 changes: 3 additions & 0 deletions packages/react-native/React/Base/RCTUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ RCT_EXTERN NSString *__nullable RCTLibraryPath(void);
// (or nil, if the URL does not specify a path within the Library directory)
RCT_EXTERN NSString *__nullable RCTLibraryPathForURL(NSURL *__nullable URL);

// Return the name of the asset in the catalog for a packager URL.
RCT_EXTERN NSString *__nullable RCTAssetCatalogNameForURL(NSURL *__nullable URL);

// Determines if a given image URL refers to a image in bundle
RCT_EXTERN BOOL RCTIsBundleAssetURL(NSURL *__nullable imageURL);

Expand Down
67 changes: 67 additions & 0 deletions packages/react-native/React/Base/RCTUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,62 @@ BOOL RCTIsGzippedData(NSData *__nullable data)
return RCTRelativePathForURL(RCTHomePath(), URL);
}

static NSRegularExpression *RCTAssetURLScaleRegex()
{
static dispatch_once_t onceToken;
static NSRegularExpression *regex;
dispatch_once(&onceToken, ^{
regex = [NSRegularExpression regularExpressionWithPattern:@"@\\dx$" options:0 error:nil];
});
return regex;
}

static NSRegularExpression *RCTAssetURLCharactersRegex()
{
static dispatch_once_t onceToken;
static NSRegularExpression *regex;
dispatch_once(&onceToken, ^{
regex = [NSRegularExpression regularExpressionWithPattern:@"[^a-z0-9_]" options:0 error:nil];
});
return regex;
}

NSString *__nullable RCTAssetCatalogNameForURL(NSURL *__nullable URL)
{
NSString *path = RCTBundlePathForURL(URL);
// Packager assets always start with assets/
if (path == nil || ![path hasPrefix:@"assets/"]) {
return nil;
}

// Remove extension
path = [path stringByDeletingPathExtension];

// Remove scale suffix
path = [RCTAssetURLScaleRegex() stringByReplacingMatchesInString:path
options:0
range:NSMakeRange(0, [path length])
withTemplate:@""];

path = [path lowercaseString];

// Encode folder structure in file name
path = [path stringByReplacingOccurrencesOfString:@"/" withString:@"_"];

// Remove illegal chars
path = [RCTAssetURLCharactersRegex() stringByReplacingMatchesInString:path
options:0
range:NSMakeRange(0, [path length])
withTemplate:@""];

// Remove "assets_" prefix
if ([path hasPrefix:@"assets_"]) {
path = [path substringFromIndex:@"assets_".length];
}

return path;
}

static BOOL RCTIsImageAssetsPath(NSString *path)
{
NSString *extension = [path pathExtension];
Expand Down Expand Up @@ -800,6 +856,17 @@ BOOL RCTIsLocalAssetURL(NSURL *__nullable imageURL)

UIImage *__nullable RCTImageFromLocalAssetURL(NSURL *imageURL)
{
NSString *catalogName = RCTAssetCatalogNameForURL(imageURL);
if (catalogName) {
UIImage *image = [UIImage imageNamed:catalogName];
if (image) {
return image;
} else {
RCTLogWarn(
@"Image %@ not found in the asset catalog. Make sure your app template is updated correctly.", catalogName);
}
}

NSString *imageName = RCTBundlePathForURL(imageURL);

NSBundle *bundle = nil;
Expand Down
5 changes: 5 additions & 0 deletions packages/react-native/scripts/react-native-xcode.sh
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ if [[ $USE_HERMES != false && $DEV == false ]]; then
EXTRA_ARGS="$EXTRA_ARGS --minify false"
fi

# PRODUCT_SETTINGS_PATH is where the target Info.plist file is. The asset
# catalog will be in the same folder.
ASSET_CATALOG_DEST=${ASSET_CATALOG_DEST:-"$(dirname "$PRODUCT_SETTINGS_PATH")"}

"$NODE_BINARY" $NODE_ARGS "$CLI_PATH" $BUNDLE_COMMAND \
$CONFIG_ARG \
--entry-file "$ENTRY_FILE" \
Expand All @@ -147,6 +151,7 @@ fi
--reset-cache \
--bundle-output "$BUNDLE_FILE" \
--assets-dest "$DEST" \
--asset-catalog-dest "$ASSET_CATALOG_DEST" \
$EXTRA_ARGS \
$EXTRA_PACKAGER_ARGS

Expand Down
3 changes: 3 additions & 0 deletions packages/react-native/template/_gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,6 @@ yarn-error.log

# testing
/coverage

# Generated asset catalog
**/RNAssets.xcassets/*.imageset
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
00E356F31AD99517003FC87E /* HelloWorldTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* HelloWorldTests.m */; };
0C80B921A6F3F58F76C31292 /* libPods-HelloWorld.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-HelloWorld.a */; };
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
0C49AA4A252E5346004CE48B /* RNAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0C49AA49252E5346004CE48B /* RNAssets.xcassets */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
7699B88040F8A987B510C191 /* libPods-HelloWorld-HelloWorldTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-HelloWorld-HelloWorldTests.a */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
Expand All @@ -30,6 +31,7 @@
00E356EE1AD99517003FC87E /* HelloWorldTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HelloWorldTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
00E356F21AD99517003FC87E /* HelloWorldTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HelloWorldTests.m; sourceTree = "<group>"; };
0C49AA49252E5346004CE48B /* RNAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = RNAssets.xcassets; path = HelloWorld/RNAssets.xcassets; sourceTree = "<group>"; };
13B07F961A680F5B00A75B9A /* HelloWorld.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloWorld.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = HelloWorld/AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = HelloWorld/AppDelegate.mm; sourceTree = "<group>"; };
Expand Down Expand Up @@ -89,6 +91,7 @@
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
13B07FB01A68108700A75B9A /* AppDelegate.mm */,
13B07FB51A68108700A75B9A /* Images.xcassets */,
0C49AA49252E5346004CE48B /* RNAssets.xcassets */,
13B07FB61A68108700A75B9A /* Info.plist */,
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,
13B07FB71A68108700A75B9A /* main.m */,
Expand Down Expand Up @@ -179,8 +182,8 @@
C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
13B07F8E1A680F5B00A75B9A /* Resources */,
00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */,
E235C05ADACE081382539298 /* [CP] Copy Pods Resources */,
);
Expand Down Expand Up @@ -242,6 +245,7 @@
buildActionMask = 2147483647;
files = (
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
0C49AA4A252E5346004CE48B /* RNAssets.xcassets in Resources */,
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
6 changes: 6 additions & 0 deletions packages/rn-tester/RNTester/RNAssets.xcassets/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
7 changes: 6 additions & 1 deletion packages/rn-tester/RNTesterPods.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

/* Begin PBXBuildFile section */
04157F50C11E9F16DDD69B17 /* libPods-RNTester.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F98312BF816A7F2688C036D /* libPods-RNTester.a */; };
0CF641B628ECB21C00DCDD11 /* RNAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0CF641B528ECB21C00DCDD11 /* RNAssets.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
2DDEF0101F84BF7B00DBDF73 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2DDEF00F1F84BF7B00DBDF73 /* Images.xcassets */; };
383889DA23A7398900D06C3E /* RCTConvert_UIColorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 383889D923A7398900D06C3E /* RCTConvert_UIColorTests.m */; };
Expand Down Expand Up @@ -78,6 +79,7 @@

/* Begin PBXFileReference section */
0CC3BE1A25DDB68A0033CAEB /* RNTester.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = RNTester.entitlements; path = RNTester/RNTester.entitlements; sourceTree = "<group>"; };
0CF641B528ECB21C00DCDD11 /* RNAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = RNAssets.xcassets; path = RNTester/RNAssets.xcassets; sourceTree = "<group>"; };
13B07F961A680F5B00A75B9A /* RNTester.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RNTester.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = RNTester/AppDelegate.h; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = RNTester/Info.plist; sourceTree = "<group>"; };
Expand Down Expand Up @@ -218,6 +220,7 @@
13B07FB71A68108700A75B9A /* main.m */,
832F45BA2A8A6E1F0097B4E6 /* SwiftTest.swift */,
2DDEF00F1F84BF7B00DBDF73 /* Images.xcassets */,
0CF641B528ECB21C00DCDD11 /* RNAssets.xcassets */,
8145AE05241172D900A3F8DA /* LaunchScreen.storyboard */,
680759612239798500290469 /* Fabric */,
272E6B3A1BEA846C001FCF37 /* NativeExampleViews */,
Expand Down Expand Up @@ -377,8 +380,9 @@
3B2555DA1E9C50DBD7DEDDC7 /* [CP] Check Pods Manifest.lock */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
68CD48B71D2BCB2C007E06A9 /* Build JS Bundle */,
5CF0FD27207FC6EC00C13D65 /* Start Metro */,
13B07F8E1A680F5B00A75B9A /* Resources */,
79E8BE2B119D4C5CCD2F04B3 /* [RN] Copy Hermes Framework */,
4E5A5A192F46F13B14A915AF /* [CP] Embed Pods Frameworks */,
4E2AB2EE08A8E6F86E659152 /* [CP] Copy Pods Resources */,
Expand Down Expand Up @@ -480,6 +484,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0CF641B628ECB21C00DCDD11 /* RNAssets.xcassets in Resources */,
2DDEF0101F84BF7B00DBDF73 /* Images.xcassets in Resources */,
8145AE06241172D900A3F8DA /* LaunchScreen.storyboard in Resources */,
3D2AFAF51D646CF80089D1A3 /* [email protected] in Resources */,
Expand Down
21 changes: 21 additions & 0 deletions packages/rn-tester/RNTesterUnitTests/RCTURLUtilsTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,25 @@ - (void)testIsLocalAssetsURLParam
XCTAssertFalse(RCTIsLocalAssetURL(otherAssetsURL));
}

- (void)testAssetCatalogNameForURL
{
NSString *validAssetPath =
[NSString stringWithFormat:@"file://%@/assets/AwesomeModule/[email protected]", [[NSBundle mainBundle] resourcePath]];
NSString *result = RCTAssetCatalogNameForURL([NSURL URLWithString:validAssetPath]);
XCTAssertEqualObjects(result, @"awesomemodule_icon");

NSString *validAssetNoScalePath =
[NSString stringWithFormat:@"file://%@/assets/AwesomeModule/icon.png", [[NSBundle mainBundle] resourcePath]];
result = RCTAssetCatalogNameForURL([NSURL URLWithString:validAssetNoScalePath]);
XCTAssertEqualObjects(result, @"awesomemodule_icon");

NSString *notPackagerAssetPath =
[NSString stringWithFormat:@"file://%@/icon.png", [[NSBundle mainBundle] resourcePath]];
result = RCTAssetCatalogNameForURL([NSURL URLWithString:notPackagerAssetPath]);
XCTAssertNil(result);

result = RCTAssetCatalogNameForURL(nil);
XCTAssertNil(result);
}

@end
6 changes: 6 additions & 0 deletions template/ios/HelloWorld/RNAssets.xcassets/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

0 comments on commit 6f971b9

Please sign in to comment.