文档管理中心
指南定位服务Android开发指南地理围栏开发

地理围栏开发

概述

如果您对某些地点比较关注,您可以根据关注地点的位置,创建地理围栏createGeofenceList,地理围栏可以感知当前设备所在位置和您的关注目标之间的距离,当用户进入围栏区域时,会向应用发起通知。同时,您可以检测用户在围栏内的停留时间,当用户在围栏内停留一段时间之后,再发起通知。

约束条件

  • 当前下发的地理围栏,采用的是GNSS/cell作为位置获取方式,推荐使用室外围栏,精度更高。
  • 为了保证地理围栏的精度,建议围栏的最小半径在200米,小于200米不保证其精度。
  • 您可以创建多个围栏,但针对于单个设备的每个应用,最多可以下发100个。

要使用地理围栏服务API,需要确保您的设备已经下载并安装了HMS Core(APK),并将Location Kit的SDK集成到您的项目中。有关详细信息,请参见开发准备。以下仅为代码片段,详情请参见示例代码

说明

地理围栏设置的位置信息使用WGS-84坐标系。

支持地理围栏的设备

请参见12.3 支持地理围栏的设备

指定应用权限

  • 如果需要使用地理围栏服务API,需要在“AndroidManifest.xml”文件中配置ACCESS_FINE_LOCATION权限和ACCESS_COARSE_LOCATION权限:
    收起
    自动换行
    深色代码主题
    复制
    1. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    2. <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
  • 在Android 10版本中,您还需要在“AndroidManifest.xml”文件中配置ACCESS_BACKGROUND_LOCATION权限,确保在后台能够持续定位:
    收起
    自动换行
    深色代码主题
    复制
    1. <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
说明

以上地理围栏相关权限属于危险权限,使用时需要动态申请。

注册静态广播

地理围栏触发信息通过广播接收,需要在“AndroidManifest.xml”文件中注册广播接收器。

收起
自动换行
深色代码主题
复制
  1. <!--注册地理围栏服务广播接收器-->
  2. <receiver
  3. android:name="
    .geofence.GeoFenceBroadcastReceiver
    "
  4. android:exported="true">
  5. <intent-filter>
  6. <action android:name="
    com.huawei.hmssample.geofence.GeoFenceBroadcastReceiver.ACTION_PROCESS_LOCATION
    " />
  7. </intent-filter>
  8. </receiver>

初始化地理围栏客户端

请在主线程中声明GeofenceService类对象,传入Context或Activity类型参数。
Java
Kotlin
收起
自动换行
深色代码主题
复制
  1. private GeofenceService
    geofenceService
    ;
  2. private ArrayList<String>
    idList
    ;
  3. private ArrayList<Geofence>
    geofenceList
    ;
  4. private String
    TAG
    ;
  5. private PendingIntent
    pendingIntent
    ;
  6. // 创建一个新的GeofenceService实例
  7. geofenceService
    = LocationServices.getGeofenceService(this);
  8. // 获取PendingIntent对象
  9. pendingIntent
    = getPendingIntent();
  10. idList
    = new ArrayList<String>();
  11. geofenceList
    = new ArrayList<Geofence>();
收起
自动换行
深色代码主题
复制
  1. private var
    geofenceService
    : GeofenceService? = null
  2. private var
    idList
    : ArrayList<String>? = null
  3. private var
    geofenceList
    : ArrayList<Geofence>? = null
  4. private var
    TAG
    : String? = null
  5. private var
    pendingIntent
    : PendingIntent? = null
  6. // 创建一个新的GeofenceService实例
  7. geofenceService
    = LocationServices.getGeofenceService(this)
  8. // 获取PendingIntent对象
  9. pendingIntent
    = getPendingIntent()
  10. idList
    = ArrayList()
  11. geofenceList
    = ArrayList()

创建并添加地理围栏

