transistorsoft / cordova-background-geolocation-lt

The most sophisticated background location-tracking & geofencing module with battery-conscious motion-detection intelligence for iOS and Android.
http://www.transistorsoft.com/shop/products/cordova-background-geolocation
Other
655 stars 277 forks source link

MeteorJS: Background location not running after terminating app on iOS #221

Closed mikkelsjolin closed 7 years ago

mikkelsjolin commented 7 years ago

Environment

BackgroundGeolocation.configure({
  desiredAccuracy: 0,
  distanceFilter: 100,
  locationUpdateInterval: 1000,
  fastestLocationUpdateInterval: 1000,
  stationaryRadius: 25,
  activityRecognitionInterval: 10000,
  stopTimeout: 5,
  url: 'http://192.168.0.3:8080/locations',
  autoSync: true,
  debug: true,
  logLevel: BackgroundGeolocation.LOG_LEVEL_VERBOSE,
  stopOnTerminate: false,
  startOnBoot: true
  }
  , function(state) {
    if (!state.enabled) {
      BackgroundGeolocation.start();
    }
});

Expected Behavior

Locations should keep coming through when app is terminated and simulator is in Freeway Drive mode.

Actual Behavior

Locations stop coming through when app is terminated and simulator is still in Freeway Drive mode.

Steps to Reproduce

(Install Meteor on your machine)

  1. Create simple Meteor app and cd into app folder meteor create test-app cd test-app
  2. Add iOS platform to application meteor add-platform ios
  3. Add cordova-background-geolocation-lt to project meteor add cordova:cordova-background-geolocation-lt@2.2.0
  4. Add BackgroundGeolocation.configure to the main.js file in client folder Meteor.startup(function(){ BackgroundGeolocation.configure({...}) });
  5. Build app for iOS meteor run ios-device
  6. In xcode, make sure correct capabilities are enabled (Location updates & Background fetch)
  7. Run application in iPhone simulator (9.3 or 10.1)
  8. Make sure you have the background-geolocation-console app running on port 8080 and that your simulator's location settings are set to Freeway Drive
  9. Validate that locations are coming through to background-geolocation-console when the iOS app is running
  10. Teminate iOS app running in simulator and wait for app to wake up in background
  11. Check if locations start coming through to background-geolocation-console app

Context

First of all, great work on this plugin! If I get this up and running, I will be upgrading and implementing this in my Android version as well 👍

At the moment I an trying to implement background tracking in an app I am developing using MeteorJS. This is causing me some issues which is why I wanted to test if it was because of something in my app, or some with this plugin, or the combination of this plugin and Meteor.

That's why I tried to implement your plugin in the most basic version of a Meteor iOS app.

Sadly, it shows the same issues as with my own app. Therefore I'm thinking the issue could be with your plugin in combination with Meteor JS.

I'm really hoping to make this work with your help :)

Thank you!

Debug logs

iOS 10.1 Simulator System log: http://pastebin.com/raw/L2hd5ntA

background-geolocation-console Terminal log: http://pastebin.com/raw/JFe8mpBD

mikkelsjolin commented 7 years ago

No? 🙊

christocracy commented 7 years ago

Sorry, I missed this.

christocracy commented 7 years ago

I'm sure it's nothing to do with Meteor. Your app will die for a period, until the geofence around the last-known-location fires (or a background-fetch event fires).

See this video where I demonstrate this behaviour of killing an app with stopOnTerminate: false.

mikkelsjolin commented 7 years ago

I have seen your video and I can't get my app to behave the same way. Even with stopOnTerminate set to false.

That's why I figured it would be worth a shot to see if you can reproduce the problem using the same setup as I am running.

mikkelsjolin commented 7 years ago

I testet this both in the simulator with location set to Freeway drive, and by installing the app on my iPhone and biking around Copenhagen.

christocracy commented 7 years ago

It's actually a harder problem to stop the plugin from coming alive (for stopOnTerminate: true).

I recorded this demo just now. No issues.

christocracy commented 7 years ago

I've tested the plugin all over the world. It works. Try booting the Sample App to isolate yourself from Meteor.

mikkelsjolin commented 7 years ago

I'm a 100% sure your plugin works. I'm just having issues getting it to work with my project or any Meteor project I build.

When I tried booting the Sample App, and running it in the simulator, I ran into another issue. The app doesn't ask for permissions to use my location and therefore never starts tracking my location.

geo_permission

geo_settings

xcode_geo_settings

