[bug][ios] event listener doesn't trigger
youniaogu opened this issue · 2 comments
my case is use volume up/down event to control flatlist scroll prev/next, so i make a useVolumeUpDown
hook based on addVolumeListener
and my problem is if the app get in background and switch to other app(i reproduce by use youtube), play video and back to app, the listener will never trigger
so is the volume listener have conflict with other app listener?
- ios: 15.4.1
- react-native: 0.72.5
- react-native-volume-manager: 1.10.0
below is my code and use case:
import { useCallback, useRef, useState } from 'react';
import { useFocusEffect } from '@react-navigation/native';
import { VolumeManager } from 'react-native-volume-manager';
import { Volume } from '~/utils';
export const useVolumeUpDown = (callback: (type: Volume) => void) => {
const volumeRef = useRef<number>();
const [initVolume, setInitVolume] = useState<number>();
const init = useCallback(() => {
VolumeManager.getVolume().then((volume) => {
let prev = typeof volume === 'number' ? volume : volume.volume;
volumeRef.current = prev;
if (prev <= 0) {
prev = 0.025;
} else if (prev >= 1) {
prev = 0.975;
}
VolumeManager.setVolume(prev);
setInitVolume(prev);
});
}, []);
const listener = useCallback(() => {
if (typeof initVolume !== 'number') {
return;
}
VolumeManager.showNativeVolumeUI({ enabled: false });
const volumeListener = VolumeManager.addVolumeListener((result) => {
if (result.volume - initVolume > 0.0001) {
setTimeout(
() => VolumeManager.setVolume(initVolume).finally(() => callback(Volume.Up)),
200
);
} else if (initVolume - result.volume > 0.0001) {
setTimeout(
() => VolumeManager.setVolume(initVolume).finally(() => callback(Volume.Down)),
200
);
}
});
return () => {
volumeListener && volumeListener.remove();
if (typeof volumeRef.current === 'number') {
VolumeManager.setVolume(volumeRef.current).finally(() => {
VolumeManager.showNativeVolumeUI({ enabled: true });
});
}
};
}, [initVolume, callback]);
useFocusEffect(init);
useFocusEffect(listener);
};
const Component = () => {
...
const callbackRef = useRef<(type: Volume) => void>();
callbackRef.current = (type) => {
if (type === Volume.Down) {
handleNextPage();
}
if (type === Volume.Up) {
handlePrevPage();
}
};
useVolumeUpDown(
useCallback((type) => {
callbackRef.current && callbackRef.current(type);
}, [])
);
...
}
The reason is most likely that you're losing the audio session. You could try using the AppState
listener to disable the AudioSession
when you background the app and then enable it once you reopen the app. To do this, call:
VolumeManager.enable(true)
Alternatively, you can use VolumeManager.setActive(true)
or false
based on the app's state.
Im one of my Apps, I am doing following:
const onAppStateChange = useCallback(async (status: AppStateStatus) => {
if (status === 'active') {
if (audioSessionIsInactive.current) {
VolumeManager.setActive(true);
audioSessionIsInactive.current = false;
}
} else if (status === 'background') {
VolumeManager.setActive(false);
audioSessionIsInactive.current = true;
}
}, []);
useAppState({
onChange: onAppStateChange,
});
Based on what libraries you use, you might need to trigger .enable(true)
as well. Check the methods in the README, that should help to solve your issue.
Thank you for the reply
I call the VolumeManager.enable(true)
and it worked!