How do you require() a sound file in React Native? - react-native

I'm using https://github.com/zmxv/react-native-sound to play sounds on my iOS (and Android) app, and I'm trying to include sound files through React Native's asset system, but when I call:
var sound = require('./sound.mp3');
I get the error:
Unable to resolve module ./sound.mp3 from [project]/index.ios.js: Invalid directory [project]/sound.mp3
I have my MP3 file in the correct (root) directory of my project, the exact same file path that the error is printing. I've tried putting it in other directories as well.
According to this thread, it sounds like sound files should be able to be packaged using require() as well?
Just doing a test, requiring an image works perfectly:
var image = require('./image.png');

What worked for me was simply using the app name as root:
import myMP3File from '<appname>/assets/mymp3.mp3';
const Sound = require('react-native-sound');
Sound.setCategory('Playback');
// Do whatever you like with it.
Sound(myMP3File, () => console.log('soundfile loaded!'));
Edit:
We now use rn-fetch-blob and the following solution to access local files:
import RNFetchBlob from 'rn-fetch-blob';
const { fs } = RNFetchBlob;
filePathIos = `${fs.dirs.MainBundleDir}/yourFolder/yourMp3.mp3`;
filePathAndroid = fs.asset('yourFolder/yourMp3.mp3');
The corresponding path can then be used to copy the file using fs.cp().

The only thing that worked for us is to put the audio files we want to ship with the app in an assets directory and then have Xcode copy those files into the app bundle at build time. At that point, you can calculate the full path to the file using something like react-native-fs, and provide that to react-native-sound.

I had the same error message with managed Expo when trying to play a sound.ogg.
None of the trick I could find worked.
In the end, what solved it was to convert the ogg file to mp3, which is supported by Expo.

You need to use react-native-asset to put files to your project and access them with require keyword.
Example for file with path ./assets/audio/some-audio.mp3:
Add or modify react-native.config.js
module.exports = {
project: {
ios: {},
android: {},
},
dependencies: {
},
assets: [
'./assets/audio'
],
};
Run npx react-native-asset
Use the file:
const someAudio = require('./assets/audio/some-audio.mp3')

Related

how to add asset files to a React Native iOS project

I am currently working on getting a react-native project that is running on Android to work on iOS. The following code uses react-native-blob-util to load files from the following folder android/app/src/main/assets/. So if the function is called with path "/app.js" it will read the file at android/app/src/main/assets/webview/app.js
async function buildLocalAssetResponse(path: string): Promise<Buffer> {
let headers = 'HTTP/1.1 ';
const bundlePath = `webview${path}`;
let data = '';
console.log(bundlePath)
try {
data = await ReactNativeBlobUtil.fs.readFile(
ReactNativeBlobUtil.fs.asset(bundlePath),
'base64',
);
I am trying to figure out how to get this working on iOS exactly, I believe I have to copy the relevant files into an ios assets folder so ReactNativeBlobUtil.fs.asset can find them but I am not sure how to create that folder.

How to download assets/files(.JSON) and store them inside my app not directly on the user's phone in React Native Expo

am using React Native Expo and I was browsing the web to find a way to download assets, and files to my react native project and came across with this post How to Download image in react native
When the user clicks the download button I want assets/files to be downloaded and stored inside the app not directly on the user's phone. I mean I don't want the users to view the downloaded files or delete them manually.
I just want the downloaded assets/files to be accessible by the React Native app. Am doing this to make the app work offline.
Once the users downloaded the assets/files, the app can use the downloaded assets/files. How can I accomplish that?
Thank you in advance!
If you are using expo managed workflow, then rn-fetch-blob will not work for you.
In that case, Expo File System is probably your way to go.
Firstly, install expo-file-system. See this
Next, for saving files and not letting users delete them manually, store them inside the cache-directory like this
import * as FileSystem from 'expo-file-system';
const downloadAssets = async () => {
let name = "Samplefile.jpg";
const result = FileSystem.createDownloadResumable(
url_Of_the_File_You_Want_to_Download,
FileSystem.cacheDirectory + name
);
const response = await result.downloadAsync();
if (response.status === 200) {
// File successfully saved
} else {
// Some error
}
};
To access this file in your app simple execute this function
import * as FileSystem from 'expo-file-system';
const getFiles = async () => {
const CacheDir = await FileSystem.readDirectoryAsync(
FileSystem.cacheDirectory
);
console.log(CacheDir); //Files are stored here
};

how to access xml static resource in react native

I want to add a static xml asset to my react native project and access it just like accessing images.
I added
resolver: {
assetExts: ['png', 'xml'],
},
to metro.config.js and const asset = require('asset.xml') returns me a number. But how to get the file content from this number?
Below code gets me a URI in development mode that I can use axios to fetch it, but in release mode it only returns a filename like asset, how to read it in release mode?
Image.resolveAssetSource(asset).uri;
You can use expo-asset to get the localUri:
const [{ localUri }] = await Asset.loadAsync(require('path/to/your/asset.xml'))
Then you can use expo-file-system to get the contents of the file as string:
const xmlString = FileSystem.readAsStringAsync(localUri)
Then you can convert the xml string to a JS object with a package like fast-xml-parser.
In order for this to work, you should edit your metro.config.js just as you mentioned above, namely: assetExts array should contain xml.
Also, if you use Typescript, you should add a declaration file, like xml.d.ts with the content of:
declare module '*.xml' {
const moduleId: number; // the react-native import reference
export default moduleId;
}
and that declaration file should be in a folder, that's added to typeRoots property in tsconfig.json.
Just a quick reminder: you can use this solution without Expo in a bare react-native app, you just have to install unimodules, which is described in the above links.
Good luck! :)

React Native RNFS delete file from download directory

I'm trying to delete some files from the Android Download Directory.
I got the android permission to the external storage to do it, so this is my code :
var RNFS = require('react-native-fs');
...
await RNFS.exists(filepath).then((exists) => {
if (exists) {
RNFS.unlink(filepath).then(() => {
RNFS.scanFile(filepath);
})
}
});
The unlink function works perfectly when I add some log in it. It doesn't catch(), but when I launch the same script again, the unlink still works while the file must be deleted, how is it possible ??
I don't understand what I have to do to completely delete these files...
EDIT :
I've checked the react-native-fs and it says :
Android support is currently limited to only the DocumentDirectory. This maps to the app's files directory.
So how can I delete files in the Download directory ?

How to get files in main directory in a react native project?

I am trying to get file names in main directory of my react native project. I have used "react-native-fs" to do it.
Here is my code;
const getFileNames = () => {
const path = FS.DocumentDirectoryPath;
console.log(path);
};
And it doesn't give me App.js, index.js, ... It gives me this result;
/data/user/0/com.mrkennedy/files
Versions;
"react-native": "0.62.2",
"react-native-fs": "^2.16.6"
You've just got path, to read the dir's content use readDir: https://github.com/itinance/react-native-fs#readdirdirpath-string-promisereaddiritem which will return you array of objects, each describing file. See this example: https://github.com/itinance/react-native-fs#basic.
Moreover, you won't access App.js etc. using DocumentDirectoryPath, document directory is not equivalent to your project's root directory. I don't think it's possible to access project's root without special configuration as package server bundles all JavaScript files into single file.