react-native-vision-camera device is null - react-native

I am trying to run a basic example of react-native-vision-camera and getting the error device is null. I checked the app permissions through android phone and camera permissions are granted. Here is my current code:
import React,{useEffect, useState} from 'react';
import { Text, View, Linking} from 'react-native';
import {useCameraDevices, Camera} from 'react-native-vision-camera';
const App = () => {
const devices = useCameraDevices();
const device = devices.back;
React.useEffect( () => {
requestCameraPermission();
}, [])
const requestCameraPermission = React.useCallback( async () => {
const permission = await Camera.requestCameraPermission();
if (permission == 'denied')
{
console.log("Permission not granted");
await Linking.openSettings();
}
}, [])
function renderCamera()
{
if(device == null)
{
console.log("device is null");
return (<View><Text>Camera not working</Text></View>)
}
else
{
<View>
<Camera
device={device}
isActive={true}
enableZoomGesture
/>
</View>
}
}
return(
<View>
{renderCamera()}
</View>
)
}
export default App;

Related

Audio and Video not working offline when using useNetInfo from netinfo

I've been battling a bug in my code for the last 4 days and would appreciate some pointers to get me going in the right directions. Component is working fine as long as there is internet connection, but if there is no internet connection, audios and videos are not playing, only thumbnail present.
I'm using netInfo's NetInfo.fetch() to check for connection. If there is connection, I'm refetching data to check for any updates to student assignments.
I'm using expo-av for playing audio/video files (v10.2.1). I'm also using useQuery hook from react-query to fetch data about audio and video files (like url etc.) My video player component is something like this:
Video Player:
import React, {
forwardRef,
ForwardRefRenderFunction,
useCallback,
useImperativeHandle,
useRef
} from 'react';
import { Platform } from 'react-native';
import Orientation from 'react-native-orientation-locker';
import { Audio, Video, VideoFullscreenUpdateEvent, VideoProps } from 'expo-av';
const Player: ForwardRefRenderFunction<
Video | undefined,
VideoProps
> = (props, ref) => {
const innerRef = useRef<Video>(null);
const orientation = useCallback<
(event: VideoFullscreenUpdateEvent) => void
>(
(event) => {
if (Platform.OS === 'android') {
if (
event.fullscreenUpdate === Video.FULLSCREEN_UPDATE_PLAYER_DID_PRESENT
) {
Orientation.unlockAllOrientations();
} else if (
event.fullscreenUpdate === Video.FULLSCREEN_UPDATE_PLAYER_DID_DISMISS
) {
Orientation.lockToPortrait();
}
}
props.onFullscreenUpdate?.(event);
},
[props]
);
useImperativeHandle(ref, () => {
if (innerRef.current) {
return innerRef.current;
}
return undefined;
});
return (
<Video
resizeMode="contain"
useNativeControls
ref={innerRef}
onLoad={loading}
{...props}
onFullscreenUpdate={orientation}
/>
);
};
export const VideoPlayer = forwardRef(Player);
Custom Hook:
For async state management, I'm using a custom react-query hook, that looks something like this (non-relevant imports and code removed):
import { useFocusEffect } from '#react-navigation/core';
import { useCallback } from 'react';
import NetInfo from '#react-native-community/netinfo';
export const useStudentAssignment = (
assignmentId: Assignment['id']
): UseQueryResult<Assignment, Error> => {
const listKey = studentAssignmentKeys.list({ assignedToIdEq: studentData?.id });
const queryClient = useQueryClient();
const data = useQuery<Assignment, Error>(
studentAssignmentKeys.detail(assignmentId),
async () => {
const { data: assignment } = await SystemAPI.fetchAssignment(assignmentId);
return Assignment.deserialize({
...assignment,
});
},
{
staleTime: 1000 * 60 * 30,
initialData: () => {
const cache= queryClient.getQueryData<Assignment[]>(listKey);
return cache?.find((assignment) => assignment.id === assignmentId);
},
initialDataUpdatedAt: queryClient.getQueryState(listKey)?.dataUpdatedAt,
}
);
useFocusEffect(
useCallback(() => {
NetInfo.fetch().then((state) => {
if (state.isConnected) {
data.refetch();
}
});
}, [data])
);
return data;
};
Component:
import React, { FC, useCallback, useEffect, useMemo, useRef } from 'react';
import { SafeAreaView } from 'react-native-safe-area-context';
import { StackScreenProps } from '#react-navigation/stack';
import { ROUTES } from 'enums/SMSRoutes';
import { StoreType } from 'enums/SMSStoreType';
import { useStudentAssignment } from 'hooks/Assignments/useStudentAssignment';
import { RootStackParamList } from 'navigators';
import { AssignmentViewer } from 'screens/AssignmentViewer';
type NavProps = StackScreenProps<
RootStackParamList,
ROUTES.ASSIGNMENT_VIEW
>;
export const AssignmentView: FC<NavProps> = ({
navigation,
route: {
params: { assignmentId }
}
}) => {
const assignmentQuery = useStudentAssignment(assignmentId);
const assignmentTracker = useStore(StoreType.AssignmentTracker);
const isDoneRef = useRef<boolean>(false);
const questions = assignmentQuery.data?.questions || [];
const activeQuestion = useMemo(() => {
return questions.filter((question) => question.active);
}, [questions]);
const onDone = useCallback(() => {
isDoneRef.current = true;
navigation.push(ROUTES.ASSIGNMENT_COMPLETED);
}, [navigation]);
useEffect(() => {
assignmentTracker.start(assignmentId);
return () => {
assignmentTracker.finish(isDoneRef.current);
};
}, []);
return (
<SafeAreaView>
<AssignmentViewer
questions={activeQuestion}
onDone={onDone}
isLoading={assignmentQuery.isLoading}
/>
</SafeAreaView>
);
};
What I'm trying to do here is that if internet connection is connected and the user navigates to the current view (which is used to view assignments), I'd like to refetch the data. Per the requirements, I can't use the staleTime property or any other interval based refetching.
Component is working fine if I don't refetch, or if internet connection is present. If connection isn't there, it doesn't play the cache'd audio/video.
If I take out the check for internet connection (remove netInfo), component display videos both offline and online. However, refetching fails due to no connectivity.
What should I change to make sure that data is refetched when connected and videos are played even if not connected to Internet?

