React Native Map crash app when getting location - react-native

My project displays a react native map and asks for user location.
In development the application runs nickel without error or bug or slowdown while when I build the app and install it when the application crashes.
Demo1 : DEMO gif app in developpement npx expo start: works fine
Demo2 : DEMO gif app builded installed with apk: crash
I use :
"react-native": "0.70.5",
"expo": "~47.0.12"
"expo-location": "~15.0.1",
"#react-native-community/geolocation": "^3.0.4",
"react-native-maps": "^1.3.2",
My file that contains my map :
import React, { useEffect, useRef, useState } from "react";
import {
...
} from "react-native";
import { StatusBar } from "expo-status-bar";
import * as Location from "expo-location";
import MapView, { Marker } from "react-native-maps";
import { Alert } from "react-native";
const Planisphere = () => {
const [location, setLocation] = useState(null);
const [errorMsg, setErrorMsg] = useState(null);
const [mapRef, setMapRef] = useState(null);
const [locationAccepted, setLocationAccepted] = useState(false);
useEffect(() => {
(async () => {
let { status } = await Location.requestForegroundPermissionsAsync();
if (status !== "granted") {
setErrorMsg("Permission to access location was denied");
Alert.alert(
"Location Permission Denied",
"Please go to settings and enable location permission for this app to continue.",
[
{
text: "Go to Settings",
onPress: () => Linking.openSettings(),
},
]
);
return;
}
let subscription = await Location.watchPositionAsync(
{ accuracy: Location.Accuracy.BestForNavigation },
(location) => {
setLocation(location);
setLocationAccepted(true);
}
);
return () => subscription.remove();
})();
}, []);
const handleFindMyLocation = () => {
...
};
const handleUnzoom = () => {
...
};
let text = "Waiting..";
if (errorMsg) {
text = errorMsg;
} else if (location) {
text = JSON.stringify(location);
}
return (
<View style={styles.container}>
<StatusBar style="auto" />
{location && (
<MapView
ref={(ref) => setMapRef(ref)}
style={styles.map}
minZoomLevel={8}
maxZoomLevel={18}
initialRegion={{
latitude: location.coords.latitude,
longitude: location.coords.longitude,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}
>
<Marker
coordinate={{
latitude: location.coords.latitude,
longitude: location.coords.longitude,
}}
title={"Your location"}
/>
</MapView>
)}
<Text style={styles.paragraph}>{text}</Text>
{locationAccepted && (
<View>
<Button title="Find my location" onPress={handleFindMyLocation} />
<Button title="Unzoom" onPress={handleUnzoom} />
</View>
)}
</View>
);
};
const styles = StyleSheet.create({
...
});
export default Planisphere;
My file ask location and when its authorized, the map appear.
UPDATE :
useEffect(() => {
const fetchPermission = async () => {
try {
const { status } = await Location.requestForegroundPermissionsAsync();
setPermissions(status);
if (status !== "granted") {
setErrorMsg("Permission to access location was denied");
}
} catch (err) {
setErrorMsg(err.message);
}
};
fetchPermission();
}, []);
useEffect(() => {
const fetchLocation = async () => {
if (permissions === "granted") {
const watcher = await Location.watchPositionAsync(
{ accuracy: Location.Accuracy.BestForNavigation },
(location) => {
setLocation(location);
setLocationAccepted(true);
}
);
setSubscription(watcher);
}
};
fetchLocation();
return () => {
if (subscription) {
subscription.remove();
}
};
}, [permissions]);
AndroidManifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.flokitoto.mapauthentificate">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<queries>
<intent>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="https"/>
</intent>
</queries>
<application android:name=".MainApplication" android:label="#string/app_name" android:icon="#mipmap/ic_launcher" android:roundIcon="#mipmap/ic_launcher_round" android:allowBackup="true" android:theme="#style/AppTheme" android:usesCleartextTraffic="true">
<meta-data android:name="expo.modules.updates.ENABLED" android:value="true"/>
<meta-data android:name="expo.modules.updates.EXPO_SDK_VERSION" android:value="47.0.0"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://exp.host/#flokitoto/mapauthentificate"/>
<activity android:name=".MainActivity" android:label="#string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="#style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="com.flokitoto.mapauthentificate"/>
<data android:scheme="com.flokitoto.mapauthentificate"/>
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false"/>
</application>
</manifest>
Update:
Error from logs:
FATAL EXCEPTION: expo-updates-error-recovery
java.lang.RuntimeException: API key not found. Check that <meta-data android:name="com.google.android.geo.API_KEY" android:value="your API key"/> is in the <application> element of AndroidManifest.xml
FATAL EXCEPTION: expo-updates-error-recovery
Process: com.flokitoto.mapauthentificate, PID: 14044
java.lang.RuntimeException: API key not found. Check that <meta-data android:name="com.google.android.geo.API_KEY" android:value="your API key"/> is in the <application> element of AndroidManifest.xml

From the error
FATAL EXCEPTION: expo-updates-error-recovery
java.lang.RuntimeException: API key not found. Check that <meta-data android:name="com.google.android.geo.API_KEY" android:value="your API key"/> is in the <application> element of AndroidManifest.xml
FATAL EXCEPTION: expo-updates-error-recovery
Process: com.flokitoto.mapauthentificate, PID: 14044
java.lang.RuntimeException: API key not found. Check that <meta-data android:name="com.google.android.geo.API_KEY" android:value="your API key"/> is in the <application> element of AndroidManifest.xml
I see that problem is in the API key for google maps
https://github.com/react-native-maps/react-native-maps/blob/master/docs/installation.md#specify-your-google-maps-api-key

Related

Getting never_ask_again by default on react native when I ask for location

This is the function that asks for permission and it logs to the console: never_ask_again automatically
requestCameraPermission = async () => {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
{
title: "Cool Photo App Camera Permission",
message:
"Cool Photo App needs access to your camera " +
"so you can take awesome pictures.",
buttonNeutral: "Ask Me Later",
buttonNegative: "Cancel",
buttonPositive: "OK"
}
);
console.log(await
PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION))
} catch (err) {
console.warn(err);
}
};
this is my androidManifest.xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />

