Description
After a fresh install, when camera permission is denied and then granted via the Android Settings app, the camera view shows a black screen upon returning to the app. The camera only works after a full app restart.
This bug is only reproducible in release/preview builds (not in debug/development builds).
Steps to Reproduce
- Fresh install of the app
- Navigate to the scanner screen
- Deny camera permission in the system dialog (or tap "Don't Allow")
- Tap "Open Settings" button (app calls
Linking.openSettings())
- Grant camera permission in Android Settings
- Return to the app (press back)
- Expected: Camera feed is visible
- Actual: Screen is completely black — camera only appears after restarting the app
Root Cause Analysis
useCameraPermission registers an AppState.addEventListener('change', ...) listener that calls Camera.getCameraPermissionStatus() synchronously to update hasPermission. On Android release builds, this listener appears to not correctly update hasPermission to true when returning from the Settings app with permission granted.
Because hasPermission is only initialized once via useState(() => get() === 'granted') and relies on the AppState listener to refresh, stale state persists until a full app restart causes useState to re-initialize with the correct permission status.
Why only release builds? In development builds, Metro's Fast Refresh causes component remounts that incidentally re-initialize the hook state. In release builds (Hermes, no Metro), this doesn't occur.
Workaround
Detect the hasPermission: false → true transition and force a navigation screen replacement to trigger a full component remount:
const shouldReplaceRef = useRef(!hasPermission);
useEffect(() => {
if (!hasPermission) {
shouldReplaceRef.current = true;
} else if (shouldReplaceRef.current && appState === 'active') {
shouldReplaceRef.current = false;
navigation.replace('scanner', route.params); // force full remount
}
}, [hasPermission, appState, navigation, route.params]);
Environment
|
|
react-native-vision-camera |
4.7.3 |
react-native |
0.79.6 |
expo |
53.0.25 |
| Platform |
Android |
| Build type |
Release / Preview (Expo EAS) |
| JS Engine |
Hermes |
Additional Notes
Camera.getAvailableCameraDevices() does not require camera permission on Android — devices are always returned correctly, so a stale device object is not the cause.
- The
useCameraPermission AppState listener is correctly registered (confirmed via source inspection of v4.7.3). The issue appears to be with the synchronous getCameraPermissionStatus() bridge call returning a stale/incorrect value in the context of an Android release build resuming from background.
Description
After a fresh install, when camera permission is denied and then granted via the Android Settings app, the camera view shows a black screen upon returning to the app. The camera only works after a full app restart.
This bug is only reproducible in release/preview builds (not in debug/development builds).
Steps to Reproduce
Linking.openSettings())Root Cause Analysis
useCameraPermissionregisters anAppState.addEventListener('change', ...)listener that callsCamera.getCameraPermissionStatus()synchronously to updatehasPermission. On Android release builds, this listener appears to not correctly updatehasPermissiontotruewhen returning from the Settings app with permission granted.Because
hasPermissionis only initialized once viauseState(() => get() === 'granted')and relies on the AppState listener to refresh, stale state persists until a full app restart causesuseStateto re-initialize with the correct permission status.Why only release builds? In development builds, Metro's Fast Refresh causes component remounts that incidentally re-initialize the hook state. In release builds (Hermes, no Metro), this doesn't occur.
Workaround
Detect the
hasPermission: false → truetransition and force a navigation screen replacement to trigger a full component remount:Environment
react-native-vision-camera4.7.3react-native0.79.6expo53.0.25Additional Notes
Camera.getAvailableCameraDevices()does not require camera permission on Android — devices are always returned correctly, so a stale device object is not the cause.useCameraPermissionAppState listener is correctly registered (confirmed via source inspection ofv4.7.3). The issue appears to be with the synchronousgetCameraPermissionStatus()bridge call returning a stale/incorrect value in the context of an Android release build resuming from background.