React-native-background-geolocation: GEOFENCE intent no longer being sent as of 2.8.3 (Android)

Created on 26 Jun 2017  ยท  25Comments  ยท  Source: transistorsoft/react-native-background-geolocation

Your Environment

  • Plugin version: 2.8.3
  • Platform: Android
  • OS version: 6.0
  • Device manufacturer / model: Pixel 5 Emulator
  • React Native version (react-native -v): 0.45
  • Plugin config: https://pastebin.com/rAsP0jDy

Expected Behavior


com.transistorsoft.locationmanager.event.GEOFENCE should be broadcasted when encountering Geofence hits. This was working fine in 2.8.1 (note: have not tested 2.8.2)

Actual Behavior


com.transistorsoft.locationmanager.event.GEOFENCE broadcast action no longer received by BroadcastReceiver registered.

Steps to Reproduce

https://pastebin.com/Xf2Hj1zY

Context


I'm using the com.transistorsoft.locationmanager.event.GEOFENCE broadcast intent to do display a local native notification using native code. When the user clicks on this notification, they are deep-link'd into the react native app.

It was working fine while I was on 2.8.1. I upgraded to 2.8.3 and it seems to have stopped working. The TSLocationManager is alerting correctly for encountered geofences, but the broadcast is not being sent. If I set up a catch all TSLocationManager intent filters (eg. GEOFENCESCHANGE, LOCATION etc), then I receive some of those, but not GEOFENCE.

Debug logs

https://pastebin.com/jG73xHty

Most helpful comment

Try installing from branch geofence-broadcast-issue

All 25 comments

Ok, I figured it out after many hours of debugging. It looks like I had to uninstall the app entirely, then reinstall it. Previously I had tried replacing the package (react-native run-android), as well as just reloading the JS bundle.

I suspect this has something to do with the way the background service remains running, even after the package is replaced. It's likely after the package was replaced, the service continued running against the older version of Settings and config, the DB entries, etc.

@christocracy can you recommend the correct upgrade process for apps which are configured to always run the background service?

I suspect this has something to do with the way the background service remains running, even after the package is replaced.

This is not true. The service is restarted.

Whenever you npm install any-new-package, you must restart your dev server.

It's hard for me to pinpoint exactly what was going on. I do know that I restarted the packager and react native, as well as the simulator before I found that reinstalling solved the issue. If it happens again, I'll try and dig more.

Ok, it looks like I've been able to reproduce this issue. It's very difficult to debug the issue since the majority of things are happening inside of the tslocationmanager JAR. I found that 2.8.3 does not broadcast the GEOFENCE action, whereas downgrading to 2.8.2 broadcasts the action correctly.

I'm sure nothing changed with this. Are you mocking Location?

Firing geofences with mock locations is problematic.

And the difference between 2.8.3 and 2.8.2 was 2 lines of code in the scheduling system.

There's absolutely no difference at all in the geofencing system in these versions.

You can't test geofences with mock locations.

@christocracy I'm mocking them yes, using the GPX data playback in the Android simulator. The geofences are firing off properly, and I was receiving them fine at one point. I actually retract my statement about 2.8.2 and 2.8.3, it's actually not working in 2.8.2 now either, it stopped working after I rebooted the simulator.

Again, the geofences are being reported fine by the service, it's just the com.transistorsoft.locationmanager.event.GEOFENCE broadcast events are no longer being triggered.

Does the TSLocationManager behavior change for broadcasting the com.transistorsoft.locationmanager.event.GEOFENCE action with startOnBoot compared to starting with the app?

Test on real device with real location. Simply add a geofence around the
current location and observe the GEOFENCE event fire.

Testing with mock locations is flaky unless you place configure your device
location services to "device only" and place your device inside a faraday
cage to prevent locations leaking in from GPS.

Yes, it will work sometimes with mock locations. It's flakey.

For more info on problems testing geofences with mock locations, google "android mock geofence"

But I will have a look and attempt to reproduce this.

Thanks for taking a look. I'm actually having zero issues with mocked locations. I just make sure I set changePace(true) and I don't have any issues, so long as I engage a hit before the stopTimeout is up. My TSLocationManager log is filled with geofence hits:

