perf: Make getCameraPermission
and getMicrophonePermission
synchronous (#2302)
This commit is contained in:
parent
3d2feb6f6c
commit
591cf30a06
@ -164,8 +164,8 @@ There could be three states to this:
|
|||||||
Simply use the **get** functions to find out if a user has granted or denied permission before:
|
Simply use the **get** functions to find out if a user has granted or denied permission before:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const cameraPermission = await Camera.getCameraPermissionStatus()
|
const cameraPermission = Camera.getCameraPermissionStatus()
|
||||||
const microphonePermission = await Camera.getMicrophonePermissionStatus()
|
const microphonePermission = Camera.getMicrophonePermissionStatus()
|
||||||
```
|
```
|
||||||
|
|
||||||
A permission status can have the following values:
|
A permission status can have the following values:
|
||||||
|
@ -149,24 +149,24 @@ class CameraViewModule(reactContext: ReactApplicationContext) : ReactContextBase
|
|||||||
return activity?.shouldShowRequestPermissionRationale(permission) ?: false
|
return activity?.shouldShowRequestPermissionRationale(permission) ?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactMethod
|
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||||
fun getCameraPermissionStatus(promise: Promise) {
|
fun getCameraPermissionStatus(): String {
|
||||||
val status = ContextCompat.checkSelfPermission(reactApplicationContext, Manifest.permission.CAMERA)
|
val status = ContextCompat.checkSelfPermission(reactApplicationContext, Manifest.permission.CAMERA)
|
||||||
var parsed = PermissionStatus.fromPermissionStatus(status)
|
var parsed = PermissionStatus.fromPermissionStatus(status)
|
||||||
if (parsed == PermissionStatus.DENIED && canRequestPermission(Manifest.permission.CAMERA)) {
|
if (parsed == PermissionStatus.DENIED && canRequestPermission(Manifest.permission.CAMERA)) {
|
||||||
parsed = PermissionStatus.NOT_DETERMINED
|
parsed = PermissionStatus.NOT_DETERMINED
|
||||||
}
|
}
|
||||||
promise.resolve(parsed.unionValue)
|
return parsed.unionValue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactMethod
|
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||||
fun getMicrophonePermissionStatus(promise: Promise) {
|
fun getMicrophonePermissionStatus(): String {
|
||||||
val status = ContextCompat.checkSelfPermission(reactApplicationContext, Manifest.permission.RECORD_AUDIO)
|
val status = ContextCompat.checkSelfPermission(reactApplicationContext, Manifest.permission.RECORD_AUDIO)
|
||||||
var parsed = PermissionStatus.fromPermissionStatus(status)
|
var parsed = PermissionStatus.fromPermissionStatus(status)
|
||||||
if (parsed == PermissionStatus.DENIED && canRequestPermission(Manifest.permission.RECORD_AUDIO)) {
|
if (parsed == PermissionStatus.DENIED && canRequestPermission(Manifest.permission.RECORD_AUDIO)) {
|
||||||
parsed = PermissionStatus.NOT_DETERMINED
|
parsed = PermissionStatus.NOT_DETERMINED
|
||||||
}
|
}
|
||||||
promise.resolve(parsed.unionValue)
|
return parsed.unionValue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { NavigationContainer } from '@react-navigation/native'
|
import { NavigationContainer } from '@react-navigation/native'
|
||||||
import React, { useEffect, useState } from 'react'
|
import React from 'react'
|
||||||
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||||
import { PermissionsPage } from './PermissionsPage'
|
import { PermissionsPage } from './PermissionsPage'
|
||||||
import { MediaPage } from './MediaPage'
|
import { MediaPage } from './MediaPage'
|
||||||
import { CameraPage } from './CameraPage'
|
import { CameraPage } from './CameraPage'
|
||||||
import { CodeScannerPage } from './CodeScannerPage'
|
import { CodeScannerPage } from './CodeScannerPage'
|
||||||
import type { Routes } from './Routes'
|
import type { Routes } from './Routes'
|
||||||
import { Camera, CameraPermissionStatus } from 'react-native-vision-camera'
|
import { Camera } from 'react-native-vision-camera'
|
||||||
import { GestureHandlerRootView } from 'react-native-gesture-handler'
|
import { GestureHandlerRootView } from 'react-native-gesture-handler'
|
||||||
import { StyleSheet } from 'react-native'
|
import { StyleSheet } from 'react-native'
|
||||||
import { DevicesPage } from './DevicesPage'
|
import { DevicesPage } from './DevicesPage'
|
||||||
@ -14,21 +14,11 @@ import { DevicesPage } from './DevicesPage'
|
|||||||
const Stack = createNativeStackNavigator<Routes>()
|
const Stack = createNativeStackNavigator<Routes>()
|
||||||
|
|
||||||
export function App(): React.ReactElement | null {
|
export function App(): React.ReactElement | null {
|
||||||
const [cameraPermission, setCameraPermission] = useState<CameraPermissionStatus>()
|
const cameraPermission = Camera.getCameraPermissionStatus()
|
||||||
const [microphonePermission, setMicrophonePermission] = useState<CameraPermissionStatus>()
|
const microphonePermission = Camera.getMicrophonePermissionStatus()
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
Camera.getCameraPermissionStatus().then(setCameraPermission)
|
|
||||||
Camera.getMicrophonePermissionStatus().then(setMicrophonePermission)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
console.log(`Re-rendering Navigator. Camera: ${cameraPermission} | Microphone: ${microphonePermission}`)
|
console.log(`Re-rendering Navigator. Camera: ${cameraPermission} | Microphone: ${microphonePermission}`)
|
||||||
|
|
||||||
if (cameraPermission == null || microphonePermission == null) {
|
|
||||||
// still loading
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const showPermissionsPage = cameraPermission !== 'granted' || microphonePermission === 'not-determined'
|
const showPermissionsPage = cameraPermission !== 'granted' || microphonePermission === 'not-determined'
|
||||||
return (
|
return (
|
||||||
<NavigationContainer>
|
<NavigationContainer>
|
||||||
|
@ -31,7 +31,7 @@ type Props = NativeStackScreenProps<Routes, 'CameraPage'>
|
|||||||
export function CameraPage({ navigation }: Props): React.ReactElement {
|
export function CameraPage({ navigation }: Props): React.ReactElement {
|
||||||
const camera = useRef<Camera>(null)
|
const camera = useRef<Camera>(null)
|
||||||
const [isCameraInitialized, setIsCameraInitialized] = useState(false)
|
const [isCameraInitialized, setIsCameraInitialized] = useState(false)
|
||||||
const [hasMicrophonePermission, setHasMicrophonePermission] = useState(false)
|
const hasMicrophonePermission = useMemo(() => Camera.getMicrophonePermissionStatus() === 'granted', [])
|
||||||
const zoom = useSharedValue(0)
|
const zoom = useSharedValue(0)
|
||||||
const isPressingButton = useSharedValue(false)
|
const isPressingButton = useSharedValue(false)
|
||||||
|
|
||||||
@ -131,10 +131,6 @@ export function CameraPage({ navigation }: Props): React.ReactElement {
|
|||||||
// Run everytime the neutralZoomScaled value changes. (reset zoom when device changes)
|
// Run everytime the neutralZoomScaled value changes. (reset zoom when device changes)
|
||||||
zoom.value = neutralZoom
|
zoom.value = neutralZoom
|
||||||
}, [neutralZoom, zoom])
|
}, [neutralZoom, zoom])
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
Camera.getMicrophonePermissionStatus().then((status) => setHasMicrophonePermission(status === 'granted'))
|
|
||||||
}, [])
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region Pinch to Zoom Gesture
|
//#region Pinch to Zoom Gesture
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
@interface RCT_EXTERN_REMAP_MODULE (CameraView, CameraViewManager, RCTViewManager)
|
@interface RCT_EXTERN_REMAP_MODULE (CameraView, CameraViewManager, RCTViewManager)
|
||||||
|
|
||||||
// Module Functions
|
// Module Functions
|
||||||
RCT_EXTERN_METHOD(getCameraPermissionStatus : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)reject);
|
RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(getCameraPermissionStatus);
|
||||||
RCT_EXTERN_METHOD(getMicrophonePermissionStatus : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)reject);
|
RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(getMicrophonePermissionStatus);
|
||||||
RCT_EXTERN_METHOD(requestCameraPermission : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)reject);
|
RCT_EXTERN_METHOD(requestCameraPermission : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)reject);
|
||||||
RCT_EXTERN_METHOD(requestMicrophonePermission : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)reject);
|
RCT_EXTERN_METHOD(requestMicrophonePermission : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)reject);
|
||||||
|
|
||||||
|
@ -84,19 +84,15 @@ final class CameraViewManager: RCTViewManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
final func getCameraPermissionStatus(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
final func getCameraPermissionStatus() -> String {
|
||||||
withPromise(resolve: resolve, reject: reject) {
|
let status = AVCaptureDevice.authorizationStatus(for: .video)
|
||||||
let status = AVCaptureDevice.authorizationStatus(for: .video)
|
return status.descriptor
|
||||||
return status.descriptor
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
final func getMicrophonePermissionStatus(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
final func getMicrophonePermissionStatus() -> String {
|
||||||
withPromise(resolve: resolve, reject: reject) {
|
let status = AVCaptureDevice.authorizationStatus(for: .audio)
|
||||||
let status = AVCaptureDevice.authorizationStatus(for: .audio)
|
return status.descriptor
|
||||||
return status.descriptor
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
|
@ -345,30 +345,18 @@ export class Camera extends React.PureComponent<CameraProps, CameraState> {
|
|||||||
* the user has permitted the app to use the camera.
|
* the user has permitted the app to use the camera.
|
||||||
*
|
*
|
||||||
* To actually prompt the user for camera permission, use {@linkcode Camera.requestCameraPermission | requestCameraPermission()}.
|
* To actually prompt the user for camera permission, use {@linkcode Camera.requestCameraPermission | requestCameraPermission()}.
|
||||||
*
|
|
||||||
* @throws {@linkcode CameraRuntimeError} When any kind of error occured while getting the current permission status. Use the {@linkcode CameraRuntimeError.code | code} property to get the actual error
|
|
||||||
*/
|
*/
|
||||||
public static async getCameraPermissionStatus(): Promise<CameraPermissionStatus> {
|
public static getCameraPermissionStatus(): CameraPermissionStatus {
|
||||||
try {
|
return CameraModule.getCameraPermissionStatus()
|
||||||
return await CameraModule.getCameraPermissionStatus()
|
|
||||||
} catch (e) {
|
|
||||||
throw tryParseNativeCameraError(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Gets the current Microphone-Recording Permission Status. Check this before mounting the Camera to ensure
|
* Gets the current Microphone-Recording Permission Status. Check this before mounting the Camera to ensure
|
||||||
* the user has permitted the app to use the microphone.
|
* the user has permitted the app to use the microphone.
|
||||||
*
|
*
|
||||||
* To actually prompt the user for microphone permission, use {@linkcode Camera.requestMicrophonePermission | requestMicrophonePermission()}.
|
* To actually prompt the user for microphone permission, use {@linkcode Camera.requestMicrophonePermission | requestMicrophonePermission()}.
|
||||||
*
|
|
||||||
* @throws {@linkcode CameraRuntimeError} When any kind of error occured while getting the current permission status. Use the {@linkcode CameraRuntimeError.code | code} property to get the actual error
|
|
||||||
*/
|
*/
|
||||||
public static async getMicrophonePermissionStatus(): Promise<CameraPermissionStatus> {
|
public static getMicrophonePermissionStatus(): CameraPermissionStatus {
|
||||||
try {
|
return CameraModule.getMicrophonePermissionStatus()
|
||||||
return await CameraModule.getMicrophonePermissionStatus()
|
|
||||||
} catch (e) {
|
|
||||||
throw tryParseNativeCameraError(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Shows a "request permission" alert to the user, and resolves with the new camera permission status.
|
* Shows a "request permission" alert to the user, and resolves with the new camera permission status.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react'
|
import { useCallback, useState } from 'react'
|
||||||
import { Camera } from '../Camera'
|
import { Camera } from '../Camera'
|
||||||
|
|
||||||
interface PermissionState {
|
interface PermissionState {
|
||||||
@ -31,7 +31,7 @@ interface PermissionState {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export function useCameraPermission(): PermissionState {
|
export function useCameraPermission(): PermissionState {
|
||||||
const [hasPermission, setHasPermission] = useState(false)
|
const [hasPermission, setHasPermission] = useState(() => Camera.getCameraPermissionStatus() === 'granted')
|
||||||
|
|
||||||
const requestPermission = useCallback(async () => {
|
const requestPermission = useCallback(async () => {
|
||||||
const result = await Camera.requestCameraPermission()
|
const result = await Camera.requestCameraPermission()
|
||||||
@ -40,10 +40,6 @@ export function useCameraPermission(): PermissionState {
|
|||||||
return hasPermissionNow
|
return hasPermissionNow
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
Camera.getCameraPermissionStatus().then((s) => setHasPermission(s === 'granted'))
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hasPermission,
|
hasPermission,
|
||||||
requestPermission,
|
requestPermission,
|
||||||
@ -65,7 +61,7 @@ export function useCameraPermission(): PermissionState {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export function useMicrophonePermission(): PermissionState {
|
export function useMicrophonePermission(): PermissionState {
|
||||||
const [hasPermission, setHasPermission] = useState(false)
|
const [hasPermission, setHasPermission] = useState(() => Camera.getMicrophonePermissionStatus() === 'granted')
|
||||||
|
|
||||||
const requestPermission = useCallback(async () => {
|
const requestPermission = useCallback(async () => {
|
||||||
const result = await Camera.requestMicrophonePermission()
|
const result = await Camera.requestMicrophonePermission()
|
||||||
@ -74,10 +70,6 @@ export function useMicrophonePermission(): PermissionState {
|
|||||||
return hasPermissionNow
|
return hasPermissionNow
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
Camera.getMicrophonePermissionStatus().then((s) => setHasPermission(s === 'granted'))
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hasPermission,
|
hasPermission,
|
||||||
requestPermission,
|
requestPermission,
|
||||||
|
Loading…
Reference in New Issue
Block a user