christocracy commented 7 years ago

In SampleApp .plist, verify:

The plugin's config.xml adds that automatically. Don't know what's up with that.

mikkelsjolin commented 7 years ago

image

christocracy commented 7 years ago

Delete the app from Sim and re-install.

On Thu, Dec 1, 2016 at 1:55 PM, Mikkel Sjølin notifications@github.com wrote:

I'm a 100% sure your plugin works. I'm just having issues getting it to work with my project or any Meteor project I build.

When I tried booting the Sample App, and running it in the simulator, I ran into another issue. The app doesn't ask for permissions to use my location and therefore never starts tracking my location.

[image: geo_permission] https://cloud.githubusercontent.com/assets/1090770/20807588/df312ffc-b7ff-11e6-84c6-50bf4bddf412.gif

[image: geo_settings] https://cloud.githubusercontent.com/assets/1090770/20807598/e8691378-b7ff-11e6-91a1-6dead5633b53.gif

[image: xcode_geo_settings] https://cloud.githubusercontent.com/assets/1090770/20807600/ed33addc-b7ff-11e6-831e-74d3e27220cc.png

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/transistorsoft/cordova-background-geolocation-lt/issues/221#issuecomment-264260089, or mute the thread https://github.com/notifications/unsubscribe-auth/AAA6l90-ma42FMa0gZ55fBVwCALEHxtpks5rDxgQgaJpZM4K7ivM .

-- Chris Scott Transistor Software http://www.transistorsoft.com

mikkelsjolin commented 7 years ago

I have removed the app, reinstalled it. Started a clean installed simulator. Installed the app again. Still not getting a permissions prompt.

I've tried running it in both 9.3 and 10.1 simulators. On iPhone 6 and 6 plus.

christocracy commented 7 years ago

Are you enabling the top-right toggle button? The plugin doesn't request permission until you turn it ON.

mikkelsjolin commented 7 years ago

Yes, I have tried toggling the on/off switch multiple times. What I'm noticing is that your icons in the bottom left are different than mine:

image

christocracy commented 7 years ago

Icons are different (and correct) because I hadn't triggered my ON switch, triggering iOS to ask permission. The icons reflect my disabled location permission.

Whatever problem you're having must be related to your dev environment. Are you SURE you set up the Sample App following the steps exactly as directed?

I booted the SampleApp from scratch and it worked perfectly.

On Fri, Dec 2, 2016 at 4:07 AM Mikkel Sjølin notifications@github.com wrote:

Yes, I have tried toggling the on/off switch multiple times. What I'm noticing is that your icons in the bottom left are different than mine:

[image: image] https://cloud.githubusercontent.com/assets/1090770/20828281/16f41e3c-b877-11e6-8ffc-1186e6c65e07.png

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/transistorsoft/cordova-background-geolocation-lt/issues/221#issuecomment-264406953, or mute the thread https://github.com/notifications/unsubscribe-auth/AAA6l-KX9N0MHsYJoGgbkbn4RwdMjwfNks5rD9_igaJpZM4K7ivM .

-- Snet form Gmail Mobile

mikkelsjolin commented 7 years ago

I removed everything, pulled the whole thing from Github, followed every step, and now Sample App works! I must have made a rookie mistake along the way first time I tried to set up the app.

When it comes to the Meteor project, I see your plugin do all the same things as in the Sample App, except booting in the background after being terminated.

mikkelsjolin commented 7 years ago

When looking through the system log for Sample App and my Meteor app. In the Meteor app I see an error being logged over and over, which is not in the Sample App.

image

This happens both in my main project and in the empty, newly created Meteor project. Maybe this is preventing the app from booting in the background?

I know this might not have anything to do with your plugin, but maybe it would be nice for you to know if your plugin can run within a Meteor project :)

mikkelsjolin commented 7 years ago

I should add that the error mentioned above only shows up in the system log with cordova-background-geolocation-lt added to the project.

mikkelsjolin commented 7 years ago

Going through the Meteor iOS build, I see that the Cordova platform version in the current Meteor version is different from the version in the Sample App.

It is running Cordova iOS 4.2.1 and your Sample App project is running 4.3.0 Could this be the issue?

mikkelsjolin commented 7 years ago

Just tried updating the Cordova platform to ios@4.3.0 with the same results.

grundmanise commented 7 years ago

Have the same problem... Meteor + Cordova. iPhone 5s iOS 10 - tested for a few days on a real device in the city and outside of the city.

