Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use asset catalog for ios images #30129

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,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 @@ -152,6 +152,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 @@ -160,6 +164,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
}
}
6 changes: 5 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 @@ -79,6 +80,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 @@ -229,6 +231,7 @@
5C60EB1B226440DB0018C04F /* AppDelegate.mm */,
13B07FB71A68108700A75B9A /* main.m */,
2DDEF00F1F84BF7B00DBDF73 /* Images.xcassets */,
0CF641B528ECB21C00DCDD11 /* RNAssets.xcassets */,
8145AE05241172D900A3F8DA /* LaunchScreen.storyboard */,
680759612239798500290469 /* Fabric */,
272E6B3A1BEA846C001FCF37 /* NativeExampleViews */,
Expand Down Expand Up @@ -407,8 +410,8 @@
3B2555DA1E9C50DBD7DEDDC7 /* [CP] Check Pods Manifest.lock */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
68CD48B71D2BCB2C007E06A9 /* Build JS Bundle */,
13B07F8E1A680F5B00A75B9A /* Resources */,
79E8BE2B119D4C5CCD2F04B3 /* [RN] Copy Hermes Framework */,
4E5A5A192F46F13B14A915AF /* [CP] Embed Pods Frameworks */,
4E2AB2EE08A8E6F86E659152 /* [CP] Copy Pods Resources */,
Expand Down Expand Up @@ -507,6 +510,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0CF641B628ECB21C00DCDD11 /* RNAssets.xcassets in Resources */,
2DDEF0101F84BF7B00DBDF73 /* Images.xcassets in Resources */,
8145AE06241172D900A3F8DA /* LaunchScreen.storyboard in Resources */,
3D2AFAF51D646CF80089D1A3 /* legacy_image@2x.png 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/icon@2x.png", [[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
}
}