首页 > 解决方案 > 未处理的承诺拒绝:错误:无权使用后台定位服务

问题描述

我在托管流程中使用 expo。另外,我正在使用 expo-task-Manager 和 expo-location。我正在使用世博会文档,但我不知道为什么当我在后台时出现错误提示:

[未处理的承诺拒绝:错误:未授权使用后台位置服务。] promiseMethodWrapper node_modules/@unimodules/react-native-adapter/build/NativeModulesProxy 中的 node_modules/react-native/Libraries/BatchedBridge/NativeModules.js:103:50。 native.js:15:23 在 moduleName.methodInfo.name node_modules/expo-location/build/Location.js: 在 startLocationUpdatesAsync node_modules/regenerator-runtime/runtime.js:63:36 在 tryCatch node_modules/regenerator-runtime/runtime。 js:293:29 in invoke node_modules/regenerator-runtime/runtime.js:63:36 in tryCatch node_modules/regenerator-runtime/runtime.js:154:27 in invoke

我的代码如下:

import React from 'react';
import {connect} from 'react-redux';
import {View, TouchableHighlight, Text, StyleSheet} from 'react-native';
import { activateSearch, actualLocation, arriveToken, logging, localFound, arriveShop, arriveShops } from '../redux/actions';
import { Alert, Platform } from 'react-native'
import * as Permissions from 'expo-permissions';
import * as Linking from 'expo-linking';
import * as Notifications from 'expo-notifications';
import * as Location from 'expo-location';
import * as TaskManager from 'expo-task-manager';
import axios from 'axios';

import {baseURL} from '../consts/url';

const LOCATION_TASK_NAME = 'background-location-tasks'

const hasNotificationPermission = async () => {
  try {
    const { status: existingStatus } = await Permissions.getAsync(Permissions.NOTIFICATIONS);
    let finalStatus = existingStatus;

    if (finalStatus === 'granted') return true;
    if (finalStatus !== 'granted') {
      Alert.alert(
        'Warning',
        'You will not receive notifications if you do not enable push notifications. If you would like to receive notifications, please enable push notifications for Fin in your settings.',
        [
          { text: 'Cancel'},
          // we can automatically open our app in their settings
          // so there's less friction in turning notifications on
          { text: 'Enable Notifications', onPress: () => Platform.OS === 'ios' ? Linking.openURL('app-settings:') : Linking.openSettings() }
        ]
      )
      return false;
      
    }
  } catch (error) {
    Alert.alert(
      'Error',
      'Something went wrong while check your notification permissions, please try again later.'
    );
    return false;
  }
}

const hasGeolocationPermission = async () => {
  try {
    const { status } = await Location.requestPermissionsAsync();
    let finalStatus = status
    if (finalStatus === 'granted') return true;
    if (finalStatus !== 'granted') {
      Alert.alert(
        'Warning',
        'You will not search if you do not enable geolocation in this app. If you would like to search, please enable geolocation for Fin in your settings.',
        [
          { text: 'Cancel'},
          // we can automatically open our app in their settings
          // so there's less friction in turning geolocation on
          { text: 'Enable Geolocation', onPress: () => Platform.OS === 'ios' ? Linking.openURL('app-settings:') : Linking.openSettings() }
        ]
      )
      return false;
      
    }
  } catch (error) {
    Alert.alert(
      'Error',
      'Something went wrong while check your geolocation permissions, please try again later.'
    );
    return false;
  }
}

const checkIfLocationEnabled = async () => {
  let enabled = await Location.hasServicesEnabledAsync();
  if (!enabled){
    alert('Location service not enabled, please enable it to continue')
  }
  else {
    return enabled;
  }
}

class IndexScreen extends React.Component {

  async componentDidMount() {
    hasNotificationPermission()
    hasGeolocationPermission()
    this.registerForPushNotificationsAsync()
    Notifications.addNotificationReceivedListener(notification => { 
      Alert.alert(notification.request.content.title, notification.request.content.body)
      console.log(notification)
      this.props.navigation('App');
    })
    Notifications.addNotificationResponseReceivedListener( response => {
      console.log(response);
      this.props.navigation('App');
    }) /*cuando el usuario pulsa encima, cambia de pantalla*/
    this.getShops()
    
    this.myInterval = setInterval(async () => {
      if (this.props.activated){
        let Notpermission = await hasNotificationPermission();
        let Geopermission = await hasGeolocationPermission();
        let EnableLocation = await checkIfLocationEnabled();
        if (Notpermission && Geopermission && EnableLocation){
          this.getPosition();
        } //Si cambia algo de los permisos, se deja de enviar.
        else {return}
      }
    }, 5000)
    this.myInterval2 = setInterval(async () => {
      if (this.props.activated){
        let Notpermission = await hasNotificationPermission();
        let Geopermission = await hasGeolocationPermission();
        let EnableLocation = await checkIfLocationEnabled();
        if (Notpermission && Geopermission && EnableLocation){
          this.sendLocation();
        } //Si cambia algo de los permisos, se deja de enviar.
        else {return}
      }
    }, 35000)
  }

  async componentWillUnmount(){
    clearInterval(this.myInterval)
    clearInterval(this.myInterval2)
  }


