连续定位

连续定位用于持续接收位置变化。

本文档介绍连续定位的接口、生命周期、相关事件流以及前台 / 后台定位的处理方式。



接口签名

class TencentLocationManager {
  Future<void> startContinuousLocation(TencentLocationRequest request);
  Future<void> stopContinuousLocation();

  Stream<TencentLocation> get onLocationChanged;
  Stream<TencentLocationError> get onLocationError;
  Stream<TencentDeviceStatus> get onStatusChanged;
}

调用顺序:

  1. 创建 TencentLocationManager 实例。

  2. 订阅 onLocationChanged / onLocationError 等事件流。

  3. 调用 startContinuousLocation(request) 启动连续定位。

  4. 在不再需要定位时调用 stopContinuousLocation(),并调用 dispose() 释放管理器。

启动连续定位

final manager = TencentLocationManager();

final locationSubscription = manager.onLocationChanged.listen((location) {
  print('新位置:${location.latitude}, ${location.longitude}, '
      'accuracy=${location.accuracy}, source=${location.source}');
});

final errorSubscription = manager.onLocationError.listen((error) {
  print('定位错误:${error.code} ${error.message}');
});

final request = TencentLocationRequest.create()
  ..setRequestLevel(RequestLevel.adminArea)
  ..setCoordinateType(CoordinateType.gcj02)
  ..setInterval(const Duration(seconds: 3));

await manager.startContinuousLocation(request);

setInterval 配置位置回调的最小间隔,建议不小于 1 秒。

注意:在同一个 TencentLocationManager 实例上重复调用 startContinuousLocation 会抛出 TencentLocationError,错误码为 alreadyStarted。如需修改请求参数,请先调用 stopContinuousLocation() 再重新启动。

停止与释放

await locationSubscription.cancel();
await errorSubscription.cancel();
await manager.stopContinuousLocation();
await manager.dispose();

dispose() 是幂等的,可以多次调用。dispose 之后再调用本实例的任何方法都会抛出 StateError

stopContinuousLocation 在未启动连续定位时调用是安全的,不会抛错。

事件流详解

onLocationChanged

每次产生新的定位结果时回调,回调的 TencentLocation 字段含义与 单次定位 章节中说明一致。

onLocationChanged 是一个广播流,可以被多次订阅,所有订阅者都会收到事件。

onLocationError

定位过程中产生的错误会通过本流回调,例如网络异常、定位失败等。错误对象同样为 TencentLocationError,错误码列表见 错误码

onStatusChanged(设备状态)

随连续定位一并产生的 GPS / Wi-Fi / 蜂窝网络 / 定位总开关等状态变化事件。

final statusSubscription = manager.onStatusChanged.listen((status) {
  print('设备状态变化:kind=${status.kind}, status=${status.status}, '
      'description=${status.description}');
});

TencentDeviceStatus 包含三个字段:

字段 类型 说明
kind DeviceStatusKind 状态类别:gps / wifi / cellular / vpn / locationSwitch
status DeviceStatus 当前状态:available / enabledButUnavailable / disabled / denied / unknown
description String? 系统提供的额外描述文本(可能为空)

平台支持:

  • Android:完整支持,事件随连续定位回调一并产生

  • iOS:iOS 系统层面对插件不开放等价的状态回调,订阅本流不会抛异常但也不会收到事件

  • HarmonyOS:支持,事件类型覆盖蜂窝网络 / Wi-Fi / VPN 网络可用性、定位总开关状态等

如果你的业务对设备状态有跨端一致需求,建议结合 错误码 中的错误回调(例如 permissionDenied / locationSwitchOff)一并处理。

调整回调频率

启动连续定位之后,可以使用 changeCallbackInterval 动态修改回调间隔,避免重新启动定位带来的开销:

await manager.changeCallbackInterval(const Duration(seconds: 5));

平台支持:

  • Android:支持

  • iOS:不支持,调用会抛出 TencentLocationError,错误码为 unsupportedOnThisPlatform

  • HarmonyOS:不支持,鸿蒙原生 SDK 需要 stop→改 request→start 才能改回调间隔,调用会抛出 TencentLocationError,错误码为 unsupportedOnThisPlatform