Screen State not Updating from AsyncStorage when going back

I'm building a React Native app.
My app has 5 Screens: Home (initialRouteName), DeckPage, QuestionPage, NewCardPage, NewDeckPage. (in this order)
I'm using Redux for state management. The state is updating from AsyncStorage.
The component that does the fetching is the class component "Home" by dispatching the "fetching" function in componentDidMount.
Component NewCardPage, NewDeckPAge are also updating the state with new content by dispatching the same fetching function as the Home when a button is pressed.
My problem appears when I want to delete a Deck component from inside DeckPage parent component. The function that does this job has this functionality: after removing the item from AsyncStorage, updates the STATE, and moves back to Screen HOME. The issue is that when I go back to HOME component the state doesn't update with the latest info from AsyncStorage.
This is not the case when I'm doing the same operation in the other 2 components NewCardPage, NewDeckPage.
I'll paste the code below:
import React, { Component } from "react";
import { connect } from "react-redux";
import { View, Text, StyleSheet, FlatList } from "react-native";
import Header from "../components/Header";
import AddDeckButton from "../components/AddDeckButton";
import DeckInList from "../components/DeckInList";
import { receiveItemsAction } from "../redux/actions";
class Home extends Component {
componentDidMount() {
this.props.getAsyncStorageContent();
}
renderItem = ({ item }) => {
return <DeckInList {...item} />;
};
render() {
const { items } = this.props;
// console.log(items);
const deckNumber = Object.keys(items).length;
return (
<View style={styles.container}>
<Header />
<View style={styles.decksInfoContainer}>
<View style={styles.deckNumber}>
<View style={{ marginRight: 50 }}>
<Text style={styles.deckNumberText}>{deckNumber} Decks</Text>
</View>
<AddDeckButton />
</View>
<View style={{ flex: 0.9 }}>
<FlatList
data={Object.values(items)}
renderItem={this.renderItem}
keyExtractor={(item) => item.title}
/>
</View>
</View>
</View>
);
}
}
const mapStateToProps = (state) => {
return {
items: state.items,
};
};
const mapDispatchToProps = (dispatch) => {
return {
getAsyncStorageContent: () => dispatch(receiveItemsAction()),
};
};
-----------DECKPAGE COMPONENT------------
import React from "react";
import { View, StyleSheet } from "react-native";
import Deck from "../components/Deck";
import { useSelector, useDispatch } from "react-redux";
import { removeItemAction, receiveItemsAction } from "../redux/actions";
import AsyncStorage from "#react-native-community/async-storage";
const DeckPage = ({ route, navigation }) => {
const { title, date } = route.params;
const questions = useSelector((state) => state.items[title].questions);
const state = useSelector((state) => state.items);
const dispatch = useDispatch();
// const navigation = useNavigation();
const handleRemoveIcon = async () => {
await AsyncStorage.removeItem(title, () => {
dispatch(receiveItemsAction());
navigation.goBack();
});
};
console.log(state);
return (
<View style={styles.deckPageContainer}>
<Deck
handleRemoveIcon={handleRemoveIcon}
title={title}
questions={questions}
date={date}
/>
</View>
);
};
-----------This is my ACTIONS file----------
import AsyncStorage from "#react-native-community/async-storage";
export const RECEIVE_ITEMS = "RECEIVE_ITEMS";
// export const REMOVE_ITEM = "REMOVE_ITEM";
export const receiveItemsAction = () => async (dispatch) => {
const objectValues = {};
try {
const keys = await AsyncStorage.getAllKeys();
if (keys.length !== 0) {
const jsonValue = await AsyncStorage.multiGet(keys);
if (jsonValue != null) {
for (let element of jsonValue) {
objectValues[element[0]] = JSON.parse(element[1]);
}
dispatch({
type: RECEIVE_ITEMS,
payload: objectValues,
});
} else {
return null;
}
}
} catch (e) {
console.log(e);
}
};
-----This is my REDUCERS file----
import { RECEIVE_ITEMS, REMOVE_ITEM } from "./actions";
const initialState = {
};
const items = (state = initialState, action) => {
switch (action.type) {
case RECEIVE_ITEMS:
return {
...state,
...action.payload,
};
// case REMOVE_ITEM:
// return {
// ...state,
// ...action.payload,
// };
default:
return state;
}
}
export default items;
-----This is my UTILS file----
import AsyncStorage from "#react-native-community/async-storage";
export const removeDeckFromAsyncStorage = async (title)=>{
try{
await AsyncStorage.removeItem(title);
}
catch(e){
console.log(`Error trying to remove deck from AsyncStorage ${e}`);
}
}

