Make RNCamera check for permissions.
Migrate permission check to different file to be shared by RNCamera and RCTCamera
This commit is contained in:
parent
0f1cdf5819
commit
177cf00775
|
@ -196,6 +196,8 @@ export default class CameraScreen extends React.Component {
|
|||
onFacesDetected={this.onFacesDetected}
|
||||
onFaceDetectionError={this.onFaceDetectionError}
|
||||
focusDepth={this.state.depth}
|
||||
permissionDialogTitle={'Permission to use camera'}
|
||||
permissionDialogMessage={'We need your permission to use your camera phone'}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
<string>Used to take photos</string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string></string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Used to record audio in videos</string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
|
|
|
@ -226,5 +226,22 @@ RCT_REMAP_METHOD(stopRecording, reactTag:(nonnull NSNumber *)reactTag)
|
|||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(checkDeviceAuthorizationStatus:(RCTPromiseResolveBlock)resolve
|
||||
reject:(__unused RCTPromiseRejectBlock)reject) {
|
||||
__block NSString *mediaType = AVMediaTypeVideo;
|
||||
|
||||
[AVCaptureDevice requestAccessForMediaType:mediaType completionHandler:^(BOOL granted) {
|
||||
if (!granted) {
|
||||
resolve(@(granted));
|
||||
}
|
||||
else {
|
||||
mediaType = AVMediaTypeAudio;
|
||||
[AVCaptureDevice requestAccessForMediaType:mediaType completionHandler:^(BOOL granted) {
|
||||
resolve(@(granted));
|
||||
}];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@ import {
|
|||
UIManager,
|
||||
} from 'react-native';
|
||||
|
||||
import { requestPermissions } from './handlePermissions';
|
||||
|
||||
const CameraManager = NativeModules.CameraManager || NativeModules.CameraModule;
|
||||
|
||||
function convertNativeProps(props) {
|
||||
|
@ -190,34 +192,8 @@ export default class Camera extends Component {
|
|||
let hasVideoAndAudio =
|
||||
this.props.captureAudio && captureMode === Camera.constants.CaptureMode.video;
|
||||
|
||||
if (Platform.OS === 'ios') {
|
||||
let check = hasVideoAndAudio
|
||||
? Camera.checkDeviceAuthorizationStatus
|
||||
: Camera.checkVideoAuthorizationStatus;
|
||||
|
||||
if (check) {
|
||||
const isAuthorized = await check();
|
||||
this.setState({ isAuthorized, isAuthorizationChecked: true });
|
||||
}
|
||||
} else if (Platform.OS === 'android') {
|
||||
const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA, {
|
||||
title: this.props.permissionDialogTitle,
|
||||
message: this.props.permissionDialogMessage,
|
||||
});
|
||||
|
||||
// On devices before SDK version 23, the permissions are automatically granted if they appear in the manifest,
|
||||
// so check and request should always be true.
|
||||
// https://github.com/facebook/react-native-website/blob/master/docs/permissionsandroid.md
|
||||
const isAuthorized =
|
||||
Platform.Version >= 23 ? granted === PermissionsAndroid.RESULTS.GRANTED : granted === true;
|
||||
|
||||
this.setState({
|
||||
isAuthorized,
|
||||
isAuthorizationChecked: true,
|
||||
});
|
||||
} else {
|
||||
this.setState({ isAuthorized: true, isAuthorizationChecked: true });
|
||||
}
|
||||
const isAuthorized = await requestPermissions(hasVideoAndAudio, Camera, Platform.OS, this.props.permissionDialogTitle, this.props.permissionDialogMessage);
|
||||
this.setState({ isAuthorized, isAuthorizationChecked: true });
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
|
|
@ -2,10 +2,21 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { mapValues } from 'lodash';
|
||||
import { findNodeHandle, Platform, NativeModules, ViewPropTypes, requireNativeComponent } from 'react-native';
|
||||
import {
|
||||
findNodeHandle,
|
||||
Platform,
|
||||
NativeModules,
|
||||
ViewPropTypes,
|
||||
requireNativeComponent,
|
||||
View,
|
||||
ActivityIndicator,
|
||||
Text,
|
||||
} from 'react-native';
|
||||
|
||||
import type { FaceFeature } from './FaceDetector';
|
||||
|
||||
import { requestPermissions } from './handlePermissions';
|
||||
|
||||
type PictureOptions = {
|
||||
quality?: number,
|
||||
};
|
||||
|
@ -108,6 +119,10 @@ export default class Camera extends React.Component<PropsType> {
|
|||
flashMode: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
whiteBalance: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
autoFocus: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]),
|
||||
permissionDialogTitle: PropTypes.string,
|
||||
permissionDialogMessage: PropTypes.string,
|
||||
notAuthorizedView: PropTypes.element,
|
||||
pendingAuthorizationView: PropTypes.element,
|
||||
};
|
||||
|
||||
static defaultProps: Object = {
|
||||
|
@ -122,6 +137,37 @@ export default class Camera extends React.Component<PropsType> {
|
|||
barCodeTypes: Object.values(CameraManager.BarCodeType),
|
||||
faceDetectionLandmarks: CameraManager.FaceDetection.Landmarks.none,
|
||||
faceDetectionClassifications: CameraManager.FaceDetection.Classifications.none,
|
||||
permissionDialogTitle: '',
|
||||
permissionDialogMessage: '',
|
||||
notAuthorizedView: (
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
Camera not authorized
|
||||
</Text>
|
||||
</View>
|
||||
),
|
||||
pendingAuthorizationView: (
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<ActivityIndicator size="small" />
|
||||
</View>
|
||||
),
|
||||
};
|
||||
|
||||
_cameraRef: ?Object;
|
||||
|
@ -133,6 +179,10 @@ export default class Camera extends React.Component<PropsType> {
|
|||
super(props);
|
||||
this._lastEvents = {};
|
||||
this._lastEventsTimes = {};
|
||||
this.state = {
|
||||
isAuthorized: false,
|
||||
isAuthorizationChecked: false,
|
||||
};
|
||||
}
|
||||
|
||||
async takePictureAsync(options?: PictureOptions) {
|
||||
|
@ -207,19 +257,31 @@ export default class Camera extends React.Component<PropsType> {
|
|||
}
|
||||
};
|
||||
|
||||
async componentWillMount() {
|
||||
const hasVideoAndAudio = true; //TODO implement capture mode for camera / video like RCTCamera. Now, infer always video.
|
||||
const isAuthorized = await requestPermissions(hasVideoAndAudio, CameraManager, Platform.OS, this.props.permissionDialogTitle, this.props.permissionDialogMessage);
|
||||
this.setState({ isAuthorized, isAuthorizationChecked: true });
|
||||
}
|
||||
|
||||
render() {
|
||||
const nativeProps = this._convertNativeProps(this.props);
|
||||
|
||||
return (
|
||||
<RNCamera
|
||||
{...nativeProps}
|
||||
ref={this._setReference}
|
||||
onMountError={this._onMountError}
|
||||
onCameraReady={this._onCameraReady}
|
||||
onBarCodeRead={this._onObjectDetected(this.props.onBarCodeRead)}
|
||||
onFacesDetected={this._onObjectDetected(this.props.onFacesDetected)}
|
||||
/>
|
||||
);
|
||||
if (this.state.isAuthorized) {
|
||||
return (
|
||||
<RNCamera
|
||||
{...nativeProps}
|
||||
ref={this._setReference}
|
||||
onMountError={this._onMountError}
|
||||
onCameraReady={this._onCameraReady}
|
||||
onBarCodeRead={this._onObjectDetected(this.props.onBarCodeRead)}
|
||||
onFacesDetected={this._onObjectDetected(this.props.onFacesDetected)}
|
||||
/>
|
||||
);
|
||||
} else if (!this.state.isAuthorizationChecked) {
|
||||
return this.props.pendingAuthorizationView;
|
||||
} else {
|
||||
return this.props.notAuthorizedView;
|
||||
}
|
||||
}
|
||||
|
||||
_convertNativeProps(props: PropsType) {
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import { PermissionsAndroid } from 'react-native';
|
||||
|
||||
export const requestPermissions = async (hasVideoAndAudio, CameraManager, osType, permissionDialogTitle, permissionDialogMessage) => {
|
||||
if (osType === 'ios') {
|
||||
let check = hasVideoAndAudio
|
||||
? CameraManager.checkDeviceAuthorizationStatus
|
||||
: CameraManager.checkVideoAuthorizationStatus;
|
||||
|
||||
if (check) {
|
||||
const isAuthorized = await check();
|
||||
return isAuthorized;
|
||||
}
|
||||
} else if (osType === 'android') {
|
||||
const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA, {
|
||||
title: permissionDialogTitle,
|
||||
message: permissionDialogMessage,
|
||||
});
|
||||
|
||||
// On devices before SDK version 23, the permissions are automatically granted if they appear in the manifest,
|
||||
// so check and request should always be true.
|
||||
// https://github.com/facebook/react-native-website/blob/master/docs/permissionsandroid.md
|
||||
const isAuthorized =
|
||||
Platform.Version >= 23 ? granted === PermissionsAndroid.RESULTS.GRANTED : granted === true;
|
||||
|
||||
return isAuthorized;
|
||||
}
|
||||
return true;
|
||||
}
|
Loading…
Reference in New Issue