You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android API31下GeoFence进入区域不触发问题求助

解决GeoFence仅当前位置触发、其他区域无响应的问题

核心问题分析

1. 所有Geofence共用同一RequestId

代码中所有Geofence都使用固定常量GEOFENCE_ID作为唯一标识:

.setRequestId(GEOFENCE_ID)

Google Play Services会将相同RequestId的Geofence判定为同一对象,新添加的Geofence会直接覆盖旧的,最终仅最后创建的Geofence生效。

2. PendingIntent的requestCode固定为0

每次创建PendingIntent时requestCode始终传0:

val pendingIntent = PendingIntent.getBroadcast(applicationContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)

配合FLAG_UPDATE_CURRENT参数,后续创建的PendingIntent会完全替换之前的实例,导致所有Geofence触发时都只会调用最新的Intent逻辑,旧Geofence的触发信息被覆盖。

3. API31适配的补充说明

你已经添加了FLAG_MUTABLE适配API31+的PendingIntent要求,这部分是正确的,但需要配合前两个问题的修复才能让多Geofence逻辑正常运行。

修复步骤

步骤1:为每个Geofence分配唯一RequestId

使用Firebase生成的唯一key作为Geofence的RequestId,确保每个区域标识不重复:

val geofence = Geofence.Builder()
    .setRequestId(key) // 替换固定常量为Firebase唯一key
    .setCircularRegion(location.latitude, location.longitude, GEOFENCE_RADIUS.toFloat())
    .setExpirationDuration(GEOFENCE_EXPIRATION.toLong())
    .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_DWELL)
    .setLoiteringDelay(GEOFENCE_DWELL_DELAY)
    .build()

步骤2:为每个PendingIntent使用唯一requestCode

用key的哈希值作为requestCode,保证每个PendingIntent实例独立:

// 基于唯一key生成不重复的requestCode
val requestCode = key.hashCode()
val pendingIntent = PendingIntent.getBroadcast(applicationContext, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)

步骤3:优化GeofenceReceiver的触发逻辑(可选但推荐)

避免依赖Intent Extra传递数据(App被杀后Extra可能丢失),改为通过触发的Geofence的RequestId从Firebase拉取对应信息:

class GeofenceReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        val geofencingEvent = GeofencingEvent.fromIntent(intent)
        if (geofencingEvent.hasError()) return

        val transitionType = geofencingEvent.geofenceTransition
        if (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER || transitionType == Geofence.GEOFENCE_TRANSITION_DWELL) {
            val triggeringGeofences = geofencingEvent.triggeringGeofences
            for (geofence in triggeringGeofences) {
                val geofenceId = geofence.requestId
                // 从Firebase获取对应提醒信息
                val database = Firebase.database
                val reference = database.getReference("reminders").child(geofenceId)
                reference.addListenerForSingleValueEvent(object : ValueEventListener {
                    override fun onDataChange(snapshot: DataSnapshot) {
                        snapshot.getValue(Reminder::class.java)?.let {
                            MapsActivity.showNotification(context, it.message)
                        }
                    }

                    override fun onCancelled(error: DatabaseError) {}
                })
            }
        }
    }
}

步骤4:确认后台定位权限

API31+必须获取ACCESS_BACKGROUND_LOCATION权限,且用户需在系统设置中允许App的后台定位权限,否则Geofence在后台无法触发。

修改后的完整createGeoFence函数

private fun createGeoFence(location: LatLng, key: String, geofencingClient: GeofencingClient) {
    val geofence = Geofence.Builder()
        .setRequestId(key)
        .setCircularRegion(location.latitude, location.longitude, GEOFENCE_RADIUS.toFloat())
        .setExpirationDuration(GEOFENCE_EXPIRATION.toLong())
        .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_DWELL)
        .setLoiteringDelay(GEOFENCE_DWELL_DELAY)
        .build()

    val geofenceRequest = GeofencingRequest.Builder()
        .setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
        .addGeofence(geofence)
        .build()

    val intent = Intent(this, GeofenceReceiver::class.java)
        .putExtra("key", key)
        .putExtra("message", "Entrada detectada al radio - ${location.latitude}, ${location.longitude}")

    val requestCode = key.hashCode()
    val pendingIntent = PendingIntent.getBroadcast(applicationContext, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)

    if (ContextCompat.checkSelfPermission(
            applicationContext, Manifest.permission.ACCESS_BACKGROUND_LOCATION
        ) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(
            this,
            arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
            GEOFENCE_LOCATION_REQUEST_CODE
        )
    } else {
        geofencingClient.addGeofences(geofenceRequest, pendingIntent)
    }
}

内容的提问来源于stack exchange,提问作者Lucho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 14:00:59