如何在Expo React Native中运行后台定位任务?

问题描述 投票:0回答:1

我正在尝试创建一个后台任务,主要用于android,它允许我每x秒获取用户的当前位置,并通过套接字将其发送到服务器套接字。我阅读了 Expo 的文档并尝试使用 Expo Location startLocationUpdatesAsync() 方法。显然,此功能需要安装 Expo TaskManager 并定义任务。这实际上有效并给了我位置:

import React from 'react';
import { Button, View, StyleSheet } from 'react-native';
import * as TaskManager from 'expo-task-manager';
import * as Location from 'expo-location';

const LOCATION_TASK_NAME = 'background-location-task';

TaskManager.defineTask(LOCATION_TASK_NAME, async ({ data, error }) => {
    console.log("Task executed");
    try {
        if (error) {
          // Error occurred - check `error.message` for more details.
          return;
        }
        if (data) {
          const { locations } = data;
          console.log("paso");
          setTimeout(() => {
              console.log("paso timeout");
          }, 5000);
          setInterval(() => {
              console.log(locations[0]);
          }, 4000);
          // do something with the locations captured in the background
        }
    } catch (error) {
        console.log(error);
    }

});

const requestPermissions = async () => {
    try {
        const { status: foregroundStatus } = await Location.requestForegroundPermissionsAsync();
        if (foregroundStatus === 'granted') {
            const { status: backgroundStatus } = await Location.requestBackgroundPermissionsAsync();
            if (backgroundStatus === 'granted') {
                if (await Location.hasStartedLocationUpdatesAsync(LOCATION_TASK_NAME)) {
                  await Location.stopLocationUpdatesAsync(LOCATION_TASK_NAME);
                  console.log("stop");
              }
              await Location.startLocationUpdatesAsync(LOCATION_TASK_NAME, {
                  accuracy: Location.Accuracy.Balanced,
              });
              console.log("start");
          }
        }   
    } catch (error) {
        console.log(`requestPermissions: ${error}`);
    }
};

const PermissionsButton = () => (
  <View style={styles.container}>
    <Button onPress={requestPermissions} title="Enable background location" />
  </View>
);

来自控制台的日志(手动将 lat 和 lng 更改为 0,以防止 dox):

  • 记录停止
  • 日志开始
  • LOG 任务已执行
  • 记录步骤
  • LOG {“坐标”:{“精度”:11.392000198364258,“高度”:0,“高度精度”:0.5,“航向”:0,“纬度”:0,“经度”:0,“速度”:0} ,“时间戳”:1696817481586}
  • LOG paso 超时

这里的问题是任务运行一次,而且如果我将应用程序留在后台足够快,则 setTimeout 和 setInterval 不会运行,直到我打开应用程序。

所以我注意到存在另一个使用 TaskManager 的包。世博会背景获取。我还尝试与此博览会包结合使用,现在任务每分钟运行一次,但没有获取位置:

import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
import * as BackgroundFetch from 'expo-background-fetch';
import * as TaskManager from 'expo-task-manager';
import * as Location from 'expo-location';

const BACKGROUND_FETCH_TASK = 'background-fetch-with-location';

TaskManager.defineTask(BACKGROUND_FETCH_TASK, async ({ data, error }) => {
  const now = Date.now();
  console.log(`Got background fetch call at date: ${new Date(now).toISOString()}`);
  try {
    if (error) {
      return;
    }
    if (data) {
      console.log("paso if(data)");
      console.log(data);
      const { locations } = data;
      console.log(locations);
      const location = locations[0];
      console.log(location);
    }
} catch (error) {
    console.log(error);
}
  return BackgroundFetch.BackgroundFetchResult.NewData;
});

async function registerBackgroundFetchAsync() {
  return await BackgroundFetch.registerTaskAsync(BACKGROUND_FETCH_TASK, {
    minimumInterval: 5, // 15 minutes
    stopOnTerminate: false, // android only,
    startOnBoot: true, // android only
  });
}

async function unregisterBackgroundFetchAsync() {
  return await BackgroundFetch.unregisterTaskAsync(BACKGROUND_FETCH_TASK);
}

export default function AppJS() {
  const [isRegistered, setIsRegistered] = React.useState(false);
  const [status, setStatus] = React.useState(null);

  React.useEffect(() => {
    checkStatusAsync();
  }, []);

  const checkStatusAsync = async () => {
    const status = await BackgroundFetch.getStatusAsync();
    const isRegistered = await TaskManager.isTaskRegisteredAsync(BACKGROUND_FETCH_TASK);
    setStatus(status);
    setIsRegistered(isRegistered);
  };

  const toggleFetchTask = async () => {
    if (isRegistered) {
      if (await Location.hasStartedLocationUpdatesAsync(BACKGROUND_FETCH_TASK)) {
        await Location.stopLocationUpdatesAsync(BACKGROUND_FETCH_TASK);
      }
      await unregisterBackgroundFetchAsync();
    } else {
      if (!(await Location.hasStartedLocationUpdatesAsync(BACKGROUND_FETCH_TASK))) {
        await Location.startLocationUpdatesAsync(BACKGROUND_FETCH_TASK, {
          accuracy: Location.Accuracy.BestForNavigation,
        });
      }
      await registerBackgroundFetchAsync();
    }

    checkStatusAsync();
  };

  return (
    <View style={styles.screen}>
      <View style={styles.textContainer}>
        <Text>
          Background fetch status:{' '}
          <Text style={styles.boldText}>
            {status && BackgroundFetch.BackgroundFetchStatus[status]}
          </Text>
        </Text>
        <Text>
          Background fetch task name:{' '}
          <Text style={styles.boldText}>
            {isRegistered ? BACKGROUND_FETCH_TASK : 'Not registered yet!'}
          </Text>
        </Text>
      </View>
      <View style={styles.textContainer}></View>
      <Button
        title={isRegistered ? 'Unregister BackgroundFetch task' : 'Register BackgroundFetch task'}
        onPress={toggleFetchTask}
      />
    </View>
  );
}

来自控制台的日志:

  • LOG 在日期进行后台提取调用:2023-10-09T02:05:04.771Z
  • LOG paso if(数据)
  • 记录{}
  • 日志未定义
  • LOG [类型错误:无法将未定义的值转换为对象]

我做错了什么?有没有办法在后台大约每 10 秒获取用户当前位置?

我尝试创建一个后台任务,每 x 秒处理(通过套接字发送到服务器)当前位置,但我只会更接近这两个结果:当应用程序处于后台时获取当前位置一次,而在其他情况下获取当前位置手,每分钟在后台运行任务,而不需要当前位置。

android react-native expo location background-task
1个回答
0
投票

显然,仅使用 expo-location 和 expo-task-manager 从 startLocationUpdatesAsync 执行的后台任务在 Expo Go 中不起作用,但在构建应用程序时却起作用。我花了几天时间寻找答案,我阅读了 expo 文档(应该是这个解释),进行了很多研究,最后我发现了来自 expo github 的问题,这帮助我意识到出了什么问题。

希望这对像我这样的人有帮助(实际上我已经寻找解决方案好几天了)。

© www.soinside.com 2019 - 2024. All rights reserved.