Android地理围栏在没有请求位置更新的情况下未触发。

4

我有一个相当标准的地理围栏设置,完全按照官方文档所述。

因此,有一个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 {
    }
}

好的。问题在于当我进入定义的区域时,地理围栏事件没有触发,直到我在应用上执行了触发requestLocationUpdatesfusedLocationProviderClient上的操作。

以下是执行此操作的代码片段:

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中还是所有操作系统中都有? - Praful Korat
你需要在 Android 11 及以上版本中添加 <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> 来获取地理围栏更新。 - Danial clarc
@Danialclarc 我有这个。不管怎样,我的设备是Android 10。 - Vahid
1个回答

0

请查看以下文件以获取解决方案

在 Android 11 中的清单文件中添加 Google 地图 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)
    }
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接