用户位置

借助 Geolocation API,您可以在征得用户同意的情况下发现用户所在的位置。

借助 Geolocation API,您可以在征得用户同意的情况下获取用户的位置信息。您可以使用此功能来引导用户前往目的地,以及为用户创建的内容添加地理标签(例如,标记照片的拍摄地点)。

Geolocation API 还可让您查看用户所在的位置,并在用户移动时跟踪其位置,但始终需要征得用户同意(并且仅在页面打开时)。这会产生许多有趣的用例,例如与后端系统集成,以便在用户靠近时准备好订单。

使用 Geolocation API 时,您需要注意许多事项。本指南将为您介绍常见的使用场景和解决方案。

摘要

  • 在对用户有益时使用地理定位。
  • 在用户做出明确手势后,请求获取权限。
  • 使用功能检测,以防用户的浏览器不支持地理定位。
  • 不仅要学习如何实现地理定位,还要学习使用地理定位的最佳方式。
  • 测试网站的地理定位功能。

何时使用地理定位

  • 查找用户距离特定物理位置最近的位置,以量身定制用户体验。
  • 根据用户所在的位置提供量身定制的信息(例如新闻)。
  • 在地图上显示用户的位置。
  • 使用用户的位置信息标记在应用内创建的数据(即为图片添加地理标记)。

以负责任的方式请求权限

最近的用户调研表明,用户不信任那些在网页加载时只是提示用户提供其位置的网站。那么,有哪些最佳实践?

假设用户不会向您提供其位置信息

许多用户不希望向您提供其位置信息,因此您需要采用防御性开发方式。

  1. 处理地理定位 API 中的所有错误,以便您可以根据这种情况调整网站。
  2. 清楚明确地说明您需要获取位置信息的原因。
  3. 如有需要,请使用后备解决方案。

如果需要地理定位,请使用后备方案

我们建议您的网站或应用不要要求访问用户的当前位置。不过,如果您的网站或应用需要用户的当前位置,您可以使用第三方解决方案来获取用户当前位置的最佳猜测。

这些解决方案通常会查看用户的 IP 地址,并将其映射到 RIPE 数据库中注册的实际地址。这些位置通常不太准确,通常会提供距离用户最近的电信中心或手机信号塔的位置。在许多情况下,这些信息甚至可能不那么准确,尤其是当用户使用 VPN 或其他代理服务时。

始终在用户手势时请求位置信息访问权限

确保用户了解您请求获取其位置信息的原因,以及他们会从中获得什么好处。在网站加载时立即在首页上请求该权限会导致糟糕的用户体验。

网站在实体店查找工具页面上请求权限。
建议:始终在用户手势上请求位置信息访问权限。
在首页上请求权限的网站。
不建议:在网站加载时,在首页上请求位置信息;这会导致糟糕的用户体验。

而是应向用户提供明确的号召性用语,或指明某项操作需要访问其位置信息。这样,用户就可以更轻松地将系统访问权限提示与刚刚发起的操作相关联。

明确指出某项操作会请求获取其位置信息

在 Google Ads 团队开展的一项研究中,当用户被要求在某个特定酒店网站上预订波士顿的一间酒店客房以参加即将举行的会议时,他们在点按首页上的“查找并预订”号召性用语后,系统立即提示他们分享其 GPS 位置信息。

在某些情况下,用户会感到沮丧,因为他们不明白为什么他们想在波士顿预订房间,却看到旧金山的酒店。

更好的做法是确保用户了解您为何请求获取其位置信息。添加一个在各种设备上通用的知名标识符(例如测距仪),或明确的号召性用语(例如“查找我附近的地点”)。

测距仪。
使用测距仪
一个带有“查找附近”按钮的表单。
明确的号召性用语,引导用户查找附近地点

温和地提醒用户授予位置信息权限

您无法访问用户正在执行的任何操作。您能确切知道用户何时不允许访问其位置信息,但无法知道用户何时授予您访问权限;您只能在结果出现时知道您已获得访问权限。

如果您需要用户完成某项操作,最好“提醒”用户执行该操作。

