没有 requestLocationUpdates 不会触发 Android 地理围栏
Posted
技术标签:
【中文标题】没有 requestLocationUpdates 不会触发 Android 地理围栏【英文标题】:Android geo-fence is not triggering without requestLocationUpdates 【发布时间】:2021-11-03 02:59:48 【问题描述】:我有一个非常标准的地理围栏设置。与this official doco 中的描述完全相同。
所以有一个 GeofenceBroadcastReceiver
和一个 onReceive
方法应该在地理围栏事件发生时触发。
以下是地理围栏区域的声明方式:
val list = workAreas.map
Geofence.Builder().setRequestId(it.id.toString())
.setCircularRegion(it.latLng.latitude, it.latLng.longitude, it.radius)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_EXIT)
.build()
val request = GeofencingRequest.Builder()
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
.addGeofences(list).build()
client.addGeofences(request, geofencePendingIntent).run
addOnSuccessListener
addOnFailureListener
好的。所以问题是当我进入一个定义的区域时地理围栏事件不会触发。直到我在fusedLocationProviderClient
上触发requestLocationUpdates
的应用程序上做一些事情。
这是完成这项工作的片段:
val request = LocationRequest.create().apply
interval = 5000
fastestInterval = 5000
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
maxWaitTime = 1000
Looper.myLooper()?.let looper ->
fusedLocationProviderClient.requestLocationUpdates(
request,
locationCallback,
looper
)
这不可能吧?您不能一直运行位置更新。这不是它在早期版本中的工作方式(你知道,JobIntentService
)。
那么我在这里遗漏了什么吗?
【问题讨论】:
这个问题只出现在 android 11 或所有操作系统中? 您需要为 android 11 及更高版本添加检查以下文件以了解您的解决方案
在 Android 11 的清单和后台位置权限中添加 Google Map API 密钥
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.recycler.geofencingdemo">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".GeofenceRegistrationService"
android:enabled="true"
android:exported="true"/>
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<!--
The API key for Google Maps-based APIs.
-->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_map_key" />
</application>
</manifest>
GeofenceRegistrationService.kt
package com.recycler.geofencingdemo
import android.app.*
import android.content.Context
import android.content.Intent
import android.os.Build
import android.text.TextUtils
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.app.TaskStackBuilder
import com.google.android.gms.location.Geofence
import com.google.android.gms.location.GeofenceStatusCodes
import com.google.android.gms.location.GeofencingEvent
import com.google.android.gms.maps.model.LatLng
import java.util.*
class GeofenceRegistrationService : IntentService(TAG)
override fun onHandleIntent(intent: Intent?)
val geofencingEvent = GeofencingEvent.fromIntent(intent)
if (geofencingEvent.hasError())
Log.d(TAG, "GeofencingEvent error " + geofencingEvent.errorCode)
else
val transaction = geofencingEvent.geofenceTransition
val geofences = geofencingEvent.triggeringGeofences
val geofence = geofences[0]
if (transaction == Geofence.GEOFENCE_TRANSITION_ENTER && geofence.requestId == Constants.GEOFENCE_ID)
Log.d(TAG, "You are inside Tacme")
else
Log.d(TAG, "You are outside Tacme")
val geofenceTransitionDetails = getGeofenceTrasitionDetails(transaction, geofences)
Constants.AREA_LANDMARKS[Constants.GEOFENCE_ID]?.let sendNotification(applicationContext,geofenceTransitionDetails, it)
// Create a detail message with Geofences received
private fun getGeofenceTrasitionDetails(geoFenceTransition: Int, triggeringGeofences: List<Geofence>): String
// get the ID of each geofence triggered
val triggeringGeofencesList = ArrayList<String?>()
for (geofence in triggeringGeofences)
triggeringGeofencesList.add(geofence.requestId)
var status: String? = null
if (geoFenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER) status = "Entering " else if (geoFenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) status = "Exiting "
return status + TextUtils.join(", ", triggeringGeofencesList)
fun sendNotification(context: Context, message: String, latLng: LatLng)
val notificationManager = context
.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
&& notificationManager.getNotificationChannel(Companion.NOTIFICATION_CHANNEL_ID) == null)
val name = context.getString(R.string.app_name)
val channel = NotificationChannel(Companion.NOTIFICATION_CHANNEL_ID,
name,
NotificationManager.IMPORTANCE_DEFAULT)
notificationManager.createNotificationChannel(channel)
val intent = MainActivity.newIntent(context.applicationContext, latLng)
val stackBuilder = TaskStackBuilder.create(context)
.addParentStack(MainActivity::class.java)
.addNextIntent(intent)
val notificationPendingIntent = stackBuilder
.getPendingIntent(getUniqueId(), PendingIntent.FLAG_UPDATE_CURRENT)
val notification = NotificationCompat.Builder(context, Companion.NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(message)
.setContentIntent(notificationPendingIntent)
.setAutoCancel(true)
.build()
notificationManager.notify(getUniqueId(), notification)
private fun getUniqueId() = ((System.currentTimeMillis() % 10000).toInt())
companion object
private const val TAG = "GeoIntentService"
// Handle errors
private fun getErrorString(errorCode: Int): String
return when (errorCode)
GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE -> "GeoFence not available"
GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES -> "Too many GeoFences"
GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS -> "Too many pending intents"
else -> "Unknown error."
private const val NOTIFICATION_CHANNEL_ID = BuildConfig.APPLICATION_ID + ".channel"
Constants.kt
package com.recycler.geofencingdemo
import com.google.android.gms.maps.model.LatLng
import java.util.*
object Constants
//Location
const val GEOFENCE_ID = "TACME"
const val GEOFENCE_RADIUS_IN_METERS = 100f
/**
* Map for storing information about tacme in the dubai.
*/
val AREA_LANDMARKS = HashMap<String, LatLng>()
init
// Tacme
AREA_LANDMARKS[GEOFENCE_ID] = LatLng(48.8603, 2.2914)
【讨论】:
以上是关于没有 requestLocationUpdates 不会触发 Android 地理围栏的主要内容,如果未能解决你的问题,请参考以下文章
Android requestLocationUpdates 没有 minDistance
如何等待 requestLocationUpdates() 回调意图完成?
为多个提供者使用 requestLocationUpdates
Android FusedLocationProviderClient.requestLocationUpdates() 返回相同的位置坐标
Android FusedLocationProviderClient.requestLocationUpdates()返回相同的位置坐标。