Meteor@1.4.1.3 cordova-background-geolocation-lt@2.2.0

Expected behaviour When the app is completely killed: 1) Send location to the configured URL when the location of the device changes i.e. when event on('location') is triggered; 2) If the device is still, trigger onHeartBeatReceived function every heartbeatInterval(7200second = 2hours). onHeartBeatReceived internally triggers geolocation.getCurrentPosition(); which get's current location with max accuracy and should then do the step 1) automatically;

My code:

import { ReactiveVar } from 'meteor/reactive-var';
import { Api } from '/imports/http/api';

let plugin;
let latLng = new ReactiveVar(null);

export const geolocation = {
   options: {
        // Geolocation config
        desiredAccuracy: 0,
        distanceFilter: 10,
        stationaryRadius: 25,
        locationUpdateInterval: 1000, 
        fastestLocationUpdateInterval: 10000, 
        // pausesLocationUpdatesAutomatically: false,

        // Activity Recognition config
        activityType: 'Other',
        activityRecognitionInterval: 10000,
        stopTimeout: 5,
        disableMotionActivityUpdates: true, 

        // Application config
        debug: false,
        stopOnTerminate: false, 
        startOnBoot: true, 
        preventSuspend: true, 
        heartbeatInterval: 7200, // every 2h.

        // HTTP / SQLite config
        url: `${Api.domain}/api/save-location?access_token=${localStorage.accessToken}`,
        method: 'POST',
        autoSync: true,
        autoSyncThreshold: 0,
        batchSync: false,
        maxDaysToPersist: 60,
    },

    // Event functions
    onLocationReceived({ coords: { latitude: lat, longitude: lng } }, taskId) {

        try {

            console.info(`[onLocation] lat = ${lat} lng = ${lng}`);

            if (typeof latLng !== 'undefined') {
                latLng.set({ lat, lng });
            }

        } catch (e) {

            console.error(`[geolocation.onLocation] Error catched! - ${e}`);

        }

        plugin.finish(taskId);
    },

    onLocationError(errorCode) {

        console.error(`[geolocation.onLocationError] Error code = ${errorCode}`);

    },

    onHeartBeatReceived(params) {
        geolocation.getCurrentPosition();
    },

    onHeartBeatError(error) {
        console.error(`[geolocation.onHeartBeatError] Error`, error);
    },

    onConfigureSuccess(state) {

        if (!state.enabled) {
            plugin.start();
            console.warn('[geolocation.config] Started geolocation services! ');
        }

    },

    onConfigureError(error) {

        console.error('[geolocation.config] ERROR: ' + error);

    },

    onNewConfigSet() {
        console.warn('[geolocation.newConfig] New config set');
    },

    onNewConfigError() {
        console.error('[geolocation.newConfig] Failed to set new config');
    },

    onHTTPsuccess({status. responseText}) {

        console.log("[Geolocation] HTTP success", status, responseText);

    },

    onHTTPfail({status. responseText}) {

        console.log("[Geolocation] HTTP failure", status, responseText);

    },

    getPlugin() {
        plugin = window.BackgroundGeolocation;
    },

    // Methods
    setConfig(options) {

        // Set config
        plugin.setConfig(options, this.onNewConfigSet, this.onNewConfigError);

    },

    getCurrentPosition() {

        if (plugin) {
            plugin.getCurrentPosition(
                ({ coords: { latitude: lat, longitude: lng } }, taskId) => {

                    try {

                        console.info(`[onLocation] lat = ${lat} lng = ${lng}`);

                        if (typeof latLng !== 'undefined') {
                            latLng.set({ lat, lng });
                        }

                    } catch (e) {

                        console.error(`[geolocation.onLocation] Error catched! - ${e}`);

                    }

                    plugin.finish(taskId);
                },
                (errorCode) => {
                    console.error(`[Geolocation] getCurrentPosition. Error: ${errorCode}`);
                }
            );
        }

    },

    latLng() {
        return latLng.get();
    },

    init() {

        this.getPlugin();

        plugin.stop();

        plugin.on('location', this.onLocationReceived, this.onLocationError);

        plugin.on('heartbeat', this.onHeartBeatReceived, this.onHeartBeatError);

        plugin.on('http', this.onHTTPsuccess, this.onHTTPfail);

        plugin.configure(this.options, this.onConfigureSuccess, this.onConfigureError);

    },
}
christocracy commented 7 years ago

An iOS app will terminate even with stopOnTerminate: false. You must be prepared for that.

