Get file path for image in main bundle in react-native - react-native

So I'm trying to find what the actual path to an image in my assets folder is during runtime.
I've used react-native-fs to get to the main bundle and can see my assets folder, but not sure how to actually get the path to the image inside the folder.
RNFS.readdir(RNFS.MainBundlePath + '/assets').then(response => {
// console.log(response)
})
• Is this something that's possible in react-native?
• I saw that Expo has an Assets package which makes this simple, but I'm not using Expo.
Thanks!

Related

Expo/React Native: Can't find image file after ejecting to bare workflow

I have an Expo project with an <Image /> component sourced from an import:
import logoImage from './assets/logo-medium.png';
...
<Image source={logoImage} />
This works fine on my device when building with expo run:ios -d. However, when I build the project with XCode, the image isn't there, and I see this error:
[native] Could not find image file:///Users/username/Library/Developer/CoreSimulator/Devices/B76D59AF-9599-4174-991B-AE484575B79C/data/Containers/Data/Application/A57C6E10-3DF9-46E0-8B56-7760AF5199C6/Library/Application%20Support/.expo-internal/assets/assets/logo-medium.png
When I try to find that file manually, there is no ...Application Support/.expo-internal directory.
Is there a different way I should be specifying image location? Or a way for the image to be correctly bundled when building from XCode?
I had the same issue, make sure about two things:
One of the potential solutions found on the web -
https://forums.expo.dev/t/assets-missing-only-in-ios-release-build-after-ejecting/42759
Ok I found out the problem.
When ejecting, expo is supposed to generate a metro.config.js file that looks like that:
module.exports = {
transformer: {
assetPlugins: ['expo-asset/tools/hashAssetFiles']
}
};
Your metro.config.js file shuld has .js extensions not .ts

Load Text file in react native locally

I am creating an application using react native expo cli, my application contains a lot of data which is in the text file.
So now i need to load the text file into my application. how can i do that?
After dig down a lot regarding this issue i manage to answer my own question.
To read text file in react-native we have to create bare react-native project.
Read this link about manage and bare project for react-native : expo-managed-vs-bare.
After eject expo project or creating bare react-native project you can use library react-native-fs, which have ability to read text file and display in Text component.
For Android,
Create an assets Folder inside your-project-file\android\app\src\main
To read this folder assets use this snippet,
import * as RNFS from 'react-native-fs';
RNFS.readFileAssets(path to your file inside assets folder).then(result => {
console.log(result);
}).catch(err => {
console.log(err);
});
This will help to read text file inside your project for android only.
As #james Liu,the simplest way is to organize your data as json an load it like this:
const data = require("./mydata.json");
By doing this you get an JS object you can easily handle in your code

How can I make react-native build copy an asset from node_modules to the apk?