React navigation and loading component in react native

Hello I have a react component like which either display a list of items or opens another component which allowes me to select some value. Here is the code
import React, { PureComponent } from "react";
import { Text, View } from "react-native";
import { withNavigationFocus } from "react-navigation-is-focused-hoc";
import { NavigationActions } from "react-navigation";
import { connect } from "react-redux";
import ClassListing from '../../components/ClassListing/ClassListing';
import Actions from "../../state/Actions";
import { default as stackStyles } from "./styles";
import {
StyleCreator
} from "../../utils";
let styles = StyleCreator(stackStyles.IndexStyles)();
#withNavigationFocus
#connect(() => mapStateToProps, () => mapDispatchToProps)
export default class ClassList extends PureComponent {
static navigationOptions = ({ navigation }) => {
const { params } = navigation.state;
return {
header: null,
tabBarOnPress({ jumpToIndex, scene }) {
params.onTabFocus();
jumpToIndex(scene.index);
},
};
};
constructor(props) {
super(props);
this.state = {};
console.ignoredYellowBox = ["Warning: In next release", "FlatList"];
}
componentDidMount() {
console.log("componentDidMount");
this.props.navigation.setParams({
onTabFocus: this.handleTabFocus
});
}
componentDidUpdate() {
console.log("I am updated");
}
_handleNavigationBar = () => (
<View style={styles.headerContainer}>
<Text style={styles.headerLeftTitle}>Klasselister</Text>
</View>
);
handleTabFocus = () => {
this.props.resetClassList();
// setTimeout(() => {
// this._openChildSchoolSelector();
// },500);
};
_openChildSchoolSelector = () => {
if (
!this.props.childrenSelection.selectedDependant ||
!this.props.childrenSelection.selectedSchool
) {
console.log("navigate to child selector");
this.props.navigation.dispatch(
NavigationActions.navigate({
routeName: "ChildSchoolSelector",
})
);
}
};
render() {
return (
<View>
{this._handleNavigationBar()}
{this.props.classList &&
this.props.classList.classList &&
this.props.classList.classList.length > 0 ? (
<ClassListing list={this.props.classList.classList} />
) : (
null
// this._openChildSchoolSelector()
)}
</View>
);
}
}
const mapStateToProps = (state) => {
const { classList, childrenSelection } = state.appData;
console.log("[Classlist] mapStateToProps", classList);
console.log("[Classlist] mapStateToProps", childrenSelection);
return {
classList,
childrenSelection
};
};
const mapDispatchToProps = (dispatch) => ({
resetClassList: () => {
dispatch(Actions.resetClassList());
},
});
My issue is that when I come to this tab, I want to reset the list which came from server and then open the school selector again, which I am doing in handleTabFocus. But there I have to first call
this.props.resetClassList();
this._openChildSchoolSelector()
The issue is that this._openChildSchoolSelector() is called while this.props.resetClassList() hasn't fininshed.
this.props.resetClassList() works like this
it calls an action like this
static resetClassList() {
return {
type: ActionTypes.RESET_CLASS_LIST
};
}
which then cleans the classlist like this
case ActionTypes.RESET_CLASS_LIST:
return createDefaultState();
in ClassListReducer.js
and also in ChildrenSelectionRedcuer.js
case ActionTypes.RESET_CLASS_LIST:
return createDefaultState();
Any hints to solve this? My project uses very old React navigation v1
One thing which I did was to use this
componentWillReceiveProps(nextProps) {
console.log(this.props);
console.log(nextProps);
if (
nextProps.isFocused &&
nextProps.focusedRouteKey == "ClassList" &&
(!nextProps.childrenSelection.selectedDependant ||
!nextProps.childrenSelection.selectedSchool)
) {
console.log("componentWillReceiveProps");
this._openChildSchoolSelector();
}
if (
this.props.isFocused &&
this.props.focusedRouteKey === "ClassList" &&
nextProps.focusedRouteKey !== "ClassList"
) {
console.log("reset");
this.props.resetClassList();
}
}
But not sure if this is an elegant way of doing this

