在Android 8或9上在后台进行地理围栏操作不起作用

时间:2019-01-24 13:44:39

标签: android background location maps geofencing

当用户到达定义的区域时,我会尝试向用户显示推送警报。

所以我从以下位置对我的应用进行了编码:https://developer.android.com/training/location/geofencing

如果我的应用程序按照用户的位置运行并带有服务,则运行良好。

例如,如果我启动google map,它也可以工作,它也可以跟踪我的位置。将会出现推送。

但是,如果我关闭我的应用程序,则不会出现该推送,因此如果没有应用程序在跟踪我的位置,则不会检测到地理围栏。

正常吗? 如何使其始终有效? 如果需要在您所在的位置跟随前台服务,地理围栏的目的是什么?

 public void createGeofenceAlerts(LatLng latLng, int radius) {
    final Geofence enter = buildGeofence(ID_ENTER, latLng, radius, Geofence.GEOFENCE_TRANSITION_ENTER);
    final Geofence exit = buildGeofence(ID_EXIT, latLng, radius, Geofence.GEOFENCE_TRANSITION_EXIT);
    final Geofence dwell = buildGeofence(ID_DWELL, latLng, radius, Geofence.GEOFENCE_TRANSITION_DWELL);

    GeofencingRequest request = new GeofencingRequest.Builder()
            .setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
            .addGeofence(enter)
            .addGeofence(exit)
            .addGeofence(dwell)
            .build();

    fencingClient.addGeofences(request, getGeofencePendingIntent()).addOnSuccessListener(new OnSuccessListener<Void>() {
        @Override
        public void onSuccess(Void aVoid) {
            Timber.i("succes");
            Toast.makeText(mContext, "Geofence added", Toast.LENGTH_LONG).show();
        }
    }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            Timber.e(e,"failure");
            Toast.makeText(mContext, "Geofence ERROR", Toast.LENGTH_LONG).show();
        }
    });
}

private PendingIntent getGeofencePendingIntent() {
    Intent intent = new Intent(mContext, GeofenceTransitionsIntentService.class);
    PendingIntent pending = PendingIntent.getService(
            mContext,
            0,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT);
    return pending;
}

private Geofence buildGeofence(String id, LatLng center, int radius, int transitionType) {
    Geofence.Builder builder = new Geofence.Builder()
            // 1
            .setRequestId(id)
            // 2
            .setCircularRegion(
                    center.getLatitude(),
                    center.getLongitude(),
                    radius)
            // 3
            .setTransitionTypes(transitionType)
            // 4
            .setExpirationDuration(Geofence.NEVER_EXPIRE);
    if (transitionType == Geofence.GEOFENCE_TRANSITION_DWELL) {
        builder.setLoiteringDelay(LOITERING_DELAY);
    }

    return builder.build();
}

3 个答案:

答案 0 :(得分:2)

我想我找到了在Android 9上测试过的解决方案。我使用了Google文档https://developer.android.com/training/location/geofencing,但我用广播接收器代替了该服务。

我的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()
}

我的BroadcastReceiver,显然您需要在清单中声明它:

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)
    }
}

重要的是要知道,在Android 8和9上,地理围栏的延迟为2分钟。

答案 1 :(得分:0)

我已经与GeoFence合作了很长时间,我遇到了同样的问题,在尝试了不同的解决方案后我自己得到了答案。因此,基本上,如果手机中的任何应用程序正在获取地理位置信息,则GeoFence只会触发大约x的持续时间。如果您测试了由Google提供的GeoFence示例应用程序,则可以看到该应用程序仅在打开Goog​​le Maps应用程序后才能运行,因为Google Maps是设备中唯一被动请求位置的应用程序。

为了证明,您可以从下面的链接中克隆GeoFence示例和LocationUpdateForGroundService示例 https://github.com/googlesamples/android-play-location 同时运行两个GeoFence和LocationUpdateForGroundService,您会注意到通过从模拟器更改纬度和经度,您现在不再需要打开Goog​​le地图,因为现在有另一个应用程序正在请求位置。

因此,请务必在GeoFence应用程序中创建前台服务,并使用Fuse Location Client请求在x持续时间内进行位置更新。

答案 2 :(得分:0)

操作系统不允许应用从后台获取位置更新。在前台服务上实施地理围栏位置代码。它将按预期运行