  activate = async () => {
    let Notpermission = await hasNotificationPermission();
    let Geopermission = await hasGeolocationPermission();
    let EnableLocation = await checkIfLocationEnabled();
    if (Notpermission && Geopermission && EnableLocation){
      if (!this.props.activated){
        this.props.dispatch(activateSearch());
        this.getPosition();
        this.sendLocation();
        const { status } = await Location.requestPermissionsAsync();
        if (status === 'granted') {
          console.log("Entra aquí")
          await Location.startLocationUpdatesAsync(LOCATION_TASK_NAME, {
            accuracy: Location.Accuracy.BalancedHighest,
            timeInterval: 10000,
            foregroundService: {
              notificationTitle: "BackgroundLocation Is On",
              notificationBody: 'To turn off, go back to the app and switch something off.',
          }});
        }
    }
      else
        this.props.dispatch(activateSearch())
        if (this.props.locationdetected)
          this.props.dispatch(localFound());
        //this.deleteToken()
    }
    else{
        return
    }
  }

    render() {
      if (this.props.logged){
        return(
            <View style={{ flex:1, flexDirection: 'column', alignItems:'center', justifyContent:'space-around'}}>
                <Text style={{flex:1, fontSize: 35 }}> Welcome {this.props.username} to this demo App </Text> 
                <Text style={{flex:1, fontSize: 35 }}> Press  'Start Search'</Text> 
                <TouchableHighlight style={styles.button} onPress = {() => this.activate()}>
                    <Text> {this.props.activated ? "Stop Search" : "Start Search"}</Text>
                </TouchableHighlight>
                <TouchableHighlight style={styles.button} onPress = {() => this.logout()}>
                    <Text>Logout</Text>
                </TouchableHighlight>
            </View>
        )
        }
        else{
          return(
            <View style={{ flex:1, flexDirection: 'column', alignItems:'center', justifyContent:'space-around'}}>
                <Text style={{flex:1, fontSize: 35 }}> You need to be logged </Text> 
            </View>
          )
        }
    }


  async registerForPushNotificationsAsync() {
    try{
      let token = (await Notifications.getExpoPushTokenAsync()).data;
      this.props.dispatch(arriveToken(token))
      this.sendToken(token);

      if (Platform.OS === 'android') {
        Notifications.setNotificationChannelAsync('default', { /*en Android es necesario poner un canal por defecto*/
          name: 'default',
          importance: Notifications.AndroidImportance.MAX,
          vibrationPattern: [0, 250, 250, 250],
          lightColor: '#FF231F7C',
        });
      }

      return token;
    }
    catch(error){
      console.log("No se ha podido obtener el token para push notifications")
    }
  }

  async getPosition() {
    try{
      const { coords } = await Location.getCurrentPositionAsync({});
      let position = coords;
      this.props.dispatch(actualLocation(position.latitude, position.longitude))
      console.log(this.props.latitud)
    } 
    catch (error) {
      console.log("getPosition -> error", error);
    }
  }

  async sendLocation(){

    let response = await fetch(baseURL+'/location', {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Accept-encoding': 'gzip, deflate',
        'Content-Type': 'application/json',
      },
      //credentials: 'include',
      body: JSON.stringify({latitud: this.props.latitud, longitud: this.props.longitud, shopfind: this.props.locationdetected}),
    });

    let responsed = await response.json();

    if (response.status == 401){
      alert('La sesión ha finalizado por exceso de espera. Vuelva a hacer Log in.')
      if(this.props.activated && this.props.logged){
        if(this.props.locationdetected){
          this.props.dispatch(localFound())
        }
        this.props.dispatch(activateSearch());
        this.props.dispatch(logging(''));
      }
    }
    else if (responsed.shop && !this.props.locationdetected) {
      this.props.dispatch(localFound())
      let placementsreformed = responsed.shop.placements.map(item => {
        return {...item,
        quantity: 0}
      })
      responsed.shop.placements = placementsreformed;
      this.props.dispatch(arriveShop(responsed.shop))
      console.log("tienda enviada")
    }
    else {
      if (this.props.locationdetected && !responsed.shop){
        this.props.dispatch(localFound())
        console.log("Se ha dejado de encontrar tiendas")
      }
      else{
        return;
      }
    }

  }

}

TaskManager.defineTask(LOCATION_TASK_NAME, async ({ data: {locations}, error }) => {
  if (error) {
    // Error occurred - check `error.message` for more details.
    return;
  }
  const [location] = locations;
  console.log(location);
  try{
    await axios.post(baseURL+'/location', {location})
  }catch (err) {
    console.log(err)
  }
}); 


const styles = StyleSheet.create({
    button: {
        height: 60,
        width: 100,
        flexDirection: 'row',
        justifyContent: 'space-around',
        backgroundColor: 'red',
        fontSize: 25,
        textAlign: 'center',
        padding: 10
    }
}
    );

function mapStateToProps(state) {
    return {
      ...state
    };
}
      
      //export default App;
export default connect(mapStateToProps)(IndexScreen);

标签: javascriptreact-nativebackgroundlocationexpo

解决方案


推荐阅读