Use require('../assets/file.mp3') in ES6 - react-native

I am trying to load a local mp3 file to be played using Expo Audio SDK.
Here's an example from the documentation:
const soundObject = new Audio.Sound();
try {
await soundObject.loadAsync(require('./assets/sounds/hello.mp3'));
await soundObject.playAsync();
// Your sound is playing!
} catch (error) {
// An error occurred!
}
I am also using ES6 in my project which makes require unavailable.
Is there any way I could still load a local resource in ES6?

As far as I know, require is still a thing in ES6. I've used it plenty of times throughout my apps. The example should work, have you tried it?

Related

Expo API for app updates resulting in blank white screen

I’m using Expo in the managed workflow. The app is coming along and I’ve added the ability for the app to auto-update itself. I’m using the expo-updates library: https://docs.expo.dev/versions/latest/sdk/updates and the implementation is pretty straightforward.
When our app is opened, our app’s App.tsx runs Updates.checkForUpdateAsync() and then Updates.reloadAsync(). We throw up a brief spinner and 9 out of 10 times the update works just fine. But about 1 out of 10 times the app screen goes white. The iOS header bar with time and Wi-Fi is still visible, but everything else is white. The user has to kill the app and re-open it to resume and now they’re running the latest version.
Unfortunately, this is a difficult issue to reproduce. We can’t do updates in development so we are trying to debug this in our staging environment (a mirror of production). Our repro steps are to push a trivial update to Expo, when the build completes, relaunch the app. We have to do it about ~10 times before we’ll get a freeze case.
The key code is: App.tsx runs:
newUpdate = await checkForAppUpdate()
If (newUpdate) await forceUpdate()
And then our library for these two methods is simple:
import * as Updates from 'expo-updates'
import {Platform} from "react-native"
export const checkForAppUpdate = async (): Promise<boolean> => {
if (Platform.OS == "web" || __DEV__) return false
try {
const update = await Updates.checkForUpdateAsync()
return update.isAvailable
} catch (e) {
console.error(e)
return false
}
}
export const forceUpdate = async () => {
try {
const result = await Updates.fetchUpdateAsync()
if (result.isNew) {
await Updates.reloadAsync()
}
} catch (e) {
console.error(e)
}
}
I’m at a loss for how to debug this. Any clues as to what might be going on? I’m assuming a race condition given the sporadic behavior but I’m stuck.
I ended up figuring this out, but it was tricky. I added all sorts of additional logging to try and catch any exception being thrown and there was not one. The issue is that I had a new dependency in my Expo build/bundle which was not yet supported by the binary version of my app I was running. I rebuilt my binary with the latest libraries and this started working again.
So anyone else who might be faced with this issue: do an audit of all library dependencies with your app and roll back to a previous version when updating was working to isolate what changed.

Playing an audio file with source => {uri: 'remote-file-path'} not working - React Native (expo)

