为 NativeScript 应用添加 GPS 功能

0 阅读5分钟

使用 @nativescript/geolocation 为应用添加 GPS 功能

构建具备 GPS 定位感知能力的应用

在当今的应用开发领域,整合基于位置的服务变得越来越重要。无论是用于地图、导航还是提供特定于位置的内容,GPS 功能都能丰富用户体验,并为移动应用程序增添巨大价值。

尽管初次集成 GPS 可能看起来令人生畏,尤其是如果你正从网页开发转向移动平台,但 NativeScript 通过官方的 @nativescript/geolocation 插件提供了无缝的解决方案。在本文中,我们将探讨如何使用这个强大的工具,轻松地为你的 NativeScript-Vue 应用添加 GPS 功能。

可在 Github 上获得示例运行中的 Vue 3 项目。

1. 技术原理

对于 Android,该包利用了 Google Play Services – Location API。这是目前以节能方式与 GPS 交互的标准方法。但这同时也意味着没有 Google Play Services 的手机(例如华为等中国手机制造商的设备)将无法使用此包。

另一方面,在 iOS 上,使用的是 Core Location 框架

2. 设置包

可以通过以下方式轻松安装该包:

npm i @nativescript/geolocation

安装包后,接下来你需要根据你打算如何与 GPS 功能交互,为各个平台设置适当的权限清单。

对于 Android,在你的 AndroidManifest.xml 中添加以下几行:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

如果你并不真正需要用户的精确位置,例如新闻应用、天气应用等,你只需要知道用户所在的国家或最近的城镇来推荐相关内容,那么可以移除 ACCESS_FINE_LOCATION

如果你需要在后台持续使用 GPS 定位,比如用户运动追踪应用。你需要为 Android 添加以下额外权限:

<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

对于 iOS 后台定位访问,添加到 plist 文件:

<key>UIBackgroundModes</key>
<array>
  <string>location</string>
</array>

(注意:如果只在前台访问位置,则不需要在 iOS plist 中添加任何内容)

专业提示

经验法则,使用更少的权限更好,这有助于你在应用审核过程中避免头疼。如果你在 Android 应用中包含 ACCESS_BACKGROUND_LOCATION,你需要向 Google 审核团队和 AppStore 审核团队解释其用途。

傻傻的我,曾经有一次不小心把后台权限包含到了我的应用中,但实际上并没有使用它,因为我们只在前台获取位置。别学我。

包的描述本身已经很好地解释了它的功能和用法,所以阅读一下也是个好主意:www.npmjs.com/package/@na…

3. 如何使用 @nativescript/geolocation

3.1. 确保你有权限

记得始终将你的 GPS 操作包装在:

import * as geolocation from '@nativescript/geolocation';

geolocation.enableLocationRequest().then(() => {
   // ... 此处安全访问 Location API
})

这确保你始终有足够的权限与设备位置进行交互。否则,在没有权限的情况下访问设备位置会导致致命错误。

专业提示

永远不要在你的 onMounted 钩子(或 Vue 2 的 mounted)中访问 Location API。问题是这些钩子调用得太早,一些组件可能还没有完全启动!相反,尝试在你的 <Page> 上使用 @loaded 事件。

3.2. 读取位置 – 基础方法

一次性获取设备的精确位置:

import { CoreTypes } from '@nativescript/core';

// 注意:将下方代码包装在 `enableLocationRequest` 内部

geolocation.getCurrentLocation({ desiredAccuracy: CoreTypes.Accuracy.high, maximumAge: 5000, timeout: 20000 })
  .then((result) => {
    // 在 `result` 变量上访问纬度和经度
    // 使用:result.latitude, result.longitude, result.
  })

对于 desiredAccuracy,你有两个选项:

  • CoreTypes.Accuracy.any: 使用较少电量,预计精度在 100 米以上
  • CoreTypes.Accuracy.high: 更耗电量,设备能给出的最精细的纬度和经度

3.3. 读取位置 – 更好的方法

getCurrentLocation 的一个缺点是,如果 GPS 信号弱,有时可能需要长达 10 秒甚至超时。我总是使用 watchLocation 来避免超时问题,而且它与 Vue 组件生命周期一起使用感觉也更直观。强烈推荐使用 watchLocation(),即使你只需要一次位置信息。

这是一个例子:

import { CoreTypes } from '@nativescript/core';

const location = ref<geolocation.Location | null>(null);
const watchId = ref<number | null>(null);

// 注意:将下方代码包装在 `enableLocationRequest` 内部

geolocation.watchLocation(
  (result) => {
    // 在 `result` 变量上访问纬度和经度
    // 使用:result.latitude, result.longitude, result.
    location.value = result;
  },
  (error) => {
    // 发生了不好的事情
  },
  {
    desiredAccuracy: CoreTypes.Accuracy.high,
    maximumAge: 5000,
    timeout: 20000
  }
)
.then((id) => {
  watchId.value = id;
});

然后,别忘了使用 clearWatch 清除监听器,如果你不确定到底在哪里应该停止监听,最好在 onUnmounted 钩子内部使用 clearWatch

onUnmounted(() => {
  if (watchId.value) {
    geolocation.clearWatch(watchId.value);
  }
});

这可以确保电源效率,并防止僵尸线程在后台运行。

专业提示

以我的做法,我会在 @loaded 事件中开始监听位置变化,在调用 watchLocation 之前,通过检查 watchId 确保没有活跃的监听器,并在 onUnmounted 钩子中使用 clearWatch,以确保每当用户离开页面时,一切都应被清理干净。

同时,记住合理地访问设备位置,以防止对用户宝贵的电池消耗造成影响。

结论

GPS 定位功能是移动世界中最有趣的方面之一。将此功能整合到你的项目中,将为用户提供更沉浸式和个性化的体验。然而,它也非常耗电,因此请明智地使用它,以防止不必要的电力消耗。

在后台服务中访问 GPS 定位,对于司机追踪、配送应用等场景也是一个有趣的用例。我正在撰写另一篇关于 NativeScript 后台服务的文章,很快就会发布,敬请期待!

如何解决 geolocation 错误:Cannot read property ‘PRIORITY_HIGH_ACCURACY’

如果你使用的是 NativeScript 8.1+,并且使用的是 @nativescript/geolocation 插件 8.1.0 版本,并且在某个地方意外设置了 googlePlayServicesVersion。来自此插件的最近更新可能会导致你的 Android 构建失败。

来自 Discord 的解答在这里插入图片描述 相关 GitHub 问题:github.com/NativeScrip…

症状

Error: Cannot enable the location service. TypeError: Cannot read property 'PRIORITY_HIGH_ACCURACY' of undefined

如何修复

尝试从所有 .gradle 脚本中移除 googlePlayServicesVersion 设置,或者将其设置为 21.+。你可能意外地在 app.gradlebefore-plugins.gradle 中设置了它。 在这里插入图片描述

修复上述行后,尝试执行:

ns clean
ns run android

以清理并重新构建你的项目。