React Admin: how to fix endless loading in Create

I'm stuck in endless loading when Create some post "contents" with REST API
there is no error, 200 ok response, and success to POST
but still in loading status, after receive 200 ok
so, I can't chack error massage just loading...
when I go to list manually, there is created new post
every thing working in backend, but loading is not stop..
I try to use onSuccess, but onSuccess does not start
I guess submission is not end..
help me!
edit : Here is more code! I'm still stuck in loading..
other post(ex.Themes) is created successfully! but contents is not..!
this is my dataprovider
getOne: async (resource, params) => {
if (resource === "themes" || resource === "curriculums") {
const { json } = await httpClient(`${PROXY}/${resource}/${params.id}`);
return {
data: json,
};
} else {
const { json: json_1 } = await httpClient(
`${PROXY}/${resource}/${params.id}`
);
return {
data: {
id: json_1.id,
title: json_1.title,
category: json_1.category,
type: json_1.type,
description: json_1.description,
thumbnail: JSON.parse(json_1.metadata).thumbnail,
files: JSON.parse(json_1.metadata).files,
createdDate: json_1.createdDate,
modifiedDate: json_1.modifiedDate,
},
};
}
},
const getFormData = (object) => {
let formData = new FormData();
Object.getOwnPropertyNames(object).forEach((key) => {
if (key === "files") {
let fileData = object[key];
let i,
j = 0;
for (i = 0, j = fileData.length; i < j; i += 1) {
formData.append(key, fileData[i]);
}
} else {
formData.append(key, object[key]);
}
});
return formData;
};
create: async (resource, params) => {
if (resource !== "contents") {
// console.log(params);
const json = await httpClient(`${PROXY}/${resource}`, {
method: "POST",
body: JSON.stringify(params.data),
});
return {
data: { ...params.data, id: json.body },
};
} else {
const formedData = getFormData(params.data);
// for (var pair of formedData.entries()) {
// console.log(pair[0] + ", " + pair[1]);
// }
const json_1 = await httpClient2(`${PROXY}/${resource}`, {
method: "POST",
body: formedData,
});
return {
data: { ...params.data, id: json_1.body },
};
}
},
this is extanding dataprovider
create: (resource, params) => {
if (resource !== "contents" || !params.data.metadata.rawFile) {
// fallback to the default implementation
return dataProvider.create(resource, params);
} else {
const newPictures = params.data.metadata.rawFile;
let transFiles = [];
if (params.data.files) {
const newFiles = params.data.files.filter(
(p) => p.rawFile instanceof File
);
newFiles.map((f) => (transFiles = transFiles.concat(f.rawFile)));
}
// console.log(transFiles);
return new Promise(() => {
dataProvider.create(resource, {
...params,
data: {
title: params.data.title,
type: params.data.type,
category: params.data.category,
description: params.data.description,
thumbnail: newPictures,
files: transFiles,
},
});
});
}
},
};
this is Posts.js code
export const PostShow = (props) => (
<Show title={<PostTitle />} {...props}>
<SimpleShowLayout>
<TextField source="id" />
<TextField source="title" />
<TextField source="category" />
<TextField source="type" />
<TextField source="description" />
<ImageField source="thumbnail">
<FunctionField
label="Image"
render={(record) => {
return <img src={record.thumbnail} alt="thumbnail" />;
}}
/>
</ImageField>
<FilesField source="files" />
<DateField label="Publication date" source="createdDate" />
<DateField label="Modified date" source="modifiedDate" />
</SimpleShowLayout>
</Show>
);
export const PostEdit = (props) => {
return (
<Edit {...props}>
<SimpleForm>
<TextInput disabled source="id" />
<TextInput source="title" />
<TextInput source="category" />
<TextInput source="type" />
<TextInput multiline source="description" />
<ImageInput
source="metadata"
label="thumbnail"
accept="image/*"
placeholder={<p>Drop your thumbnail here</p>}>
<ImageField source="src" />
</ImageInput>
<FileInput source="files" label="Related files" multiple={true}>
<FileField source="src" title="title" />
</FileInput>
</SimpleForm>
</Edit>
);
};
export const PostCreate = (props) => {
return (
<Create {...props}>
<SimpleForm redirect="list">
<TextInput source="title" />
<TextInput source="category" />
<TextInput source="type" />
<TextInput multiline source="description" />
<ImageInput
source="metadata"
label="thumbnail"
accept="image/*"
placeholder={<p>Drop your thumbnail here</p>}
validate={required()}>
<ImageField source="src" />
</ImageInput>
<FileInput source="files" label="Related files" multiple={true}>
<FileField source="src" title="title" />
</FileInput>
</SimpleForm>
</Create>
);
};
this is my App.js
const App = () => {
return (
<Admin authProvider={authProvider} dataProvider={myDataProvider}>
<Resource
name="contents"
list={PostList}
show={PostShow}
edit={PostEdit}
create={PostCreate}
/>
<Resource
name="themes"
list={ThemeList}
show={ThemeShow}
create={ThemeCreate}
/>
<Resource
name="curriculums"
list={CurriculumList}
show={CurriculumShow}
create={CurriculumCreate}
/>
</Admin>
);
};
export default App;
this is my Themes.js
export const ThemeShow = (props) => (
<Show {...props} title={<ThemeTitle />}>
<SimpleShowLayout>
<TextField source="id" />
<TextField source="title" />
<ArrayField source="contents">
<Datagrid>
<TextField source="id" />
<TextField source="title" />
<TextField source="category" />
<TextField source="type" />
<TextField source="description" />
</Datagrid>
</ArrayField>
<DateField label="Publication date" source="createdDate" />
</SimpleShowLayout>
</Show>
);
export const ThemeCreate = (props) => {
const validateInput = required();
const optionRenderer = (choice) => `${choice.id} (${choice.title})`;
return (
<Create {...props}>
<SimpleForm>
<TextInput source="title" validate={validateInput} />
<ReferenceInput
source="contentIds"
reference="contents"
validate={validateInput}>
<SelectArrayInput optionText={optionRenderer} />
</ReferenceInput>
</SimpleForm>
</Create>
);
};
this is my version
"react": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1"
}
},
"react-admin": {
"version": "3.16.4",
"resolved": "https://registry.npmjs.org/react-admin/-/react-admin-3.16.4.tgz",
"integrity": "sha512-l7HEFXmjwqcfuKV0eB3SFPjT/7kP7LjGci4YoPHmy9EFzNtR7uyh2WeCNmgSryTStyu6zKijE/2yRPdfvDhSUw==",
"requires": {
"#material-ui/core": "^4.11.2",
"#material-ui/icons": "^4.11.2",
"#material-ui/styles": "^4.11.2",
"connected-react-router": "^6.5.2",
"final-form": "^4.20.2",
"final-form-arrays": "^3.0.2",
"ra-core": "^3.16.3",
"ra-i18n-polyglot": "^3.16.3",
"ra-language-english": "^3.16.3",
"ra-ui-materialui": "^3.16.3",
"react-final-form": "^6.5.2",
"react-final-form-arrays": "^3.1.3",
"react-redux": "^7.1.0",
"react-router": "^5.1.0",
"react-router-dom": "^5.1.0",
"redux": "^3.7.2 || ^4.0.3",
"redux-saga": "^1.0.0"
}
},