How to open app settings page in react native android?

At the end react native bridge is the only way.But is there any npm package which has been worked successfully for anyone?
You can open your app settings by using Linking library.
import {Linking} from 'react-native';
Linking.openSettings();
Offical document: https://reactnative.dev/docs/linking#opensettings
You can use #react-native-community/react-native-permissions library.
Here offical documantation: https://github.com/react-native-community/react-native-permissions#opensettings
Example:
import { openSettings } from 'react-native-permissions';
openSettings();
combining the existing answers: this works for me for both iOS and Android (without expo)
import { Linking, Platform } from 'react-native';
const handleOpenSettings = () => {
if (Platform.OS === 'ios') {
Linking.openURL('app-settings:');
} else {
Linking.openSettings();
}
};
// add a button that calls handleOpenSetttings()
Use
IntentLauncher.startActivity({
action: 'android.settings.SETTINGS',
})
instead of
IntentLauncher.startActivity({
action: 'android.settings.APPLICATION_DETAILS_SETTINGS',
data: 'package:' + pkg
})
Like
import IntentLauncher, { IntentConstant } from 'react-native-intent-launcher'
const openAppSettings = () => {
if (Platform.OS === 'ios') {
Linking.openURL('app-settings:')
} else {
IntentLauncher.startActivity({
action: 'android.settings.SETTINGS',
})
}
}
ANDROID
Wifi
IntentLauncher.startActivity({
action: 'android.settings.SETTINGS'
})
GPS
IntentLauncher.startActivity({
action: 'android.settings.LOCATION_SOURCE_SETTINGS'
})
IOS
WIFI
Linking.openURL("App-Prefs:root=WIFI");
GPS
Linking.openURL('App-Prefs:Privacy&path=LOCATION')
Linking API from react-native core provides the function to send custom intent action to Android.
NOTE - You can send any custom action that is acceptable by android moreover you can also pass data to the intent.
Here is an example to open settings :
import {Linking} from 'react-native';
// To open settings
Linking.sendIntent('android.settings.SETTINGS');
// To open GPS Location setting
Linking.sendIntent('android.settings.LOCATION_SOURCE_SETTINGS');
Hope this will help you or somebody else. Thanks!
Happy Coding :-)
This is a complete answer for both android & iOS.
Without Expo:
import DeviceInfo from 'react-native-device-info';
import IntentLauncher, { IntentConstant } from 'react-native-intent-launcher'
const pkg = DeviceInfo.getBundleId();
const openAppSettings = () => {
if (Platform.OS === 'ios') {
Linking.openURL('app-settings:')
} else {
IntentLauncher.startActivity({
action: 'android.settings.APPLICATION_DETAILS_SETTINGS',
data: 'package:' + pkg
})
}
}
With Expo:
import Constants from 'expo-constants'
import * as IntentLauncher from 'expo-intent-launcher'
const pkg = Constants.manifest.releaseChannel
? Constants.manifest.android.package
: 'host.exp.exponent'
const openAppSettings = () => {
if (Platform.OS === 'ios') {
Linking.openURL('app-settings:')
} else {
IntentLauncher.startActivityAsync(
IntentLauncher.ACTION_APPLICATION_DETAILS_SETTINGS,
{ data: 'package:' + pkg },
)
}
}
import React, { useCallback } from "react";
import { Button, Linking, StyleSheet, View } from "react-native";
const OpenSettingsButton = ({ children }) => {
const handlePress = useCallback(async () => {
// Open the custom settings if the app has one
await Linking.openSettings();
}, []);
return <Button title={children} onPress={handlePress} />;
};
const App = () => {
return (
<View style={styles.container}>
<OpenSettingsButton>Open Settings</OpenSettingsButton>
</View>
);
};
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: "center", alignItems: "center" },
});
import { Linking, Platform } from 'react-native';
const openSettingsAlert = () =>
Alert.alert('Please provide the require permission from settings', '', [
{
text: 'Cancel',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel',
},
{ text: 'Go To Settings', onPress: () => openSettings() },
]);
const openSettings = () => {
if (Platform.OS === 'ios') {
Linking.openURL('app-settings:');
} else {
Linking.openSettings();
}
};
let isStoragePermitted = await requestExternalWritePermission();
if (isStoragePermitted === true) {
}else{
console.log('permission not granted');
openSettingsAlert();
}
const requestExternalWritePermission = async () => {
if (Platform.OS === 'android') {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
);
// If WRITE_EXTERNAL_STORAGE Permission is granted
return granted === PermissionsAndroid.RESULTS.GRANTED;
} catch (err) {
console.warn(err);
alert('Storage Access permission error:', err);
}
return false;
}
};

