我正在尝试创建一个后台任务,主要用于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):
这里的问题是任务运行一次,而且如果我将应用程序留在后台足够快,则 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>
);
}
来自控制台的日志:
我做错了什么?有没有办法在后台大约每 10 秒获取用户当前位置?
我尝试创建一个后台任务,每 x 秒处理(通过套接字发送到服务器)当前位置,但我只会更接近这两个结果:当应用程序处于后台时获取当前位置一次,而在其他情况下获取当前位置手,每分钟在后台运行任务,而不需要当前位置。
显然,仅使用 expo-location 和 expo-task-manager 从 startLocationUpdatesAsync 执行的后台任务在 Expo Go 中不起作用,但在构建应用程序时却起作用。我花了几天时间寻找答案,我阅读了 expo 文档(应该是这个解释),进行了很多研究,最后我发现了来自 expo github 的问题,这帮助我意识到出了什么问题。
希望这对像我这样的人有帮助(实际上我已经寻找解决方案好几天了)。