我们建议采用以下做法:

  1. 设置一个在短时间后触发的计时器;5 秒是一个不错的值。
  2. 如果您收到出错提示,请向用户显示一条消息。
  3. 如果您收到肯定响应,请停用计时器并处理结果。
  4. 如果在超时后您未收到肯定响应,请向用户显示通知。
  5. 如果响应稍后才收到,并且通知仍然存在,请将其从屏幕中移除。
button.onclick = function () {
  var startPos;
  var nudge = document.getElementById('nudge');

  var showNudgeBanner = function () {
    nudge.style.display = 'block';
  };

  var hideNudgeBanner = function () {
    nudge.style.display = 'none';
  };

  var nudgeTimeoutId = setTimeout(showNudgeBanner, 5000);

  var geoSuccess = function (position) {
    hideNudgeBanner();
    // We have the location, don't display banner
    clearTimeout(nudgeTimeoutId);

    // Do magic with location
    startPos = position;
    document.getElementById('startLat').innerHTML = startPos.coords.latitude;
    document.getElementById('startLon').innerHTML = startPos.coords.longitude;
  };
  var geoError = function (error) {
    switch (error.code) {
      case error.TIMEOUT:
        // The user didn't accept the callout
        showNudgeBanner();
        break;
    }
  };

  navigator.geolocation.getCurrentPosition(geoSuccess, geoError);
};

浏览器支持

大多数浏览器现在都支持 Geolocation API,但最好在执行任何操作之前始终检查是否支持。

您可以通过测试地理位置对象是否存在来轻松检查兼容性:

// check for Geolocation support
if (navigator.geolocation) {
  console.log('Geolocation is supported!');
} else {
  console.log('Geolocation is not supported for this Browser/OS.');
}

确定用户的当前位置

Geolocation API 提供了一种简单、一次性的方法来获取用户的位置信息:getCurrentPosition()。调用此方法会异步报告用户的当前位置。

window.onload = function () {
  var startPos;
  var geoSuccess = function (position) {
    startPos = position;
    document.getElementById('startLat').innerHTML = startPos.coords.latitude;
    document.getElementById('startLon').innerHTML = startPos.coords.longitude;
  };
  navigator.geolocation.getCurrentPosition(geoSuccess);
};

如果这是此网域中的应用首次请求权限,浏览器通常会检查用户是否同意。根据浏览器的不同,可能还会有始终允许或不允许权限查找的偏好设置,在这种情况下,系统会绕过确认流程。

根据浏览器使用的定位设备,位置对象实际上可能包含的信息远不止纬度和经度;例如,它可能包含海拔高度或方向。在位置系统实际返回数据之前,您无法知道它使用了哪些额外信息。

监控用户的位置

借助 Geolocation API,您只需调用一次 getCurrentPosition() 即可获取用户的位置信息(需征得用户同意)。

如果您想持续监控用户的位置信息,请使用 Geolocation API 方法 watchPosition()。它的运作方式与 getCurrentPosition() 类似,但会多次触发,因为定位软件会:

  1. 更准确地锁定用户。
  2. 确定用户的位置正在发生变化。
var watchId = navigator.geolocation.watchPosition(function (position) {
  document.getElementById('currentLat').innerHTML = position.coords.latitude;
  document.getElementById('currentLon').innerHTML = position.coords.longitude;
});

何时使用地理定位来监视用户的位置

  • 您希望更精确地锁定用户位置。
  • 您的应用需要根据新的位置信息更新界面。
  • 当用户进入某个定义的区域时,您的应用需要更新业务逻辑。

使用地理定位时的最佳实践

始终清理并节省电池电量

监控地理位置的变化并非免费操作。虽然操作系统可能会引入平台功能,让应用能够接入地理子系统,但作为 Web 开发者,您并不知道用户的设备对监控用户位置的支持情况,而且在监控位置时,您会让设备进行大量额外处理。

当您不再需要跟踪用户的位置时,请调用 clearWatch 以关闭地理定位系统。

妥善处理错误

遗憾的是,并非所有位置查找都能成功。可能是无法定位 GPS,或者用户突然停用了位置信息查找功能。如果发生错误,系统会调用 getCurrentPosition() 的第二个可选参数,以便您在回调中通知用户:

window.onload = function () {
  var startPos;
  var geoSuccess = function (position) {
    startPos = position;
    document.getElementById('startLat').innerHTML = startPos.coords.latitude;
    document.getElementById('startLon').innerHTML = startPos.coords.longitude;
  };
  var geoError = function (error) {
    console.log('Error occurred. Error code: ' + error.code);
    // error.code can be:
    //   0: unknown error
    //   1: permission denied
    //   2: position unavailable (error response from location provider)
    //   3: timed out
  };
  navigator.geolocation.getCurrentPosition(geoSuccess, geoError);
};

减少启动地理定位硬件的需求

在许多用例中,您不需要用户的最新位置信息,而只需要粗略估算的位置信息。

使用 maximumAge 可选属性告知浏览器使用最近获取的地理定位结果。如果用户之前请求过数据,此方法不仅会更快地返回数据,而且还会阻止浏览器启动其地理定位硬件接口(例如 Wi-Fi 三角测量或 GPS)。

window.onload = function () {
  var startPos;
  var geoOptions = {
    maximumAge: 5 * 60 * 1000,
  };

  var geoSuccess = function (position) {
    startPos = position;
    document.getElementById('startLat').innerHTML = startPos.coords.latitude;
    document.getElementById('startLon').innerHTML = startPos.coords.longitude;
  };
  var geoError = function (error) {
    console.log('Error occurred. Error code: ' + error.code);
    // error.code can be:
    //   0: unknown error
    //   1: permission denied
    //   2: position unavailable (error response from location provider)
    //   3: timed out
  };

  navigator.geolocation.getCurrentPosition(geoSuccess, geoError, geoOptions);
};

不要让用户等待,请设置超时

除非您设置了超时,否则您对当前位置的请求可能永远不会返回。

window.onload = function () {
  var startPos;
  var geoOptions = {
    timeout: 10 * 1000,
  };

  var geoSuccess = function (position) {
    startPos = position;
    document.getElementById('startLat').innerHTML = startPos.coords.latitude;
    document.getElementById('startLon').innerHTML = startPos.coords.longitude;
  };
  var geoError = function (error) {
    console.log('Error occurred. Error code: ' + error.code);
    // error.code can be:
    //   0: unknown error
    //   1: permission denied
    //   2: position unavailable (error response from location provider)
    //   3: timed out
  };

  navigator.geolocation.getCurrentPosition(geoSuccess, geoError, geoOptions);
};

首选粗略位置,而非精细位置

如果您想找到距离用户最近的商店,则不太可能需要 1 米的精确度。该 API 旨在提供粗略位置,并尽快返回结果。

如果您确实需要高精度,可以使用 enableHighAccuracy 选项替换默认设置。请谨慎使用此方法:它的解析速度较慢,且耗电量较大。

window.onload = function () {
  var startPos;
  var geoOptions = {
    enableHighAccuracy: true,
  };

  var geoSuccess = function (position) {
    startPos = position;
    document.getElementById('startLat').innerHTML = startPos.coords.latitude;
    document.getElementById('startLon').innerHTML = startPos.coords.longitude;
  };
  var geoError = function (error) {
    console.log('Error occurred. Error code: ' + error.code);
    // error.code can be:
    //   0: unknown error
    //   1: permission denied
    //   2: position unavailable (error response from location provider)
    //   3: timed out
  };

  navigator.geolocation.getCurrentPosition(geoSuccess, geoError, geoOptions);
};

使用 Chrome 开发者工具模拟地理定位

开发者工具中的“传感器”标签页。

设置好地理定位后,您需要:

  • 测试您的应用在不同地理位置的运行情况。
  • 验证您的应用在地理定位不可用时是否会正常降级。

您可以在 Chrome 开发者工具中执行这两项操作。

  1. 打开 Chrome 开发者工具。
  2. 按 Esc 键打开控制台抽屉式导航栏。
  3. 打开控制台抽屉式导航栏菜单
  4. 点击传感器选项,以显示“传感器”标签页。

在这里,您可以将地理位置替换为预设的主要城市、输入自定义地理位置,或通过将替换设置为地理位置不可用来停用地理定位。

反馈