bundling failed: SyntaxError in D:\RN\AtmosphericMeshing-\src\router.js: D:/RN/AtmosphericMeshing-/src/router.js: Unexpected token (16:0)

everyone, I have been reporting wrong when I used the react-native compilation project, I don't know how to solve it, I can't find the error, please give me some Suggestions, thank you very much.
import React, { PureComponent } from 'react';
import { BackHandler, Platform, View, StatusBar, Text,Modal } from 'react-native';
import {
addNavigationHelpers
} from 'react-navigation';
import { connect } from 'react-redux';
import moment from 'moment';
import SplashScreen from 'react-native-splash-screen';
import { loadToken, getNetConfig, saveNetConfig, loadNetConfig } from './dvapack/storage';
import { createAction, NavigationActions, getCurrentScreen } from './utils';
import NetConfig from './config/NetConfig.json';
import api from './config/globalapi';
import AppNavigator from './containers/';
*I don't know if this is the correct way of writing the router, and it has led to this problem.*
#connect(({ router }) => ({ router }))***//一直报这里的错误=I've been making mistakes here.***
class Router extends PureComponent {
constructor(props) {
super(props);
this.state = {
configload: true
};
}
async componentWillMount() {
let netconfig =await loadNetConfig();
if (!netconfig && !netconfig != null) {
if (NetConfig.isAutoLoad) {
const newconfig = [];
NetConfig.Config.map((item, key) => {
const netitem = {};
// netitem.neturl = `http://${item.configIp}:${item.configPort}`+api.appurl;
netitem.neturl = `http://${item.configIp}:${item.configPort}`;
if (key === 0) {
netitem.isuse = true;
} else {
netitem.isuse = false;
}
newconfig.push(netitem);
});
saveNetConfig(newconfig);
} else {
this.setState({ configload: false });
SplashScreen.hide();
}
}
BackHandler.addEventListener('hardwareBackPress', this.backHandle);
}
async componentDidMount() {
const user = await loadToken();
this.props.dispatch(createAction('app/loadglobalvariable')({ user }));
}
componentWillUnmount() {
if (Platform.OS === 'android') {
BackHandler.removeEventListener('hardwareBackPress', this.backHandle);
JPushModule.removeReceiveCustomMsgListener(receiveCustomMsgEvent);
JPushModule.removeReceiveNotificationListener(receiveNotificationEvent);
JPushModule.removeReceiveOpenNotificationListener(openNotificationEvent);
JPushModule.removeGetRegistrationIdListener(getRegistrationIdEvent);
JPushModule.clearAllNotifications();
} else {
DeviceEventEmitter.removeAllListeners();
NativeAppEventEmitter.removeAllListeners();
}
}
backHandle = () => {
const currentScreen = getCurrentScreen(this.props.router);
//登录
if (currentScreen === 'Login') {
return true;
}
if (currentScreen !== 'Home') {
this.props.dispatch(NavigationActions.back());
return true;
}
return false;
}
render() {
if (!this.state.configload) {
return (
<View style={{ flex: 1 }}>
<StatusBar
barStyle="light-content"
/>
{/* <ScanNetConfig ScanSuccess={() => {
this.setState({ configload: true });
}}
/> */}
<Text>ScanNetConfig</Text>
</View>
);
}
const { dispatch, router } = this.props;
const navigation = addNavigationHelpers({ dispatch, state: router });
return (
<View style={{ flex: 1 }}>
<AppNavigator navigation={navigation} />
</View>
);
}
}
export function routerReducer(state, action = {}) {
return AppNavigator.router.getStateForAction(action, state);
}
export default Router;
Need More Detail?
this is the error.
bundling failed: SyntaxError in D:\RN\AtmosphericMeshing-\src\router.js: D:/RN/AtmosphericMeshing-/src/router.js: Unexpected token (16:0)
I find the Solution
.babelrc needs to be changed:
{
"presets": ["react-native"],
"plugins": [
"syntax-decorators",
"transform-decorators-legacy",
["import", { "libraryName": "antd-mobile" }]
]
}