TypeScript - Expo קבלת עדכוני מיקום ברקע, לא מקבל עדכונים


אני מנסה לקבל את המיקום ברקע ואז לשלוח אותו לשרת שלי, עקבתי אחרי כל תשובה ב-Stack Overflow והמדריכים הרשמיים אבל עבורי העדכונים פשוט לא קורים. יש לי התקנה פשוטה, משתמש ב-Expo SDK 48, וב-expo-task-manager הרשמי עם expo-location

אז יש לי רכיב שמכיל את הלוגיקה הזו, הוא נקרא LocationTracker ובאמצעות useLocationTracker hook אני עוטף את הלוגיקה

הנה הלוגיקה בפועל של useLocationTracker.ts

import { useEffect } from "react";
import * as Location from "expo-location";
import { LatLng } from "react-native-maps";
import * as TaskManager from "expo-task-manager";
import { LocationObject } from "expo-location";
import { logger } from "../logger";
type Callback = (coords: LatLng) => void;
const LOCATION_TRACKING_TASK = "location_tracking_task";

const executor: (body: TaskManager.TaskManagerTaskBody<object>) => void = (
    body
) => {
    const data = body.data as unknown as { locations: LocationObject[] };
    const l = data?.locations[0];
    console.log("location", l);
    if (!l) return;

    for (const callback of Object.values(locationCallbacks)) {
        callback({
            latitude: l.coords.latitude,
            longitude: l.coords.longitude,
        });
    }
};

TaskManager.defineTask(LOCATION_TRACKING_TASK, executor);

const locationCallbacks: { [key: string]: Callback } = {};

function addLocationCallback(callback: Callback) {
    const id = uuid() as string;
    locationCallbacks[id] = callback;
    return {
        remove: () => {
            delete locationCallbacks[id];
        },
    };
}

export const useLocationTracker = (
    callback: Callback | null,
    active: boolean = true
) => {
    useEffect(() => {
        if (!active) return;
        if (!callback) return;
        startTrackingLocation();
        const subscription = addLocationCallback(callback);
        return () => {
            subscription.remove();
            stopTrackingLocation();
        };
    }, [callback, active]);

    async function startTrackingLocation() {
        const { status: foregroundStatus } = await Location.requestForegroundPermissionsAsync();
        if (foregroundStatus === 'granted') {
            const { status: backgroundStatus } = await Location.requestBackgroundPermissionsAsync();
            if (backgroundStatus === 'granted') {
                try {
                    logger.info("starting location updates");
                    Location.startLocationUpdatesAsync(LOCATION_TRACKING_TASK, {
                        showsBackgroundLocationIndicator: true,
                        accuracy: Location.Accuracy.Highest,
                        distanceInterval: 10, // minimum change (in meters) betweens updates
                        deferredUpdatesInterval: 1000, // minimum interval (in milliseconds) between updates
                        timeInterval: 3000,
                        // foregroundService is how you get the task to be updated as often as would be if the app was open
                        foregroundService: {
                            notificationTitle: 'Using your location',
                            notificationBody: 'To turn off, go back to the app and switch something off.',
                        },
                    });
                } catch (e) {
                    logger.error("failed to start location updates", e);
                }
            }
        }
    }

    async function stopTrackingLocation() {
        Location.hasStartedLocationUpdatesAsync(LOCATION_TRACKING_TASK).then((value) => {
            if (value) {
                logger.info("stopping location updates");
                Location.stopLocationUpdatesAsync(LOCATION_TRACKING_TASK);
            }
        });
    }
}

הנה הרכיב (מאוד בסיסי)

LocationTracker.tsx
import { api } from "@employees/lib/api";
import { useLocationTracker } from "@employees/lib/hooks/useLocationTask";
import { logger } from "@employees/lib/logger";
import { useAppStore } from "@employees/lib/store";
import { Point } from "@safedriver/db";
import { useCallback } from "react";

export const LocationTracker = () => {
    const { mutate, isLoading, isError } = api.employee.updateLocation.useMutation({
        onSuccess: (data) => {
            logger.info(new Date(), "updateLocation success", data)
        }
    })

    const callback = useCallback((location: Point) => {
        console.log("update location", location)
        mutate({ location })
    }, [mutate, shift]);

    useLocationTracker(callback, true)

    return null;
}

ורכיב זה משמש ב-_layout.tsx שלי כך

export default function Layout() {
    return (
        <TRPCProvider>
            <LocationTracker />
            <SafeAreaProvider>
                <Stack screenOptions={{ headerShown: false }} />
                <StatusBar />
            </SafeAreaProvider>
        </TRPCProvider>
    );
}

בדקתי כדי לוודא האם המשימה רשומה ופועלת והיא אכן כן, כך שזה לא הגורם לבעיה. ההגדרות שלי זהות לתשובות העליונות ב-Stack Overflow, הדאגה היחידה שלי היא שההגדרה שלי עם ה-hook והקומפוננטה לא פועלת בגלל איזושהי בעיית רינדור מחדש מוזרה או משהו כזה, מכיוון שהקוד עצמו למעקב מיקום אמור להיות נכון.

הסיבה שאני שוקל את סוגיית הרינדור מחדש היא מכיוון שאני מקבל זאת ברשומות כל הזמן

 LOG  [INFO] 53:52.699 Main - stopping location updates
 LOG  [INFO] 53:52.701 Main - starting location updates
 LOG  [INFO] 53:57.738 Main - stopping location updates
 LOG  [INFO] 53:57.740 Main - starting location updates
 LOG  [INFO] 54:03.2 Main - stopping location updates
 LOG  [INFO] 54:03.4 Main - starting location updates
 LOG  [INFO] 54:08.27 Main - stopping location updates
 LOG  [INFO] 54:08.29 Main - starting location updates
 LOG  [INFO] 54:13.81 Main - stopping location updates
 LOG  [INFO] 54:13.84 Main - starting location updates
 LOG  [INFO] 54:18.111 Main - stopping location updates
 LOG  [INFO] 54:18.113 Main - starting location updates