所以问题是这段代码在所有其他设备上都能正常工作并获取结果,但在使用 Android 14 的三星设备时却不能。它在前台时仍会提供位置,但一旦移至后台,它就会停止提供位置更新。
代码
import React, { useState } from 'react';
import {
SafeAreaView,
Text,
StyleSheet,
TouchableOpacity,
PermissionsAndroid,
Platform,
Alert,
} from 'react-native';
import BackgroundService from 'react-native-background-actions';
import Geolocation from 'react-native-geolocation-service';
export default function App() {
const [location, setLocation] = useState({});
const sleep = (time) => new Promise((resolve) => setTimeout(resolve, time));
const requestLocationPermission = async () => {
if (Platform.OS === 'android') {
try {
const fineLocationGranted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
{
title: 'Fine Location Permission',
message: 'This app needs access to your precise location.',
buttonNeutral: 'Ask Me Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
}
);
if (fineLocationGranted !== PermissionsAndroid.RESULTS.GRANTED) {
Alert.alert('Permission Denied', 'Fine location permission is required.');
return false;
}
const coarseLocationGranted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION,
{
title: 'Coarse Location Permission',
message: 'This app needs access to your approximate location.',
buttonNeutral: 'Ask Me Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
}
);
if (coarseLocationGranted !== PermissionsAndroid.RESULTS.GRANTED) {
Alert.alert('Permission Denied', 'Coarse location permission is required.');
return false;
}
const backgroundLocationGranted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_BACKGROUND_LOCATION,
{
title: 'Background Location Permission',
message: 'This app needs access to your location in the background.',
buttonNeutral: 'Ask Me Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
}
);
if (backgroundLocationGranted !== PermissionsAndroid.RESULTS.GRANTED) {
Alert.alert('Permission Denied', 'Background location permission is required.');
return false;
}
return true;
} catch (err) {
console.warn(err);
return false;
}
}
return true;
};
const sendLocationToServer = async (location) => {
try {
console.log('Sending location to server:', location);
const response = await fetch('https://dummy.com/location', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(location),
});
const data = await response.text();
console.log('Server response:', data);
} catch (error) {
console.error('Error sending location to server:', error);
}
};
const veryIntensiveTask = async (taskDataArguments) => {
const { delay } = taskDataArguments;
await new Promise(async (resolve) => {
for (let i = 0; BackgroundService.isRunning(); i++) {
Geolocation.getCurrentPosition(
async (position) => {
console.log('Location received:', position);
const newLocation = {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
timestamp: new Date().toLocaleTimeString(),
};
setLocation(newLocation);
await sendLocationToServer(newLocation);
console.log('Location dispatched to server:', newLocation);
},
(error) => {
console.error('Error receiving location:', error);
},
{
enableHighAccuracy: true,
distanceFilter: 0,
interval: 30000,
fastestInterval: 15000,
forceRequestLocation: true,
showLocationDialog: true,
}
);
await BackgroundService.updateNotification({
taskDesc: `Location tracking ${i}`,
});
await sleep(delay);
}
});
};
const options = {
taskName: 'Location',
taskTitle: 'Tracking Location',
taskDesc: 'Tracking your location in the background',
taskIcon: {
name: 'ic_launcher',
type: 'mipmap',
},
color: '#ff00ff',
linkingURI: 'yourapp://location', // Adjust this to match your app's URI scheme
parameters: {
delay: 30000, // Set the delay to 30 seconds
},
foreground: true,
};
const startBackgroundService = async () => {
const hasLocationPermission = await requestLocationPermission();
if (!hasLocationPermission) {
return;
}
// Check for battery optimization settings
if (Platform.OS === 'android') {
try {
const isIgnoringOptimization = await BackgroundService.isIgnoringBatteryOptimizations();
if (!isIgnoringOptimization) {
await BackgroundService.requestIgnoreBatteryOptimizations();
}
} catch (err) {
console.warn(err);
}
}
await BackgroundService.start(veryIntensiveTask, options);
await BackgroundService.updateNotification({ taskDesc: 'Location tracking started' });
console.log('Background service started');
};
const stopBackgroundService = async () => {
await BackgroundService.stop();
console.log('Background service stopped');
};
return (
<SafeAreaView style={styles.container}>
<Text style={styles.text}>Location Tracker</Text>
<TouchableOpacity style={styles.button} onPress={startBackgroundService}>
<Text style={styles.buttonText}>Start Background Service</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={stopBackgroundService}>
<Text style={styles.buttonText}>Stop Background Service</Text>
</TouchableOpacity>
{location.latitude && (
<Text style={styles.locationText}>
Latitude: {location.latitude}, Longitude: {location.longitude}, Time: {location.timestamp}
</Text>
)}
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#282C34',
padding: 20,
},
text: {
fontSize: 28,
color: '#61DAFB',
fontWeight: 'bold',
marginBottom: 20,
},
button: {
marginTop: 20,
paddingVertical: 12,
paddingHorizontal: 32,
backgroundColor: '#61DAFB',
borderRadius: 8,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.8,
shadowRadius: 2,
elevation: 5,
},
buttonText: {
color: '#282C34',
fontSize: 18,
fontWeight: '600',
},
locationText: {
fontSize: 18,
color: 'white',
marginTop: 20,
},
});
ANDROID 清单文件
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
老实说,我什至不知道如何解决这个问题,因为它对于其他所有设备都可以正常工作,例如其他具有 Android 14 的设备(如 Pixel 8),甚至具有 Android 版本的三星设备< 14.
编辑: 这是我在 browserStack 上测试时发现的一个差异。在 Android 14 三星设备上测试时,此行会被记录
E/Adreno-AppProfiles(20049):QSPM AIDL 服务不存在
我有同样的问题...权限在 Android 14 上不起作用...