06-27 16:38:25.819  3144  3239 D TSLocationManager: โ•Ÿโ”€ ๐Ÿ“  Location[fused 37.199398,-121.734998 acc=20 et=+1m38s867ms alt=0.0]
06-27 16:38:25.831  3144  3239 W TSLocationManager: [c.t.l.l.TSLocationManager onSingleLocationResult]
06-27 16:38:25.831  3144  3239 W TSLocationManager:   โš ๏ธ  Failed to find SingleLocationRequest
06-27 16:38:25.851  3144  3239 I TSLocationManager: [c.t.l.LocationService onLocation]
06-27 16:38:25.851  3144  3239 I TSLocationManager:   โ„น๏ธ  Location availability: true
06-27 16:38:31.664  3144  3241 D TSLocationManager: [c.t.l.LocationService onLocation]
06-27 16:38:31.664  3144  3241 D TSLocationManager: โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
06-27 16:38:31.664  3144  3241 D TSLocationManager: โ•‘ LocationService: location
06-27 16:38:31.664  3144  3241 D TSLocationManager: โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
06-27 16:38:31.664  3144  3241 D TSLocationManager: โ•Ÿโ”€ ๐Ÿ“  Location[fused 37.199800,-121.734998 acc=20 et=+1m44s867ms alt=0.0]
06-27 16:38:31.696  3144  3241 D TSLocationManager: [c.t.l.l.TSLocationManager onLocationResult]
06-27 16:38:31.696  3144  3241 D TSLocationManager: โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
06-27 16:38:31.696  3144  3241 D TSLocationManager: โ•‘ Process LocationResult
06-27 16:38:31.696  3144  3241 D TSLocationManager: โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
06-27 16:38:31.734  3144  3241 D TSLocationManager: [c.t.l.l.TSLocationManager calculateMedianAccuracy] 20.0
06-27 16:38:31.763  3144  3241 D TSLocationManager: [c.t.l.l.TSLocationManager incrementOdometer] 1458.379
06-27 16:38:33.705  3144  3242 I TSLocationManager: [c.t.l.geofence.GeofenceService onHandleIntent]
06-27 16:38:33.705  3144  3242 I TSLocationManager: โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
06-27 16:38:33.705  3144  3242 I TSLocationManager: โ•‘ Geofencing Event: ENTER
06-27 16:38:33.705  3144  3242 I TSLocationManager: โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
06-27 16:38:33.705  3144  3242 I TSLocationManager: โ•Ÿโ”€ MockLocation1
06-27 16:38:33.705  3144  3242 I TSLocationManager: โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

But my BroadcastReceiver receives not a single com.transistorsoft.locationmanager.event.GEOFENCE event action.

Is it possible for the manager to recognize a geofence hit, but not perform a sendBroadcast? Would look into this myself, but the source for this is in the compiled adapter.BackgroundGeolocation class, so it's difficult to debug.

mocking locations is fine. It's getting mocked locations to fire a geofence which is the problem; it works sometimes.

It's not hard for me to debug if the issue can be reproduced.

When you say:

fire a geofence

Do you mean _firing Android broadcast_ or the GeofencingEvent? Because the events are showing up in my log no problem, so I have no issues there. The broadcast is what is inconsistent for me.

Ok, I've found the problem.

geofenceCallbacks here contains you callbacks registered with the Javascript API, ie:

BackgroundGeolocation.on('geofence', onGeofence);
public void onGeofencingEvent(GeofencingEvent geofenceEvent) {
    for (Geofence geofence : geofenceEvent.getTriggeringGeofences()) {
        .
        .
        .
        if (!geofenceCallbacks.isEmpty()) {  // <-- HERE:  this will be empty when MainActivity is not alive.
            fireGeofenceCallbacks(params);
        }
    }
}

private void fireGeofenceCallbacks(JSONObject params) {
    Iterator<TSCallback> iterator = geofenceCallbacks.iterator();
    while (iterator.hasNext()) {
        iterator.next().success(params);
    }
    // Broadcast GEOFENCE.
    Intent intent = new Intent();
    intent.setAction(getBroadcastAction(EVENT_GEOFENCE));
    intent.putExtra("geofence", params.toString());
    mContext.sendBroadcast(intent);
}

Try installing from branch geofence-broadcast-issue

I'm not so sure this is the issue. I never registered any geofence listeners in my JS with the react activity running because I was handling them natively using the broadcast action.

Also, I tried adding this to my main activity:

BackgroundGeolocation.getInstance(context, intent).on("geofence", tsCallback)

Which seems to not make a difference.

I am noticing however that the broadcast is sent out properly when I reload the package or perform a fresh reinstall for the first hit. Any subsequent hits are not broadcasted (but they are logged by TSLocationManager as a hit).

Will try that feature branch now, thank you.

Try installing from branch geofence-broadcast-issue

Worked! Thanks for the quick turnaround. Tested after various scenarios -- reboot (with startOnBoot=true), reloading JS bundle, uninstall/reinstall. No issues at all.

What exactly was the fix? Can't really tell since it's all in the compiled classes.

Look at the Java I posted above. How would you have fixed that?

Sure. But as I mentioned, I didn't think that was the issue here, since I never registered any geofence callbacks in the first place due to using the broadcast receiver in native code to handle geofence events. Yet I the event was being broadcast (but only for the first hit).

So somehow, it was getting past that !geofenceCallbacks.isEmpty() check (theoretically) for that first hit.

In any event, this is great. Thanks again for the fix.

There is at least one case in the plugin where all listeners are cleared if a MainActivity is not detected (e.g. When #stop is executed)

In the above code, I simply removed the if (!geofenceCallbacks.isEmpty())

Plans to merge this into master?

Soon

This is now released in 2.8.4

Was this page helpful?
0 / 5 - 0 ratings