I am building a react-native app which embeds a WebView in order to host some non-native react components. I have a small html file which is the source for the WebView and lives in a sub-folder of android/app/src/main/assets, which I understand is where it needs to be for the build to copy it to the apk, though I think I will need another copy in another location for IOS. So far so good...this much works.
Now, the htm file needs to pull in the regular react components from code in an npm module. It contains a script tag whose src needs to reference a file which is available in a subdirectory of node_modules. I don't know of any url I can put in the src that will reference the file direct from node_modules and get it copied to the apk. The simple solution is to manually copy the file into the same subfolder of android/app/src/main/assets and simply use its name as the src. This also works, though there may be a better way.
Problem: how can I automate copying the file from node_modules to assets?
(Ideally, a solution would also work for IOS, though at this point I'd be glad to have an android-only one.)
I explored rnpm and react-native link. Documentation I can find is very inadequate, but it appears this mechanism can only be used for fonts.
I explored adding a copy command to the start script in package.json, like this:
"scripts": {
"start": "copy/Y node_modules/X/Ybundle.js android/app/src/main/assets/X/Ybundle.js & node node_modules/react-native/local-cli/cli.js start"
},
but the copy did not happen when I ran react-native start-android.
I am wondering whether something could be added to the react-native project's gradle script, but cannot find any documentation on how this is used in the react native build process.
The best solution I've found so far is to add some scripts to package.json:
"scripts": {
"copyAssets": "node -e \"fs.copyFileSync('./node_modules/bloom-player-react/output/bloomPlayerControlBundle.js','./android/app/src/main/assets/bloom-player/bloomPlayerControlBundle.js')\"",
"start-android": "npm run copyAssets && react-native run-android",
...
}
Then when I npm run start-android, first the copy happens, and then the normal android startup.
I answered very same question in here with same answer: https://stackoverflow.com/a/72191579/7376041
For Android, you can run a custom Gradle task that able to will handle copy your assets in build time.
Create a Gradle file in your module's root, like below:
(I presume your module name is react-native-my-awesome-module and your HTML files is under www folder in module's root.)
awesome.gradle:
/**
* Register HTML asset source folder
*/
android.sourceSets.main.assets.srcDirs += file("$buildDir/intermediates/ReactNativeMyAwesomeModule")
/**
* Task to copy HTML files
*/
afterEvaluate {
def targetDir = "../../node_modules/react-native-my-awesome-module/www";
def fileNames = [ "*.html" ];
def htmlCopyTask = tasks.create(
name: "copyReactNativeMyAwesomeModuleAssets",
type: Copy) {
description = "copy react native my awesome module assets."
into "$buildDir/intermediates/ReactNativeMyAwesomeModule/www"
fileNames.each { fileName ->
from(targetDir) {
include(fileName)
}
}
}
android.applicationVariants.all { def variant ->
def targetName = variant.name.capitalize()
def generateAssetsTask = tasks.findByName("generate${targetName}Assets")
generateAssetsTask.dependsOn(htmlCopyTask)
}
}
After installing the module, put the below line in your project's android/app/build.gradle file:
apply from: file("../../node_modules/react-native-my-awesome-module/awesome.gradle");
When you build your app, your assets under www folder will be copied from your module. You can access your resources in your app like below :
<WebView
source={{uri: 'file:///android_asset/www/index.html'}}
/>

lack of files after generating APK

I am building an app , my app contains a folder called content that folder contains a menu.html file that is calling some js, css files
content (size 5 MG)
menu.html
css
js
images
my problem is that after having generated my apk , installed it on my mobile
it displays first screen , when i click to move to next screen (the screen that is calling menu.html) here it sucks , i get a simple empty screen !
my question should I import manually this content folder to my android assets folder ? should I remove the 2 existing files in assets index.android.bundle and index.android.bundle.meta ?
You could try linking it. Since rnpm is part of RN you don't need to install anything, just add an entry in your package.json
"rnpm": {
"assets": [
"./path/to/file.html"
]
}
and then run react-native link
If you're already using rnpm you can add another path separated by a comma to that assets array. I don't know for certain but I would imagine the react-native is going to by default ignore HTML files unless they are explicitly linked.
You could also manually store the file in your Android assets folder and require it from there, but this won't work for iOS so if you're going cross platform I would try to get it to work via link.
Also as a side note, WebView kind of sucks. For a better user experience I would suggest rewriting the contents of that file in a way that react-native can render them.

Link non-font assets using rnpm

There are plenty of tutorials on including font assets using rnpm. These are the steps:
Put fonts in, say, ./assets/fonts
Add the following snippet to package.json:
"rnpm": {
"assets": [
"./assets/fonts",
]
}
run react-native link.
Works well for font assets, but what about other types? I need to include a text file, but repeating the above steps for text file assets does not seem to have any effect. What am I missing? There are no mentions on the internet, so I'm not even sure this is possible at all with rnpm.
EDIT: To be more specific, I added a file.txt to the ./assets/raw directory and added ./assets/raw next to ./assets/fonts in the rnpm config in package.json. After running react-native link I expected file.txt to appear in the Android project assets directory (/android/app/src/main/assets), and in the "Copy Bundle Resources" build phase in iOS project, but it didn't happen. react-native link ran normally and produced no errors.
My ultimate goal is to include a text file in the app bundle and have it accessible at runtime. Another option would be to wrap the text in JSON, but that way it ends up in JS bundle increasing its size by ~25%, which is probably not good. Some also recommend react-native-fs to read the file, but I'm not sure where to put it so that it's available for both Android and iOS. rnpm knows where to put assets for Android and iOS (and how to copy them to bundle), so using it seems to be the way to go, but I can't make it work with text assets.
Any thoughts or suggestions?
After digging around in the React Native CLI I found out that react-native link, handles only fonts. Here's the relevant piece of code from /node_modules/react-native/local-cli/link/android/copyAssets.js:
/**
* Copies each file from an array of assets provided to targetPath directory
*
* For now, the only types of files that are handled are:
* - Fonts (otf, ttf) - copied to targetPath/fonts under original name
*/
module.exports = function copyAssetsAndroid(files, targetPath) {
const assets = groupFilesByType(files);
(assets.font || []).forEach(asset =>
fs.copySync(asset, path.join(targetPath, 'fonts', path.basename(asset)))
);
};
As you can see, groupFilesByType groups all files by their MIME type (font, text, etc.), but then only fonts are actually copied to the project.
Others ran into this issue before. There was a pull request adding support for video assets, but it was not merged. Apparently the way to go is to use packager.