React-Native-Image-Picker: How do I restrict user to upload video more than given length?

Can I do something to restrict a user to upload a video of duration more than 300 seconds? Either the bigger videos should be trimmed to 300s or the videos more than 300s should be disabled. I use durationLimit prop which is not working for android. I have used the following versions of this library:
"react-native-image-picker": "^2.3.4"
Then
"react-native-image-picker": "^3.5.0",
Then
"react-native-image-picker": "^4.0.2",
Neither working for me
import ImagePicker from "react-native-image-picker";
const uploadVideo = async () => {
activateKeepAwake();
let options = {
title: "Select video",
takePhotoButtonTitle: null,
mediaType: "video",
path: "video",
quality: 1,
videoQuality: "normal",
durationLimit: 300,
allowsEditing: true,
};
ImagePicker.showImagePicker(options, async (response) => {
if (response.didCancel) {
console.log("User cancelled image picker");
} else if (response.error) {
console.log("ImagePicker Error: ", response.error);
} else if (response.customButton) {
console.log("User tapped custom button: ", response.customButton);
} else {
if (response && response.uri) {
let selectedUri;
let videoFilePath;
let selectedFileUri = response.uri;
setVideoLoader(true);
setModalAddVisible(false);
if (
Platform.OS === "ios" &&
(selectedFileUri.includes(".mov") ||
selectedFileUri.includes(".MOV"))
) {
videoFilePath = await handleConvertToMP4(selectedFileUri);
selectedUri = "file://" + videoFilePath.path;
} else {
selectedUri =
Platform.os === "ios"
? selectedFileUri
: "file://" + response.path;
}
setVideoSource(null);
setVideoSource(selectedUri);
await createThumbnailForVideos(selectedUri, 1);
var filename = selectedUri.substring(
selectedUri.lastIndexOf("/") + 1,
selectedUri.length
);
const file = {
uri: selectedUri,
name: selectedGroup.id + "-dev-" + filename,
};
uploadVideoOnS3(file, "video");
}
}
});
};
Here are my android permissions:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
According to the official documentation, the durationLimit prop works for already recorded video but not for live recording the video. Reference: https://github.com/react-native-image-picker/react-native-image-picker/issues/1738