如需在 iOS / HarmonyOS 端调整频率,建议先 stopContinuousLocation(),重新构造请求并 startContinuousLocation

获取最近一次定位结果

final last = await manager.getLastLocation();
if (last != null) {
  print('最近一次位置:${last.latitude}, ${last.longitude}');
}

平台支持:

  • Android:支持

  • iOS:不支持,调用会抛出 TencentLocationError,错误码为 unsupportedOnThisPlatform

  • HarmonyOS:支持

前台定位(保持后台运行)

应用进入后台后,Android 系统可能会收紧后台定位频率甚至完全停止后台定位。如需在后台稳定接收定位回调,可以启用前台服务:

await manager.enableForeground(
  notificationId: 1001,
  channelId: 'location_channel',
  title: '正在为您提供定位服务',
  text: '点击返回应用',
  smallIconResourceName: 'ic_launcher',
);

参数说明:

  • notificationId:通知 ID,必须大于 0

  • channelId:Android 8.0 及以上必填的 NotificationChannel ID

  • title / text:通知栏展示的标题与正文文案

  • smallIconResourceName:通知小图标的资源名(位于 mipmap / drawable 目录下,不含扩展名);为空时使用应用默认图标

不再需要前台服务时调用:

await manager.disableForeground();

平台支持:

  • Android:支持

  • iOS:不支持,调用会抛出 TencentLocationError,错误码为 unsupportedOnThisPlatform

  • HarmonyOS:不支持,鸿蒙的后台定位由 后台定位任务 一节的独立接口提供,不共用同一套 API

iOS 端的后台定位通过在 Info.plist 中勾选 UIBackgroundModeslocation 启用,并在请求权限时申请「始终允许」(requestIosAlwaysAuthorization)。

后台定位任务(HarmonyOS 独有)

HarmonyOS 提供独立的后台定位任务接口,用于让应用在进入后台后仍可持续接收位置回调:

await manager.startBackgroundLocationTask();

// 不再需要后台定位时:
await manager.stopBackgroundLocationTask();

startBackgroundLocationTask 接受一个可选参数 wantAgentInfo:需要自定义后台任务通知点击行为时,传入鸿蒙 wantAgent.WantAgentInfo 对应的 map(key 与鸿蒙 API 一致,原样透传);不传时使用系统默认行为。

调用 startBackgroundLocationTask 时,系统会通过通知栏显示一条常驻通知向用户表明后台定位正在进行;点击通知会拉起应用自身的 Ability。

平台支持:

  • Android:不支持,调用会抛出 TencentLocationError,错误码为 unsupportedOnThisPlatform。Android 端请使用上一节的 前台定位 接口。

  • iOS:不支持,调用会抛出 TencentLocationError,错误码为 unsupportedOnThisPlatform。iOS 端请在 Info.plist 中勾选 UIBackgroundModeslocation,并申请「始终允许」授权。

  • HarmonyOS:支持

调用前请确认已在 entry/src/main/module.json5 中声明 ohos.permission.LOCATION_IN_BACKGROUND 并申请到用户授权。

完整示例

import 'dart:async';

import 'package:tencent_location_flutter_plugin/tencent_location_flutter_plugin.dart';

class LocationService {
  final TencentLocationManager _manager = TencentLocationManager();
  StreamSubscription<TencentLocation>? _locationSub;
  StreamSubscription<TencentLocationError>? _errorSub;
  Future<void> start() async {
    _locationSub = _manager.onLocationChanged.listen((location) {
      print('位置更新:${location.latitude}, ${location.longitude}');
    });
    _errorSub = _manager.onLocationError.listen((error) {
      print('定位错误:${error.code} ${error.message}');
    });

    final request = TencentLocationRequest.create()
      ..setRequestLevel(RequestLevel.adminArea)
      ..setCoordinateType(CoordinateType.gcj02)
      ..setInterval(const Duration(seconds: 3));

    await _manager.startContinuousLocation(request);
  }

  Future<void> stop() async {
    await _manager.stopContinuousLocation();
    await _locationSub?.cancel();
    await _errorSub?.cancel();
    await _manager.dispose();
  }
}
本页内容