Фоновая задача expo-task-manager не запускается в фоновом режиме на iOSIOS

Программируем под IOS
Ответить
Anonymous
 Фоновая задача expo-task-manager не запускается в фоновом режиме на iOS

Сообщение Anonymous »

Это одна из моих первых публикаций. Когда я застреваю, я обычно просто ударяюсь головой о стену, но сегодня я прошу о помощи. У меня есть приложение ReactNative, созданное с использованием Expo, которое выполняет мониторинг местоположения в реальном времени. Это работает, когда компонент активен на экране, но когда приложение уходит в фон, оно перестает работать. Я попытался реализовать фоновую задачу с помощью expo-task-manager, но, хоть убей, не могу заставить ее работать. Я реализовал его, чтобы использовать тактильные ощущения, чтобы уведомить меня о том, что оно работает правильно во время тестирования в полевых условиях, и хотя на симуляторе оно работает нормально (по крайней мере, я получаю console.log), реальное устройство гудит только тогда, когда компонент активен и на экране. Я вижу синий индикатор, когда приложение неактивно, но нет тактильных ощущений.
Может кто-нибудь понять, что я здесь пропустил? Заранее большое спасибо.
Вот мой код:

Код: Выделить всё

import React, { useState, useEffect } from 'react';
import { Text, 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 ({ data, error }) => {
if (error) {
console.error('Background location task error:', error.message);
return;
}

const { locations } = data;
if (locations && locations.length > 0) {
const { latitude, longitude } = locations[0].coords;
const distance = calculateDistance(
latitude,
longitude,
DESTINATION_COORDS.latitude,
DESTINATION_COORDS.longitude
);
if (distance < 10) {
await triggerHaptics();
console.log('found it.', Date.now());
}
}
});

const calculateDistance = (lat1, lon1, lat2, lon2) => {
const R = 6371; // Radius of the earth in km
const dLat = deg2rad(lat2 - lat1);  // deg2rad below
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(() => {
// Start background location updates when component mounts
Location.startLocationUpdatesAsync(BACKGROUND_LOCATION_TASK, {
accuracy: Location.Accuracy.BestForNavigation,
timeInterval: 10000, // Check every 10 seconds
distanceInterval: 0,
showsBackgroundLocationIndicator: true,
});

// Clean up function to stop background location updates when component unmounts
return () => {
Location.stopLocationUpdatesAsync(BACKGROUND_LOCATION_TASK);
};
}, []);

useEffect(() => {
// Fetch current location every second
const interval = setInterval(() => {
fetchCurrentLocation();
}, 1000);

// Clean up function to clear the interval when component unmounts
return () => clearInterval(interval);
}, []);

const requestPermissions = async () => {
const { status: foregroundStatus } = await Location.requestForegroundPermissionsAsync();
if (foregroundStatus === 'granted') {
const { status: 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 destination
const distance = calculateDistance(
location.coords.latitude,
location.coords.longitude,
DESTINATION_COORDS.latitude,
DESTINATION_COORDS.longitude
);
setDistanceToDestination(distance);
};

const handleButtonPress = async () => {
await triggerHaptics();
};

return (

Listening for arrival...
{currentLocation &&  (
Current Location: {currentLocation.latitude}, {currentLocation.longitude}
)}
Destination: {DESTINATION_COORDS.latitude}, {DESTINATION_COORDS.longitude}
Distance to Destination: {distanceToDestination?.toFixed(2)} meters



);
};

export default BuzzOnArrival;

А вот мой package.json:

Код: Выделить всё

{
"name": "geocaster",
"version": "1.0.0",
"main": "expo-router/entry",
"scripts": {
"start": "expo start",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --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"
},
"private": true
}

Я также предоставляю, по моему мнению, соответствующие части моего 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
}
],
],
...
}
}

и даже мой Info.plist:

Код: Выделить всё

        NSLocationUsageDescription
Use of location for determining waypoints and proximity
NSLocationWhenInUseUsageDescription
Use of location for determing waypoints and proximity
NSMicrophoneUsageDescription
The Microphone will be used to record videos for waypoints.
NSMotionUsageDescription
The of motion sensors required for the compass.
NSPhotoLibraryUsageDescription
The photo library can be used to select images and videos for upload.
NSUserActivityTypes

$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route

UIBackgroundModes

location
fetch


На данный момент я сосредоточен на iOS, поэтому тестировал ее только там. Я пробовал работать с ним и в симуляторе, и на реальных устройствах. Приведенный выше код гудит, когда компонент активен, но не когда он находится в фоновом режиме.
Я ожидаю, что он гудит, когда я приближаюсь к DESTINATION_COORDS примерно на десять метров, независимо от того, есть ли у меня приложение на переднем плане ИЛИ в фоновом режиме.
Сейчас оно гудит только тогда, когда приложение находится на переднем плане и компонент активно отображается на экране.

Подробнее здесь: https://stackoverflow.com/questions/784 ... und-on-ios
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «IOS»