stopOnTerminate: false allows your app to be re-launched when the device starts moving or a background-fetch event occurs. You can simulate this behaviour in iOS simulator.

It's a harder problem to keep an iOS app from relaunching with stopOnTerminate: true.

grundmanise commented 7 years ago

The app is not re-launching even when I traveled 100+ km...

christocracy commented 7 years ago

Test in sim. If it's not re-launching, I have no explanation. It must be something with Meteor.

mikkelsjolin commented 7 years ago

@grundmanise I'm so happy I'm not the only one! This has been driving me crazy over the last couple of weeks. I still haven't been able to fix it 😤

mikkelsjolin commented 7 years ago

@christocracy If you look at the iOS logs I posted, it looks like the app IS relaunching.

grundmanise commented 7 years ago

@mikkelsjolin how have you managed to make the app to relaunch? mine is not relaunching...

grundmanise commented 7 years ago

@christocracy could you please tell, what parts of the JS code are re-launching after the device starts moving or a background-fetch event occurs? Your plugin saves some JS snapshot (caches some JS) isn't it? or it is only relaunching the plugin.on('location', this.onLocationReceived, this.onLocationError); part and its callbacks?

christocracy commented 7 years ago

This is not a plugin issue. It's a Meteor with Cordova issue.

The entire Cordova app is relaunched (including all plugins). Just as if opened by user by clicking home screen icon.

I don't know anything about Meteor.

On Thu, Dec 22, 2016 at 1:08 PM grundmanise notifications@github.com wrote:

@christocracy https://github.com/christocracy could you please tell, what parts of the JS code are re-launching after the device starts moving or a background-fetch event occurs? Your plugin saves some JS snapshot (caches some JS) isn't it? or it is only relaunching the plugin.on('location', this.onLocationReceived, this.onLocationError); part and its callbacks?

— You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub https://github.com/transistorsoft/cordova-background-geolocation-lt/issues/221#issuecomment-268856955, or mute the thread https://github.com/notifications/unsubscribe-auth/AAA6l0vuNk2hGWXUh_tNdLrTpoPuN5sqks5rKrytgaJpZM4K7ivM .

-- Snet form Gmail Mobile

grundmanise commented 7 years ago

@christocracy If I hardcode my server URL into the plugin (obj-c part) will it be sufficient to auto POST (sync) locations? I.e with a minor changes to the plugin itself is it possible to "turn on" the 'location POST'ing' feature when the app is killed, even when the plugin is unable to auto relaunch the app?

grundmanise commented 7 years ago

@christocracy no? :speak_no_evil:

mikkelsjolin commented 7 years ago

@grundmanise I just created a post about this in the Meteor Forums: https://forums.meteor.com/t/plugin-issue-cordova-background-geolocation-lt/32768

grundmanise commented 7 years ago

@christocracy I have used the code from this plugin and this SO answer I've implemented this in PURE Objective-C and I can get locations using the same stack: MeteorJS + Cordova. ALSO: I can see that the app IS restarting when significant location change event occurs, only I don't see that your plugin is restarting in the I log.

christocracy commented 7 years ago

It's Cordova's responsibility to boot plugins

grundmanise commented 7 years ago

Cordova is booting all other plugins.

christocracy commented 7 years ago

I have no issue with my SampleApp, nor are other users reporting issues.

It's a harder problem to keep the app from rebooting with stopOnTerminate: false.

christocracy commented 7 years ago

show me logs

mikkelsjolin commented 7 years ago

@grundmanise I think I might have found where the issue is coming from in Meteor: https://github.com/meteor/cordova-plugin-meteor-webapp/issues/24

mikkelsjolin commented 7 years ago

@grundmanise Try this in your app and tell me if it works:

In WebAppLocalServer.swift try adding to the following: let options = [ GCDWebServerOption_Port: NSNumber(value: localServerPort as UInt), GCDWebServerOption_BindToLocalhost: true]

So it looks like this: let options = [ GCDWebServerOption_Port: NSNumber(value: localServerPort as UInt), GCDWebServerOption_BindToLocalhost: true, GCDWebServerOption_AutomaticallySuspendInBackground: false]

Now try running your app in the simulator and see if it boots in the background.

grundmanise commented 7 years ago

@mikkelsjolin wow! Thank you very much, you saved me! Now it works, the app is starting in the bg even when the app was terminated by the user! Locations are POST'ed to the server!

christocracy commented 7 years ago

Can someone explain to me what the issue was?