您可以先创建地理围栏实例,并构建添加地理围栏的请求。在发送请求之后,会通过Task通知您是否添加成功。

  1. 创建地理围栏实例。
    Java
    Kotlin
    收起
    自动换行
    深色代码主题
    复制
    1. geofenceList
      .add(new Geofence.Builder()
    2. .setUniqueId(
      "mGeofence"
      )
    3. .setValidContinueTime(
      10000
      )
    4. // 传入经纬度信息,圆形地理围栏半径(单位:米)
    5. .setRoundArea(
      latitude
      , longitude,
      radius
      )
    6. // 进入或退出围栏时触发回调
    7. .setConversions(Geofence.ENTER_GEOFENCE_CONVERSION | Geofence.EXIT_GEOFENCE_CONVERSION)
    8. .build());
    9. idList
      .add(
      "mGeofence"
      );
    收起
    自动换行
    深色代码主题
    复制
    1. geofenceList
      !!.add(
    2. Geofence.Builder()
    3. .setUniqueId(
      "mGeofence"
      )
    4. // 传入经纬度信息,圆形地理围栏半径(单位:米)
    5. .setValidContinueTime(
      10000
      )
    6. // 进入或退出围栏时触发回调
    7. .setRoundArea(
      latitude
      ,
      longitude
      ,
      radius
      .toFloat())
    8. .setConversions(Geofence.ENTER_GEOFENCE_CONVERSION or Geofence.EXIT_GEOFENCE_CONVERSION)
    9. .build()
    10. )
    11. idList
      !!.add(
      "mGeofence"
      )

    Geofence.builder的核心方法解析

    展开

    方法名

    参数说明

    返回值说明

    方法效果

    setConversions(int conversions)

    设置地理围栏触发类型,触发类型包含进入(值为1)、退出(值为2)、驻留(值为4)三种,支持“或”位运算

    Geofence.Builder对象

    设置地理围栏触发类型

    setDwellDelayTime(int dwellDelayTime)

    设置地理围栏驻留触发时间,当用户在围栏中并停留超过这个时间,则会触发围栏上报

    Geofence.Builder对象

    设置地理围栏驻留触发时间

    setNotificationInterval(int notificationInterval)

    设置通知响应能力,默认为0秒,如果设置的值较大,可以相应地降低功耗,但是可能会延迟上报围栏事件。

    Geofence.Builder对象

    设置通知响应能力

    setRoundArea(double latitude, double longitude, float radius)

    设置圆形围栏的中心点经纬度和半径

    Geofence.Builder对象

    设置圆形围栏的中心点经纬度和半径

    setUniqueId(String uniqueId)

    设置地理围栏的唯一ID。唯一ID是一个字符串,用于标识地理围栏。当创建地理围栏的uniqueId已存在时,新的围栏会替换旧的围栏。

    Geofence.Builder对象

    设置地理围栏的唯一ID

    setValidContinueTime(long validContinueTime)

    设置地理围栏超时时间。超过该时间,该地理围栏将自动移除。如果值小于0时,地理围栏将会设置为永不过期。

    Geofence.Builder对象

    设置地理围栏超时时间

  2. 创建添加地理围栏的请求。
    Java
    Kotlin
    收起
    自动换行
    深色代码主题
    复制
    1. private GeofenceRequest getAddGeofenceRequest() {
    2. GeofenceRequest.Builder
      builder
      = new GeofenceRequest.Builder();
    3. // 当用户在围栏中时,添加围栏后立即触发回调
    4. builder
      .setInitConversions(GeofenceRequest.ENTER_INIT_CONVERSION);
    5. builder
      .createGeofenceList(
      geofenceList
      );
    6. return
      builder
      .build();
    7. }
    收起
    自动换行
    深色代码主题
    复制
    1. private fun getAddGeofenceRequest(): GeofenceRequest? {
    2. val
      builder
      = GeofenceRequest.Builder()
    3. // 当用户在围栏中时,添加围栏后立即触发回调
    4. builder
      .setInitConversions(GeofenceRequest.ENTER_INIT_CONVERSION)
    5. builder
      .createGeofenceList(
      geofenceList
      )
    6. return
      builder
      .build()
    7. }

    GeofenceRequest.Builder核心方法解析

    展开

    方法名

    参数说明

    返回值说明

    方法效果

    createGeofence(Geofence geofence)

    添加一个地理围栏。

    GeofenceRequest.Builder对象。

    添加单个地理围栏。

    createGeofenceList(List<Geofence> geofences)

    添加多个地理围栏。当前对于每个应用仅支持最多添加100个围栏。

    GeofenceRequest.Builder对象。

    添加多个地理围栏。

    setCoordinateType(int coordinateType)

    设置地理围栏坐标系类型,当前仅支持WGS-84坐标系。

    GeofenceRequest.Builder对象。

    设置地理围栏坐标系。类型

    setInitConversions(int initConversions)

    初始化触发类型,如果设置为0,则参数失效;默认值为GeofenceRequest.ENTER_INIT_CONVERSION | GeofenceRequest.DWELL_INIT_CONVERSION

    GeofenceRequest.Builder对象。

    设置初始化触发类型。

  3. 动态注册GeoFenceBroadcastReceiver广播接收器。
    Java
    Kotlin
    收起
    自动换行
    深色代码主题
    复制
    1. // 通过PendingIntent动态注册GeoFenceBroadcastReceiver广播接收器,当触发围栏的时候,会通过广播通知。
    2. private PendingIntent getPendingIntent() {
    3. Intent
      intent
      = new Intent(this,
      GeoFenceBroadcastReceiver.class
      );
    4. intent
      .setAction(
      GeoFenceBroadcastReceiver.ACTION_PROCESS_LOCATION
      );
    5. if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
    6. return PendingIntent.getBroadcast(this, 0,
      intent
      , PendingIntent.FLAG_UPDATE_CURRENT);
    7. } else {
    8. // 针对android12及以上设备需要主动配置pendingIntent的可变性,默认配置PendingIntent.FLAG_MUTABLE
    9. // 如果compileSdkVersion为30及以下,可将PendingIntent.FLAG_MUTABLE用 1<<25 替换
    10. // buildToolsVersion为31及以上才可使用PendingIntent.FLAG_MUTABLE
    11. return PendingIntent.getBroadcast(this, 0,
      intent
      ,
    12. PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
    13. }
    14. }
    收起
    自动换行
    深色代码主题
    复制
    1. // 通过PendingIntent动态注册GeoFenceBroadcastReceiver广播接收器,当触发围栏的时候,会通过广播通知。
    2. private fun getPendingIntent(): PendingIntent? {
    3. val
      intent
      = Intent(this,
      GeoFenceBroadcastReceiver::class.java
      )
    4. intent.action =
      GeoFenceBroadcastReceiver.ACTION_PROCESS_LOCATION
    5. return if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
    6. PendingIntent.getBroadcast(this, 0,
      intent
      , PendingIntent.FLAG_UPDATE_CURRENT)
    7. } else {
    8. // 针对android12及以上设备需要主动配置pendingIntent的可变性,默认配置PendingIntent.FLAG_MUTABLE
    9. // 如果compileSdkVersion为30及以下,可将PendingIntent.FLAG_MUTABLE用 1<<25 替换
    10. // buildToolsVersion为31及以上才可使用PendingIntent.FLAG_MUTABLE
    11. PendingIntent.getBroadcast(
    12. this,
    13. 0,
    14. intent
      ,
    15. PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
    16. )
    17. }
    18. }
  4. 发送添加地理围栏请求。
    Java
    Kotlin
    收起
    自动换行
    深色代码主题
    复制
    1. // 通过传入PendingIntent的方式添加地理围栏,并处理地理围栏添加行为的响应数据
    2. geofenceService
      .createGeofenceList(getAddGeofenceRequest(),
      pendingIntent
      )
    3. .addOnCompleteListener(new OnCompleteListener<Void>() {
    4. @Override
    5. public void onComplete(Task<Void>
      task
      ) {
    6. if (task.isSuccessful()) {
    7. // TODO: 添加围栏成功处理
    8. } else {
    9. // TODO: 添加围栏失败处理
    10. }
    11. }
    12. });
    收起
    自动换行
    深色代码主题
    复制
    1. // 通过传入PendingIntent的方式添加地理围栏,并处理地理围栏添加行为的响应数据
    2. geofenceService
      .createGeofenceList(getAddGeofenceRequest(),
      pendingIntent
      )
    3. .addOnCompleteListener(OnCompleteListener<Void?> { task ->
    4. if (task.isSuccessful) {
    5. // TODO: 添加围栏成功处理
    6. } else {
    7. // TODO: 添加围栏失败处理
    8. }
    9. })
  5. 地理围栏触发信息处理。
    当检测到用户触发围栏事件时,会通过PendingIntent发送广播通知用户。
    Java
    Kotlin
    收起
    自动换行
    深色代码主题
    复制
    1. // 地理围栏服务广播接收器
    2. public class
      GeoFenceBroadcastReceiver
      extends BroadcastReceiver {
    3. public static final String
      ACTION_PROCESS_LOCATION
      =
    4. "com.huawei.hmssample.geofence.GeoFenceBroadcastReceiver.ACTION_PROCESS_LOCATION";
    5. @Override
    6. public void onReceive(Context
      context
      , Intent
      intent
      ) {
    7. if (
      intent
      != null) {
    8. final String
      action
      =
      intent
      .getAction();
    9. if (
      ACTION_PROCESS_LOCATION
      .equals(
      action
      )) {
    10. // 从intent中解析出GeofenceData对象
    11. GeofenceData
      geofenceData
      = GeofenceData.getDataFromIntent(
      intent
      );
    12. if (
      geofenceData
      != null) {
    13. // 获取错误码
    14. int
      errorCode
      =
      geofenceData
      .getErrorCode();
    15. // 获取地理围栏触发类型
    16. int
      conversion
      =
      geofenceData
      .getConversion();
    17. // 获取触发的地理围栏信息
    18. List<Geofence>
      list
      =
      geofenceData
      .getConvertingGeofenceList();
    19. // 获取触发时的位置信息
    20. Location
      mLocation
      =
      geofenceData
      .getConvertingLocation();
    21. // 是否是正常触发围栏事件,返回false时表示出现错误
    22. boolean
      status
      =
      geofenceData
      .isSuccess();
    23. // TODO: 您可以根据返回的地理围栏信息,做相应的
    24. }
    25. }
    26. }
    27. }
    28. }
    收起
    自动换行
    深色代码主题
    复制
    1. // 地理围栏服务广播接收器
    2. class
      GeoFenceBroadcastReceiver
      : BroadcastReceiver() {
    3. override fun onReceive(
    4. context
      : Context,
    5. intent
      : Intent
    6. ) {
    7. if (
      intent
      != null) {
    8. val
      action
      =
      intent
      .action
    9. if (
      ACTION_PROCESS_LOCATION
      ==
      action
      ) {
    10. // 从intent中解析出GeofenceData对象
    11. val
      geofenceData
      = GeofenceData.getDataFromIntent(
      intent
      )
    12. if (
      geofenceData
      != null) {
    13. // 获取错误码
    14. val
      errorCode
      =
      geofenceData
      .errorCode
    15. // 获取地理围栏触发类型
    16. val
      conversion
      =
      geofenceData
      .conversion
    17. // 获取触发的地理围栏信息
    18. val
      list
      =
      geofenceData
      .convertingGeofenceList
    19. // 获取触发时的位置信息
    20. val
      mLocation
      : Location =
      geofenceData
      .convertingLocation
    21. // 是否是正常触发围栏事件,返回false时表示出现错误
    22. val
      status
      =
      geofenceData
      .isSuccess
    23. // TODO:您可以根据返回的地理围栏信息,做相应的处理
    24. }
    25. }
    26. }
    27. }
    28. companion object {
    29. const val
      ACTION_PROCESS_LOCATION
      =
    30. "com.huawei.hmssample.geofence.GeoFenceBroadcastReceiver.ACTION_PROCESS_LOCATION"
    31. }
    32. }
  6. 移除地理围栏。除了通过id移除地理围栏,您还可以通过PendingIntent进行移除。
    Java
    Kotlin
    收起
    自动换行
    深色代码主题
    复制
    1. // 通过围栏id移除地理围栏,并处理地理围栏移除行为的响应数据
    2. geofenceService
      .deleteGeofenceList(
      idList
      ).addOnCompleteListener(new OnCompleteListener<Void>() {
    3. @Override
    4. public void onComplete(Task<Void>
      task
      ) {
    5. if (task.isSuccessful()) {
    6. // TODO: 移除围栏成功处理
    7. } else {
    8. // TODO: 移除围栏失败处理
    9. }
    10. }
    11. });
    收起
    自动换行
    深色代码主题
    复制
    1. // 通过围栏id移除地理围栏,并处理地理围栏移除行为的响应数据
    2. geofenceService
      .deleteGeofenceList(
      idList
      )
    3. .addOnCompleteListener(OnCompleteListener<Void?> { task ->
    4. if (task.isSuccessful) {
    5. // TODO: 移除围栏成功处理
    6. } else {
    7. // TODO: 移除围栏失败处理
    8. }
    9. })
在 指南 中进行搜索
请输入您想要搜索的关键词