在 RN 中获取当前用户坐标的最佳方法是什么

What is the best way to make function for getting current user coordinates in RN

我想创建一个获取用户坐标的函数,但我发现我不确定我的方法是否足够好。
我想知道其他人如何编写此函数以在 ios 和 android.
100% 确定地工作 现在我有这样的东西:

function getUserLocation(callback: func) {
  Permissions.check('location')
  .then(response => {
    if (response == 'authorized') {
      navigator.geolocation.getCurrentPosition(
        (location) => {
          callback({
              latitude: location.coords.latitude, 
              longitude: location.coords.longitude
            }, response);
        },
        (error) => {
          callback(null);
        },
        Platform.OS === 'android' ? null : {enableHighAccuracy: true, timeout: 100000, maximumAge: 1000}
      );
    } else {
      callback(null, response);
    }
  })
}

所以你可以看到我想使用这个函数,这样调用者就可以知道是否允许使用位置以及是否获取当前坐标。
我正在尝试的是学习如何:

1. 使这样的函数成为 awaitable.
2. 其他人如何实现这样的功能(OS)并且工作 100% 相同。

你的问题分为两部分

1. Make function like this to be awaitable.

这可以通过向您提供如何操作的逻辑来直接回答。 Awaitable 只不过是一个异步函数或 return 承诺的东西。如果你想要 async 方式,那么你需要先制作一个 getCurrentPosition 的版本,return 是一个承诺。可以像下面那样完成

function getCurrentLocation(options) {
  return new Promise((resolve, reject) => {
    navigator.geolocation.getCurrentPosition(resolve, ({code, message}) =>
      reject(Object.assign(new Error(message), {name: "PositionError", code})),
      options);
    });
};

PS:感谢 以上代码

现在您可以像下面这样重写代码

async function getUserLocation() {
  let response = await Permissions.check('location')
  let options = Platform.OS === 'android' ? null : {enableHighAccuracy: true, timeout: 100000, maximumAge: 1000}

  if (response == 'authorized') {
      return await getCurrentLocation(options)
  }

  return null;
}

如果你不想走promise的路,它会像下面这样

function getUserLocation() {
    return new Promise((resolve, reject) => {
        Permissions.check('location')
            .then(response => {
                if (response == 'authorized') {
                    navigator.geolocation.getCurrentPosition(
                        (location) => {
                            resolve({
                                latitude: location.coords.latitude,
                                longitude: location.coords.longitude
                            });
                        },
                        (error) => {
                            reject(error);
                        },
                        Platform.OS === 'android' ? null : { enableHighAccuracy: true, timeout: 100000, maximumAge: 1000 }
                    );
                } else {
                    resolve(null);
                }
            })
    });
}

这里的一个关键点与回调不同,承诺解析单个值,这意味着您需要使用对象来 return 多个参数。

2. How others make function like this (for both OS) and to work 100% same.

这是你的问题变得固执己见的地方,我可能会采取一些不同的方法,你可能会做其他事情,而另一个人可能会做完全不同的事情。但我仍将讨论几种可能性。

拆分为多个函数

function getUserLocation() {
   if (Platform.OS === 'android')
   {
       return getUserLocationAndroid();
   } else {
       return getUserLocationIOS();
   }
}

维护键值对

您可以拥有基于 OS.

自动绑定函数的代码
Utils = {
   getFunction(name) {
      if ((name + Platform.OS) in this)
          return this[name + Platform.OS]
      return this[name];
   }
   getLocation: function() {}
   //getLocationandroid: function() {}
}

因此,默认情况下,您将 getLocation 用于服务器 OS,但如果 OS 代码之一偏离太多,您将为相同的代码创建一个新函数。代码如下所示

Utils.getFunction("getLocation")(...)

一个带分支的函数

这就是您目前的做法。只要功能易于理解并且有明确的意图,我会坚持使用代码的哪一部分执行特定于平台的内容

这里可能还有 10 多种不同的方法,但最终取决于一件事,哪种更容易维护、理解使用。有些方法也是特定于用例的,您可以根据用例混合使用多种方法

总的来说,对我来说这种方法不是最好的方法。有什么理由要拉吗?

两者 OS 都有一个推送模式,你可以根据位置的变化跟踪位置,这对用户的电池寿命和你的应用程序必须做的处理来说更好。此外,使某些东西可用将是一个阻塞调用的事情,你不会真的想做很多事情。

React Native 有方法navigator.geolocation.watchPosition你可以找一个参考[​​=13=]。您可以定义有关准确性、超时等的选项。

下一个函数用于 redux 的情况,因此 redux-thunk 每次都会发送事件作为承诺,以重新计算 reducer 中的状态,但可以通过修改回调函数来轻松适应,以执行您想要的任何其他操作。

let geolocationSettings = {enableHighAccuracy: true, timeout: 5000, maximum: 5000, distanceFilter:10}

function setPositionWatch(dispatch,geolocationSettings){
    positionWatcher = navigator.geolocation.watchPosition(
        (pos) => {
            dispatch({
                type: types.NEW_POSITION,
                state: pos
            })
        },
        () => {
            dispatch({
                type: types.ERROR_POSITION
            })
        },
        geolocationSettings)
}

基本上,您为这种推送机制提供正确行为、错误行为和选项的回调。当您想停止收集位置信息时,您可以执行 clearWatch.

制作 getCurrentPosition 的异步版本,您可以将此功能添加到 navigator.geolocation。

async function getCurrentPosition(options) {
    return new Promise((resolve, reject) => {
        navigator.geolocation.getCurrentPosition(
            position => resolve(position.coords),
            error => reject(error),
            options
        });
    });
}

下一个函数就是你想要的。最好在未授权时抛出异常,因为无论如何你需要 try / catch 因为 getCurrentPosition.

const locationOptions = Platform.OS === 'android' ? null : 
    { enableHighAccuracy: true, timeout: 100000, maximumAge: 1000 };

async function getUserLocation() {
    let permission = await Permissions.check('location');
    if (permission !== 'authorized') {
        throw new Error('Not authorized: ' + permission);
    }

    return await getCurrentPosition(locationOptions);
}

使用方法:

try {
    let location = await getUserLocation(); // { latitude, longitude }
} catch (error) {
    Alert.alert(error.message);
}