Geofencing in background on Android 8 or 9 does not work

前端 未结 2 1678
执笔经年
执笔经年 2020-12-16 22:33

I try to make appear a push alert to the user when he reach a defined zone.

So I coded my app from : https://developer.android.com/training/location/geofencing

相关标签:
2条回答
  • 2020-12-16 23:12

    I think I found a solution, tested on Android 9. I used the Google documentation https://developer.android.com/training/location/geofencing but I replaced the service by a broadcast receiver.

    My GeofenceManager :

    private val braodcastPendingIntent: PendingIntent
        get() {
            val intent = Intent(mContext, GeofenceTransitionsBroadcastReceiver::class.java)
            val pending = PendingIntent.getBroadcast(
                    mContext.applicationContext,
                    0,
                    intent,
                    PendingIntent.FLAG_UPDATE_CURRENT)
            return pending
        }
    
     fun createGeofenceAlerts(latLng: LatLng, radiusMeter: Int, isBroadcast: Boolean) {
        val enter = buildGeofence(ID_ENTER, latLng, radiusMeter, Geofence.GEOFENCE_TRANSITION_ENTER)
        val exit = buildGeofence(ID_EXIT, latLng, radiusMeter, Geofence.GEOFENCE_TRANSITION_EXIT)
        val dwell = buildGeofence(ID_DWELL, latLng, radiusMeter, Geofence.GEOFENCE_TRANSITION_DWELL)
    
        val request = GeofencingRequest.Builder()
                .setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
                .addGeofence(enter)
                .addGeofence(exit)
                .addGeofence(dwell)
                .build()
    
        val pending = if (isBroadcast) {
            braodcastPendingIntent
        } else {
            servicePendingIntent
        }
        fencingClient.addGeofences(request, pending).addOnSuccessListener {
            Timber.i("succes")
            Toast.makeText(mContext, "Geofence added", Toast.LENGTH_LONG).show()
        }.addOnFailureListener { e ->
            Timber.e(e, "failure")
            Toast.makeText(mContext, "Geofence ERROR", Toast.LENGTH_LONG).show()
        }
    }
    
    private fun buildGeofence(id: String, center: LatLng, radius: Int, transitionType: Int): Geofence {
        val builder = Geofence.Builder()
                // 1
                .setRequestId(id)
                // 2
                .setCircularRegion(
                        center.latitude,
                        center.longitude,
                        radius.toFloat())
                // 3
                .setTransitionTypes(transitionType)
                // 4
                .setExpirationDuration(Geofence.NEVER_EXPIRE)
        if (transitionType == Geofence.GEOFENCE_TRANSITION_DWELL) {
            builder.setLoiteringDelay(LOITERING_DELAY)
        }
    
        return builder.build()
    }
    

    My BroadcastReceiver, obviously you need to declare it in the manfifest :

    class GeofenceTransitionsBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Timber.i("received")
        val geofencingEvent = GeofencingEvent.fromIntent(intent)
        if (geofencingEvent.hasError()) {
            Timber.e("Geofence error")
            return
        }
    
        // Get the transition type.
        val geofenceTransition = geofencingEvent.geofenceTransition
    
        // Test that the reported transition was of interest.
        if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER || geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT
                || geofenceTransition == Geofence.GEOFENCE_TRANSITION_DWELL) {
    
            // Get the geofences that were triggered. A single event can trigger
            // multiple geofences.
            val triggeringGeofences = geofencingEvent.triggeringGeofences
    
            // Get the transition details as a String.
            val geofenceTransitionDetails = GeofenceManager.getGeofenceTransitionDetails(
                    geofenceTransition,
                    triggeringGeofences, true
            )
    
            // Send notification and log the transition details.
            GeofenceManager.sendNotification(context, geofenceTransition, geofenceTransitionDetails)
            Timber.i(geofenceTransitionDetails)
        } else {
            // Log the error.
            Timber.e("Unknown geo event : %d", geofenceTransition)
        }
    }
    

    The important part is to know that on Android 8 and 9 the geofencing has a latency of 2 minutes.

    0 讨论(0)
  • 2020-12-16 23:22

    I have been working with GeoFence for such a long time, I had the same question and I got the answer by myself after trying different solutions, So basically, GeoFence only get triggers if any app in the phone is fetching the location for some x duration. If you test the GeoFence sample app provided by google then you can see that the app works only when you open the Google maps application, its because Google Maps is the only app in the device that requests locations passively.

    For Prove you can clone GeoFence sample and the LocationUpdateForGroundService sample from this below link https://github.com/googlesamples/android-play-location Run both of them GeoFence and LocationUpdateForGroundService at the same time, You will notice by changing the lat and long from the emulator that now you dont need to open Google maps any more because now there is another app which is requesting location.

    So do create a foreground service in the GeoFence application and use Fuse Location Client to request location updates for some x duration.

    0 讨论(0)
提交回复
热议问题