That is one in all my first posts ever. Once I’m caught I normally simply hit my head in opposition to a wall, however at the moment I am asking for assist. I’ve acquired a ReactNative app constructed utilizing Expo which does some realtime location monitoring. Which works when the element is energetic on the display, however when the app goes into the background, it stops functioning. I’ve tried to implement a background activity utilizing expo-task-manager, however for the lifetime of me I can not seem to get it to work. I’ve carried out it to make use of haptics to inform me that it is functioning correctly whereas testing within the area, and whereas it appears to work okay on the simulator (I get the console.log not less than), the true machine solely buzzes when the element is energetic and on display. I’m able to see the blue indicator when the app just isn’t energetic, however no haptics.
Can somebody determine what I’ve missed right here? Thanks a lot prematurely.
This is my code:
import React, { useState, useEffect } from 'react';
import { Textual content, View, Button } from 'react-native';
import * as Location from 'expo-location';
import * as TaskManager from 'expo-task-manager';
import * as Haptics from 'expo-haptics';
const DESTINATION_COORDS = {
latitude: 44.0041179865438,
longitude: -121.68169920997431,
};
const BACKGROUND_LOCATION_TASK = 'background-location-task-buzz-v2';
TaskManager.defineTask(BACKGROUND_LOCATION_TASK, async ({ information, error }) => {
if (error) {
console.error('Background location activity error:', error.message);
return;
}
const { places } = information;
if (places && places.size > 0) {
const { latitude, longitude } = places[0].coords;
const distance = calculateDistance(
latitude,
longitude,
DESTINATION_COORDS.latitude,
DESTINATION_COORDS.longitude
);
if (distance < 10) {
await triggerHaptics();
console.log('discovered it.', Date.now());
}
}
});
const calculateDistance = (lat1, lon1, lat2, lon2) => {
const R = 6371; // Radius of the earth in km
const dLat = deg2rad(lat2 - lat1); // deg2rad beneath
const dLon = deg2rad(lon2 - lon1);
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2)
;
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const d = R * c; // Distance in km
return d * 1000; // Convert to meters
};
const deg2rad = (deg) => {
return deg * (Math.PI / 180);
};
const triggerHaptics = async () => {
await Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
};
const BuzzOnArrival = () => {
const [currentLocation, setCurrentLocation] = useState(null);
const [distanceToDestination, setDistanceToDestination] = useState(null);
useEffect(() => {
// Begin background location updates when element mounts
Location.startLocationUpdatesAsync(BACKGROUND_LOCATION_TASK, {
accuracy: Location.Accuracy.BestForNavigation,
timeInterval: 10000, // Verify each 10 seconds
distanceInterval: 0,
showsBackgroundLocationIndicator: true,
});
// Clear up operate to cease background location updates when element unmounts
return () => {
Location.stopLocationUpdatesAsync(BACKGROUND_LOCATION_TASK);
};
}, []);
useEffect(() => {
// Fetch present location each second
const interval = setInterval(() => {
fetchCurrentLocation();
}, 1000);
// Clear up operate to clear the interval when element unmounts
return () => clearInterval(interval);
}, []);
const requestPermissions = async () => {
const { standing: foregroundStatus } = await Location.requestForegroundPermissionsAsync();
if (foregroundStatus === 'granted') {
const { standing: backgroundStatus } = await Location.requestBackgroundPermissionsAsync();
if (backgroundStatus === 'granted') {
await Location.startLocationUpdatesAsync(LOCATION_TASK_NAME, {
accuracy: Location.Accuracy.Balanced,
});
}
}
};
const fetchCurrentLocation = async () => {
const location = await Location.getCurrentPositionAsync({});
setCurrentLocation(location.coords);
// Calculate distance to vacation spot
const distance = calculateDistance(
location.coords.latitude,
location.coords.longitude,
DESTINATION_COORDS.latitude,
DESTINATION_COORDS.longitude
);
setDistanceToDestination(distance);
};
const handleButtonPress = async () => {
await triggerHaptics();
};
return (
<View model={{ flex: 1, justifyContent: 'middle', alignItems: 'middle' }}>
<Textual content>Listening for arrival...</Textual content>
{currentLocation && (
<Textual content>Present Location: {currentLocation.latitude}, {currentLocation.longitude}</Textual content>
)}
<Textual content>Vacation spot: {DESTINATION_COORDS.latitude}, {DESTINATION_COORDS.longitude}</Textual content>
<Textual content>Distance to Vacation spot: {distanceToDestination?.toFixed(2)} meters</Textual content>
<Button title="Check Haptics" onPress={handleButtonPress} />
<Button onPress={requestPermissions} title="Allow background location" />
</View>
);
};
export default BuzzOnArrival;
And right here is my bundle.json:
{
"identify": "geocaster",
"model": "1.0.0",
"essential": "expo-router/entry",
"scripts": {
"begin": "expo begin",
"android": "expo run:android",
"ios": "expo run:ios",
"internet": "expo begin --web"
},
"dependencies": {
"@gorhom/bottom-sheet": "^4.6.1",
"@react-native-async-storage/async-storage": "1.21.0",
"@reduxjs/toolkit": "^2.0.1",
"@supabase/supabase-js": "^2.39.3",
"base64-arraybuffer": "^1.0.2",
"expo": "~50.0.2",
"expo-av": "~13.10.3",
"expo-background-fetch": "^11.8.1",
"expo-camera": "~14.0.1",
"expo-constants": "~15.4.5",
"expo-crypto": "~12.8.0",
"expo-file-system": "~16.0.6",
"expo-haptics": "~12.8.1",
"expo-image-picker": "~14.7.1",
"expo-linking": "~6.2.2",
"expo-location": "~16.5.2",
"expo-media-library": "~15.9.1",
"expo-notifications": "~0.27.5",
"expo-router": "~3.4.4",
"expo-secure-store": "~12.8.1",
"expo-sensors": "~12.9.1",
"expo-status-bar": "~1.11.1",
"expo-task-manager": "~11.7.0",
"expo-updates": "~0.24.12",
"expo-web-browser": "~12.8.2",
"firebase": "^10.7.1",
"geolib": "^3.3.4",
"jszip": "^3.10.1",
"jszip-utils": "^0.1.0",
"lucide-react-native": "^0.314.0",
"pullstate": "^1.25.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-native": "0.73.2",
"react-native-draggable-flatlist": "^4.0.1",
"react-native-easy-grid": "^0.2.2",
"react-native-gesture-handler": "^2.16.0",
"react-native-maps": "1.8.0",
"react-native-paper": "^5.12.1",
"react-native-progress": "^5.0.1",
"react-native-reanimated": "^3.8.1",
"react-native-safe-area-context": "4.8.2",
"react-native-screens": "~3.29.0",
"react-native-snap-carousel": "^3.9.1",
"react-native-svg": "14.1.0",
"react-native-web": "~0.19.6",
"react-redux": "^9.1.0",
"redux": "^5.0.1"
},
"devDependencies": {
"@babel/core": "^7.20.0"
},
"personal": true
}
I additionally am offering what I imagine is the related components of my app.json:
{
"expo": {
...
"ios": {
...,
"infoPlist": {
"UIBackgroundModes": ["location", "fetch"],
"NSLocationAlwaysAndWhenInUseUsageDescription": "Placeholder",
"NSLocationAlwaysUsageDescription": "Placeholder",
"NSLocationWhenInUseUsageDescription": "Placeholder",
}
},
...,
"plugins": [
"expo-router",
"expo-secure-store",
[
"expo-location",
{
"locationAlwaysAndWhenInUsePermission": "Placeholder",
"isAndroidBackgroundLocationEnabled": true,
"isIosBackgroundLocationEnabled": true
}
],
],
...
}
}
and even my Data.plist:
<key>NSLocationUsageDescription</key>
<string>Use of location for figuring out waypoints and proximity</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Use of location for determing waypoints and proximity</string>
<key>NSMicrophoneUsageDescription</key>
<string>The Microphone might be used to document movies for waypoints.</string>
<key>NSMotionUsageDescription</key>
<string>The of movement sensors required for the compass.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>The photograph library can be utilized to pick photos and movies for add.</string>
<key>NSUserActivityTypes</key>
<array>
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
</array>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
<string>fetch</string>
</array>
I am centered on iOS for the second so have solely examined it there. I’ve tried working with it within the simulator, and on actual gadgets. The code above buzzes when the element is energetic, however not when it is within the background.
I’d anticipate it to buzz as I get inside about ten meters of the DESTINATION_COORDS, whether or not I’ve the app within the foreground OR within the background.
Proper now it solely buzzes when the app is within the foreground and the element is actively on the display.