How to pass some data to Android App from the browser in react-native

I want to open android app form the browser and pass some data .
I did the following, In javascript :
<a href="my.special.scheme://adny/max/120">
Open Android Application ....
</a>
React-native, AndroidManifest.xml
<intent-filter>
<data android:scheme="my.special.scheme" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
and finally, in the component, to get data :
useEffect(() => {
Linking.getInitialURL()
.then((url) => {
console.log(url) // here I want to get parameters like (andy, max, 120)
}).catch(err => console.error('An error occurred ', err))
}, []);
any help would be appreciated.
You can see here an example of how to set-up your app to support Deep-linking.
On the tutorial, it's done this way:
import React from 'react';
import { Platform, Text, Linking } from 'react-native';
class Home extends React.Component {
static navigationOptions = {
title: 'Home',
};
componentDidMount() {
if (Platform.OS === 'android') {
Linking.getInitialURL().then(url => {
this.navigate(url);
});
} else {
Linking.addEventListener('url', this.handleOpenURL);
}
}
componentWillUnmount() {
Linking.removeEventListener('url', this.handleOpenURL);
}
handleOpenURL = (event) => {
this.navigate(event.url);
}
navigate = (url) => {
const { navigate } = this.props.navigation;
const route = url.replace(/.*?:\/\//g, '');
const id = route.match(/\/([^\/]+)\/?$/)[1];
const routeName = route.split('/')[0];
if (routeName === 'people') {
navigate('People', { id, name: 'chris' })
};
}
render() {
return <Text>Hello from Home!</Text>;
}
}
export default Home;

React Navigation 4 Deep Linking is not working

I am using react-navigation-4. I was in expo and ejected from that using bare workflow.
Now I want to use deep linking so that when I want to click on a notification, it goes to a certain screen in my app.
I followed the instructions in https://reactnavigation.org/docs/4.x/deep-linking but when I using Linking.openURL("rnfarmer://submitrating/dd"); to open screen, nothing happens.
This is my App.js :
import React from "react";
import MyNavigator from "./navigation/MyNavigator";
export default function App() {
const prefix = 'rnfarmer://';
return <MyNavigator uriPrefix={prefix} />;
}
This is MyNavigator.js file :
...
export default createAppContainer(createStackNavigator({SubmitRating: {
screen: SubmitRatingScreen,
path: 'submitrating/:orderId'
}}));
and also I've added these lines to AndroidManifest.xml :
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="rnfarmer" />
</intent-filter>
Finally I found the answer.
I am using DrawerNavigator so I have a nested navigation and because of that I should add path to parent navigator and then to the child.
EDIT
Example :
This is your Main Navigator:
const MainNavigator = createDrawerNavigator({
MainNav: {
screen: FarmerNavigator,
path: "main"
} ,
ProfileNav: FillProfileNavigator,
MyOrdersNav: MyOrdersNavigator,
RatingNav: RatingNavigator,
RulesNav: RulesNavigator,
AboutAppNav: AbouAppNavigator
}, {
drawerPosition: "right",
contentComponent: DrawerContent,
contentOptions: {
activeTintColor: FarmerColors.colorPrimary,
itemsContainerStyle: {
marginVertical: 0,
},
iconContainerStyle: {
opacity: 1
}
}
});
And this is your Farmer Navigator:
const AsanZeraatNavigator = createStackNavigator({
ShowLand: ShowLandScreen,
ShowOrder: {
screen: ShowOrderScreen,
path: 'showorder/:params'
},
SubmitRating: {
screen: SubmitRatingScreen,
path: 'submitrating/:params',
}
});