Reputation: 781
I have a png that is being accessed in my React Native Project via in Image Component:
// app.js
<Image source={require('./images/bird.png')} />
Now I want to access bird.png in my Native iOS Module without importing it via Xcode (The React Native Packager should add this to the build, so I should have access to it). I need to create a UIImage specifically for this Native Module.
// MYNativeModule.m
RCT_EXPORT_METHOD(doSomething) {
UIImage *birdImage = [UIImage imageNamed:@"bird.png"];
}
Unfortunately, this doesn't work. Does anyone know how to access bird.png from the React Native package?
UPDATE: Artal's answer is the correct answer. In the meantime, I found an alternative solution that did the job, though isn't as useful for my specific question (though it still may be useful in the case where you want to access a React Native Packaged asset WITHOUT having to go over the bridge). First I'll show how I incorporated it using the bridge:
// app.js
NativeModules.MYNativeModule.doSomething("assets/app/images/bird.png")
The code above lets you put in a file path. You can find the path of your React Native Packaged asset by building your project in Xcode, and in the navigator on the left, right click on Products > YourApp.app
Then click 'Show in Finder'. Then right-click YourApp.app (the extension may be hidden), and click 'Show Package Contents'. From here, you can see the directory layout that the package created. It'll probably mimic your app's layout. I think it was created like this so that you can have multiple files with the same name, but in different directories (by default, I believe Xcode puts all assets at the root level when you create a build. That's why you can't have multiple assets with the same name in an Xcode project). Then your bridge's module can work as below.
// MYNativeModule.m file
RCT_EXPORT_METHOD(doSomething: (NSString *) imagePath) {
NSString *bundlePath = [[NSBundle mainBundle] resourcePath];
NSString *path = [NSString stringWithFormat:@"%@/%@", bundlePath, imagePath];
UIImage *img = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL fileURLWithPath:path]]];
}
The advantage to this method is that you can do this without a bridge if you know the path ahead of time. The negative is that you need to know the path. If the path isn't know ahead of time, then this won't work.
Upvotes: 2
Views: 3280
Reputation: 9143
This doesn't work because you can't access the images directly unless they are added to your Xcode project. To use the same images on the native side you will need to pass it to your native module in a way that it can be sent over the bridge and then convert it back to a UIImage
.
A required image is just an id to an asset mapped in your bundle, you first need to resolve the asset on the JS side and pass it to the native module method:
const resolveAssetSource = require('react-native/Libraries/Image/resolveAssetSource');
const birdImage = require('./images/bird.png');
NativeModules.MYNativeModule.doSomething(resolveAssetSource(birdImage));
On the native side you get a json object with the image info that can now be converted:
#import <React/RCTConvert.h>
RCT_EXPORT_METHOD(doSomething:(id)image) {
UIImage *birdImage = [RCTConvert UIImage:image];
}
Upvotes: 5