React Native 后台位置跟踪不适用于搭载 Android 14 的三星设备

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

所以问题是这段代码在所有其他设备上都能正常工作并获取结果,但在使用 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 react-native mobile geolocation samsung-mobile
1个回答
0
投票

我有同样的问题...权限在 Android 14 上不起作用...

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