I keep getting this error when i try to play an audio from my local backend or an already uploaded audio from a site.
No matter what file format, this is what I get and this only happens with ios
error: Possible Unhandled Promise Rejection (id: 0): Error: The server is not correctly configured. - The AVPlayerItem instance has failed with the error code -11850 and domain "AVFoundationErrorDomain". Error: The server is not correctly configured. - The AVPlayerItem instance has failed with the error code -11850 and domain "AVFoundationErrorDomain".
error image
const player = new Audio.Sound();
player.loadAsync({ uri: url }, initialStatus).then(() => {
player.playAsync().then((playbackStatus) => {
if (playbackStatus.error) {
handlePlaybackError(playbackStatus.error);
}
});
});
After adding more error handling, I found out the error comes from loadAsync and it only happens when I try to play an audio from my local backend server. (ex: http://127.0.0.1:8000/media/audios/2021/08/08/27/21/filename.mp4)
It would be really great if I could get help on this, thanks in advance!
Update: Provided more code
So I found out that the that warning was being generated and preventing my audio files from playing because they are stored in my local server and for some reason the expo Audio.Sound object had an issue loading them, so I had to install expo-file-system, use the FileSystem to read download the file and use the uri produced from the download.
Example:
import * as FileSystem from 'expo-file-system';
const splitUrl = url.split('/');
const lastItem = splitUrl[splitUrl.length - 1];
const { uri } = await FileSystem.downloadAsync(
url,
FileSystem.documentDirectory + lastItem
);
const source = { uri: uri }; //the source you provide to the loadAsync() method
loadAsync() returns a Promise, so you have to await it.
If this is not the problem you have to provide more code, please.
Here's the documentation, so use it like this:
const sound = new Audio.Sound();
try {
await sound.loadAsync(require('./assets/sounds/hello.mp3'));
await sound.playAsync();
// Your sound is playing!
// Don't forget to unload the sound from memory
// when you are done using the Sound object
await sound.unloadAsync();
} catch (error) {
// An error occurred!
}
And here's a simple snack I made, it works for me, you might want to consider error handling using try-catch:
Snack example

Expo secure-store unavailable in jest tests

This question is specifically about expo-secure-store and jest.
Currently, I am using expo-secure-store to store my JWT when logging in. It works fine when running on emulator however, it doesn't work at all in Jest tests; token comes back as undefined. I am able to call the functions like normal.
Excuse any typos I might have made refactoring this.
Calling from tests:
test('when logging in, given correct credentials, gets response token.', async () => {
try {
var token = await SecureStore.getItemAsync("token");
await SecureStore.setItemAsync('token', 'test');
token = await SecureStore.getItemAsync('token');
console.log(token);
expect(token).toBeDefined();
expect(token).toBe("test");
} catch (err) {
console.log(err);
throw err;
}
}
Question: Does expo-secure-store not load/work without an actual device/emulator?
There are no documentation at all about testing with secure-store and from what I can tell I might have to mock this module.
you have to mock any native module that you use because their implementations live primarily in native code that is intended to be run on ios and android devices. so the same applies here - you should mock expo-secure-store.

React native custom internet phone call

I have a 3 part question from important to less important:
Does someone know if there is a package to do phone calls trough the internet as Whatsapp and Facebook do?
Would it even be possible to do it without a phone number?
For example, only knowing someone's device id.
And can you even make your "ring page" custom? So adding functionalities while calling.
Thank you in advance!
Yes this is possible. There are plenty of ways to attack this but I would recommend using a React Native wrapper for Twilio (https://github.com/hoxfon/react-native-twilio-programmable-voice).
import TwilioVoice from 'react-native-twilio-programmable-voice'
// ...
// initialize the Programmable Voice SDK passing an access token obtained from the server.
// Listen to deviceReady and deviceNotReady events to see whether the initialization succeeded.
async function initTelephony() {
try {
const accessToken = await getAccessTokenFromServer()
const success = await TwilioVoice.initWithToken(accessToken)
} catch (err) {
console.err(err)
}
}
// iOS Only
function initTelephonyWithUrl(url) {
TwilioVoice.initWithTokenUrl(url)
try {
TwilioVoice.configureCallKit({
appName: 'TwilioVoiceExample', // Required param
imageName: 'my_image_name_in_bundle', // OPTIONAL
ringtoneSound: 'my_ringtone_sound_filename_in_bundle' // OPTIONAL
})
} catch (err) {
console.err(err)
}
For that approach I believe you have to have a phone number but you can build out the ui however you like.
If you are not into the Twilio approach, you can use pure JS libraries to do the trick such as SipJS.
There are also tutorials on Youtube which can lead you through the process like this.
I recommend you Voximplant, https://voximplant.com/docs/references/articles/quickstart,
it's easy to use and has clear documentation.

AsyncStorage is not returning the callback

I am using redux-persist in a react native project, that runs just fine in a broad number of devices except Android 7. I am trying to debug the problem on why my local storage is nor persisting and found this:
The following code executes inside React Native component lifecycle's
componentDidMount() {
attachObservables(store)
setInterval(async () => {
console.log('Inside setInterval')
const data = await AsyncStorage.getAllKeys()
console.log('inside the getAllKeys')
data.forEach(async k => {
const value = await AsyncStorage.getItem(k)
console.group(k)
console.log(value)
console.groupEnd()
})
}, 3000)
}
Code after 'Inside setInterval' is never called. It only runs once if outside the setInterval. If I call once the code outside the setInterval it appears to run just fine. I also tried callback format vs async / await version but it does not seem to matter.
Same problem I had using firebase js library (callbacks never return after the first one). I am now looking for alternatives to workaround the problem.
Any ideas?
As of React Native 0.51 in some Android versions, the runtime can get blocked by other native modules, impeding the resolution of the mentioned methods.
It can be fixed via https://github.com/facebook/react-native/issues/14101#issuecomment-345563563, ensuring this methods use a free thread from the thread pool.
A PR has been submitted and I hope that will be released in future versions. If you want it to use this fix right now, it is available here https://github.com/netbeast/react-native
EDIT:
I am not experiencing this anymore on real devices over react-native#0.53, anyhow others have also reported, so the issue is still open.