Follow user walking using react-native-maps and expo-location - android

I'm currently developing an university project in React Native (android app).
My goal in this component is to render a map where you can see your location, and it follows you as you walk.
Problem 1: there's a MapView props named followsUserLocation, but it only works on Apple devices. How can I do it on an android phone?
Problem 2: I'm saving the location on a state in order to reuse it everywhere else, but the Location object is empty on first render (or takes a second or two to get the location info from the emulator). Whenever I use the state where I saved that info I get an error since I have this delay.
Here's my location useEffect:
export default function App() {
const [userLocation, setUserLocation] = useState({})
const [isLoading, setIsLoading] = useState(false)
const mapRef = React.createRef();
React.useEffect(() => {
(async () => {
setIsLoading(true);
let { status } = await Location.requestForegroundPermissionsAsync();
if (status !== "granted") {
console.log("Permission to access location was denied");
return;
}
let location = await Location.getCurrentPositionAsync({
accuracy: Location.Accuracy.Balanced,
enableHighAccuracy: true,
timeInterval: 1,
});
//console.log(location);
//console.log(location.coords.latitude);
setUserLocation(location)
setIsLoading(false);
})();
}, []);
I'm new in React Native, thank you for you patience! :)

You can't rely on followsUserLocation it's iOS-specific and not offers more flexibility.
Ideally, a Custom Location maker is required which indicates the current user's location as she moves.
The expo-location package provides Location.watchPositionAsync(options, callback) method which continuously dispatches new user location information when she moves.
With this new information, you can update the location marker in realtime.

Related

expo-camera takePictureAsync() not working on Android

I recently updated several lines of code in a managed expo project, unrelated to the camera functionality. It still works fine on iOS, only Android does not work. I had released a previous version one month ago that worked well. When I revert back to the old commit from then, though, it also does not work on Android (iOS fine).
expo 44.0.6
expo-camera 12.1.2
react 17.0.1
react-native 0.64.3
There is no issue launching the camera, etc. Rather, the issue occurs at takePictureAsync, which hangs and then does not return anything.
const snapPic = async () => {
const { status } = await Camera.getCameraPermissionsAsync();
if (status != 'granted') {
alert('Please grant access to camera and retry.');
await Camera.requestCameraPermissionsAsync();
return;
}
const options = { quality: 0.1 };
const photo = await this.camera.takePictureAsync(options);
this.camera.pausePreview();
this.setState({imageSource: photo.uri});
};
<Camera style={styles.cameraBox} ref={ref => {this.camera = ref}} />
Please let me know what other information I can provide, if necessary. Thanks in advance!
Instead of pause preview method. Try it with skipProcessing to false inside option object

React native: requestTechnology called only if the app is brought from background to foreground

I am currently working on a simple app for scanning, reading data from an NFC card (in my case a Mifare NFC card) and displaying in on the screen. I have built it using this example.
The app should work both on Android and iOS, but for the moment, I have tested it only on an android device (an Oppo device with NFC capablities and developer mode activated).
At the launch of the app, everything seems to be working fine, the NfcManager has been successfully started, but there is an issue when the app tries to request the technology for reading the card, namely, I have to bring the app first in the background and then again in the foreground so that the message requestTechnology success is displayed, otherwise, it's simply not called.
After this, the promise NfcManager.getTag() gets rejected with the error message: no reference available.
Here is my code:
componentDidMount() {
NfcManager.start({
onSessionClosedIOS: () => {
alert('ios session closed');
},
}).then(() => console.warn('NfcManager started')) // successfully started
.catch((error) => alert('Error starting NfcManager: ', error));
}
{... componentWillUnmount and render method ...}
_read = async () => {
try {
let tech = Platform.OS === 'ios'
? NfcTech.MifareIOS : [NfcTech.MifareClassic, NfcTech.NfcA, NfcTech.IsoDep, NfcTech.Ndef];
let resp = await NfcManager.requestTechnology(tech, {
alertMessage: 'Ready to do some custom Mifare cmd!'
})
.then((value) => alert('requestTechnology success', value)) // here the value is empty, so no NfcTech
.catch(() => console.warn('reuqestTechnology error'));
const tag = await NfcManager.getTag()
.then((value) => alert('Tag event: ', value))
.catch((err) => console.warn('error getting tag: ', err));
// this part of the code is reached, but not working properly since the tag.id is not correctly retrieved
if (Platform.OS === 'ios') {
resp = await NfcManager.sendMifareCommandIOS([0x30, 0x00]);
} else {
resp = await NfcManager.transceive([0x30, 0x00]);
}
console.warn('Response: ', resp);
this._cleanUp();
} catch (ex) {
console.warn(ex);
this._cleanUp();
}
}
If I scan the card against the device, it makes the sound like it has been scanned, but nothing seems to be displayed.
Does anyone know why does the app needs to be brought to the background so that the technology is requested? And second, does the fail of the getTag() method have anything to do with it?
I hope anyone can help me with this issue, I have been struggling with this problem for quite some time and I haven't found any solution.
May be related to github.com/revtel/react-native-nfc-manager/issues/423 ?? there seems to be a scenario where this package does not correctly configure enableForegroundDispatch and manually pausing and resuming the App by sending it to the background would fix it.

Using coordinates in ionic LaunchNavigator.navigate instead of city text

i'm trying to load a navigator app from my ionic application to show directions and i am using google maps, but the problem is that i am using the launchNavigator function which only accepts a string - the name of the location.
navigateLocation(){
let options: LaunchNavigatorOptions = {
start:[this.latitude,this.longitude],
app: this.launchNavigator.APP.GOOGLE_MAPS
};
this.launchNavigator.navigate('Lagos, ON', options) //here
.then(success =>{
console.log(success);
},error=>{
console.log(error);
})
}
so the Lagos option, could be london, or any other city, but what if i'm trying to get a remote location, or some other city.
why cant i just use the longitude and latitude, instead of the name..
for example
this.launchNavigator.navigate({lat:8.234345, lng:7:5644563}, 'ON', options);
something similar to that....
i dont know if anyone has done this before, please help.
thanks.
I use it like this
let destination = [lat, lng];
this.launchNavigator.navigate(destination)
.then(
success => console.log('Launched navigator'),
error => console.log('Error launching navigator', error)
);
And it shows me how do i go from where I am to the coordinates I pass.

Device GPS configuration in react-native

I'm developing a react-native app and I want to check that if the GPS of device is on do something and if the device's GPS is off, tell the user and request him to turn it on. So my question is:
How can I check that the GPS of device is on?
How can I redirect the user to GPS setting page?
I want to do these without adding any new package to project.
My problem is solved. I should use the error code of the getCurrentPosition function. If error code equals 1, it means that the GPS of device is off.
navigator.geolocation.getCurrentPosition(
(position) => {
...
},
(error) => {
if (error.code === 1) {
// gps is off
}
...
},
{enableHighAccuracy: false, timeout: 10000},
)

Follow user location on React Native AirBnb's MapView [Android]

I'm using airbnb's map for react-native on my app. This question is for the android app since I didn't get around the iOS app yet.
My problem:
navigator.geolocation works fine on emulator, but takes too long on real devices, to the point it sometimes times out on older devices.
What I've noticed:
if showsUserLocation prop is set to true, I can see the native "current position" marker on the map way before getCurrentPosition resolves.
What I want:
I want my region to always be centered on the user's location.
I want either a way to access native geolocation api (should be
faster?), or maybe someone to tell me what I'm doing wrong. Below is
a code sample.
I want to still be able to detect the user's location even after the location services have been toggled on/off. This is the behaviour of the showsUserLocation prop, but it seems once watchPostion errors, it stops completely.
Here's what I have so far, it's very simple as it is:
componentDidMount() {
navigator.geolocation.getCurrentPosition(
(position) => {
console.log("getCurrentPosition Success");
this.setState({
region: {
...this.state.region,
latitude: position.coords.latitude,
longitude: position.coords.longitude,
}
});
this.props.resetNotifications();
this.watchPosition();
},
(error) => {
this.props.displayError("Error dectecting your location");
alert(JSON.stringify(error))
},
{enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
);
}
watchPosition() {
this.watchID = navigator.geolocation.watchPosition(
(position) => {
console.log("watchPosition Success");
if(this.props.followUser){
this.map.animateToRegion(this.newRegion(position.coords.latitude, position.coords.longitude));
}
},
(error) => {
this.props.displayError("Error dectecting your location");
},
{enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
);
}
I have always found watchPosition iffy between different browsers, one thing that worked for me before is to replace with getCurrentPosition inside a setInterval so that it will get the location every few seconds, and if it fails once it will retry next interval, unlike watchPosition which stops watching if an error occurs.
Generally browser geolocation is not very reliable, you can check this thread for some issues https://github.com/facebook/react-native/issues/7495
Another alternative which will definitely be faster and maybe more reliable is to use the native geolocation API. Check this question for libraries that expose native geolocation for react native React-native Android geolocation
Not sure if this will solve your issue but try this:
navigator.geolocation.getCurrentPosition(
(position) => {
console.log("getCurrentPosition Success");
this.setState({
region: {
...this.state.region,
latitude: position.coords.latitude,
longitude: position.coords.longitude,
}
}, () => {
this.props.resetNotifications();
this.watchPosition();
});
},

Categories

Resources