capacitor-community / background-geolocation

A Capacitor plugin that sends you geolocation updates, even while the app is in the background.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Capacitor 4 after 5 minutes stop working

ghimarcos opened this issue · comments

Describe the bug

I have an application that was previously on Capacitor version 3.6.0, and it worked perfectly. So we need to update Capacitor to version 4.6.1 and now it always stops working after 5 minutes in while the application is in Background.

To Reproduce

create an application with the following libs:

"@capacitor-community/background-geolocation": "1.2.7",
"@capacitor/android": "4.6.1",
"@capacitor/ios": "4.6.1",
"@capacitor/core": "4.6.1",
"@capacitor/app": "4.1.1",

Remembering that the same code with these lib versions here work perfectly sending POST for more than 5 minutes:

"@capacitor-community/background-geolocation": "1.2.7",
"@capacitor/android": "3.5.1",
"@capacitor/ios": "3.6.0",
"@capacitor/core": "3.6.0",
"@capacitor/app": "1.1.1",

Are you using the native HTTP plugin to send your POST requests? See #14 (comment).

Yes, in both versions (@capacitor 3.6.0 and @capacitor 4.6.1 ), I used native requests from CapacitorHttp, example:

if (window.navigator.onLine) {
const doPost = async () => {
const options = {
url: 'https://myApiUrl',
headers: { 'Authorization': Bearer ${localStorage.getItem('token')}, 'Content-Type': 'application/json' },
data: { trackingCoords: this.trackingCoords },
};
const response: HttpResponse = await Http.post(options);
};
doPost();
}

Can you reproduce this using the app in the example/ directory?

I believe so, but only tomorrow, then I'll let you know

In app from the example/ directory when i generated apk by android studio, it worked correctly in the background for 5 minutes, but then it stopped, I didn't even change the code, could it be that something was missing?

I got the same problem. It was working perfectly before I updated to capacitor v4 and it stopped working. Right now it stops after 5 minutes. And yes I am also using HTTP to make requests. Anyone that knows a fix?

Is this affecting iOS, or just Android?

Were you using the same version of this plugin for both Capacitor v3 and Capacitor v4? I just want to be sure that it's not a bug I introduced recently.

Try setting some breakpoints around

. We must determine whether the issue is with the location provider, or communication with the WebView.

Try setting some breakpoints around

. We must determine whether the issue is with the location provider, or communication with the WebView.

I did this in the example, and from what I noticed, it continues to capture the values, but after 5 minutes it stops sending to the application but continues capturing, if we open the app again, leaving to the background, it sends everything that it captured all at once.

https://drive.google.com/file/d/1XOIMpzMi_0tC_Tawal90O0hAZ9iDBTqI/view?usp=share_link
https://drive.google.com/file/d/11Was8pK6cmcHQh8Xl60QWmgsgx_DK3VU/view?usp=share_link
https://drive.google.com/file/d/1dvS0uXE1L15nigOA6bMDkzZTfT1eRUt8/view?usp=share_link

It seems that the operating system is suspending execution of the WebView. Have you ensured battery optimisation is turned off? See https://dontkillmyapp.com/. It seems strange that upgrading to Capacitor 4 would cause this.

I resolved my problem, it was probably a structural problem, i removed all my code and did it based on the example, some imports changed too, here's how the code made in typescript was in case anyone needs it.

` async addWatcher(background: boolean): Promise {
try {
let id: number;

  const theConfig = Object.assign(
    { stale: true },
    background
      ? {
        backgroundTitle: 'Location you',
        backgroundMessage: 'getting your location.',
      }
      : {
        distanceFilter: 0,
      }
  );

  // eslint-disable-next-line prefer-const
  id = await BackgroundGeolocation.addWatcher(theConfig, function callback(
    location: any,
    error: any
  ): void {
    if (error) {
      if (
        error.code === 'NOT_AUTHORIZED' &&
        window.confirm(
       'This app needs your location, ' +
                'but does not have permission.\n\n' +
                'Open settings now?'
        )
      ) {
        BackgroundGeolocation.openSettings();
      }
      return this.logError(error);
    }

    return console.log('getting', location, 'id :', id);
  });

  console.log('your logic...', id);

} catch (error) {
  console.log(error);
}

}`

I'm not sure that will have resolved your problem. Above your comment there is a reference to a bug report for Capacitor 4, which makes it look like we need some kind of workaround like this to prevent the WebView going to sleep in the background. @Samy-F , do you want to see if you can implement this fix?

I believe it's not a problem with the background-geolocation plugin, because I'm managing to send Post now normally for as long as I want, and I'm on the latest version of both the capacitor and the geolocation plugin, but I admit that I don't know what the problem really was, I simply deleted everything I had and redid everything again.

OK, I'm glad you got it working. I will leave this issue open because it seems others are having the same problem.

Hi,
I have the same problem my appp work fine in background for 5 ~ 10 minutes and then stop de sent locations, but when open again app star work fine.

sorry by my english

Can you replace the handleOnPause method in BackgroundGeolocation.java with the following, and see if that solves the problem?

    @Override
    protected void handleOnPause() {
        if (service != null) {
            service.onActivityStopped();
            new Thread(() -> {
                try {
                    Thread.sleep(1000);
                    this.bridge.getWebView().dispatchWindowVisibilityChanged(View.VISIBLE);
                } catch (Exception ignore) {}
            }).start();
        }
        stoppedWithoutPermissions = !hasRequiredPermissions();
        super.handleOnPause();
    }
commented

Thanks for all your work !
Do you if adding Capacitor Permissions (using annotation per example) can help about background ? I have my own plugin about beacons scanning in background and my device and others where the following permissions were requested hadn't issue about background. I had a try with ten's of users with several device (without the part about the permissions) and they got issues about background location.

I suggest to add the following permissions :

  • android.Manifest.permission.ACCESS_BACKGROUND_LOCATION
  • android.Manifest.permission.FOREGROUND_SERVICE
  • android.Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS

EDIT : ok, I add an issue (no service triggered and no notificatio, using Capacitor 4), now when I add ACCESS_BACKGROUND_LOCATION the notification is OK. I will try the background behavior using this notification.

If you want I can create a PR !
thanks again

That is interesting, but I don't see how can be a permissions problem. The locations are being recorded in the background, but they are only reported to the WebView when the app comes to the foreground again.

Also, on Android, we do not technically record locations in the "background" (see #58 (comment)), so the ACCESS_BACKGROUND_LOCATION should not be necessary.

The FOREGROUND_SERVICE permission is already requested in the plugin's AndroidManifest.xml. I wonder if the REQUEST_IGNORE_BATTERY_OPTIMIZATIONS has something to do with it - but from my understanding, that is just a convenient way to disable battery optimizations, which can be done via the settings anytime).

using annotation per example

Which example is this?

ok, I add an issue (no service triggered and no notificatio, using Capacitor 4)

Can you please link to this issue?

Are you using this plugin, a different plugin, or both?

same issue for me in android pixel 5

Try setting some breakpoints around

. We must determine whether the issue is with the location provider, or communication with the WebView.

I did this in the example, and from what I noticed, it continues to capture the values, but after 5 minutes it stops sending to the application but continues capturing, if we open the app again, leaving to the background, it sends everything that it captured all at once.

https://drive.google.com/file/d/1XOIMpzMi_0tC_Tawal90O0hAZ9iDBTqI/view?usp=share_link https://drive.google.com/file/d/11Was8pK6cmcHQh8Xl60QWmgsgx_DK3VU/view?usp=share_link https://drive.google.com/file/d/1dvS0uXE1L15nigOA6bMDkzZTfT1eRUt8/view?usp=share_link

same happens for me @ghimarcos how you fixed it?

Please test that this is fixed in v1.2.12.

The workaround introduced in v1.2.12 causes window.document to emit a bogus "visibilitychange" event, at which point document.visibilityState is "visible". This change caused a serious bug in my app (which would have been next to impossible to diagnose had I not thought of this workaround) so I am going to remove it.

Does anybody know any other way to keep the WebView responsive after 5 minutes in the background? Why does this bug only affect Capacitor 4, but not Capacitor 3?

commented

As written before, can you try with the ACCESS_BACKGROUND_LOCATION ?

I spent hours and hours to try a lot of possibilities about several apps.

By using the access background location my WebView was still receiving updates several hours later.

I have not been able to reproduce the problem on my device, but if I can I will try adding that permission. Thanks.

commented

All the background issues (WebView, app) are a big mess.
It think you're aware about it but it depends of devices and also settings.

You can try to reproduce that issue about wake up by using doze mode.

For testing purpose I add a "POST" request (using Native Http) and locally I created a server with pings.

Does this problem occur even when the app is exempt from battery optimizations? It looks like Android restricts access to the network once the app has entered Doze mode. https://developer.android.com/training/monitoring-device-state/doze-standby#support_for_other_use_cases

commented

Ok I spent the last few hours testing cases. For the moment I have not enought time for the others test case (several devices because manufacturers doesn't have the same behavior, I know Samsung is stricter than several other manufacturers), I also need to try with the other permissions (background geolocation and battery optimization).

Context: Android Emulator (Android API 33), App: ViteJS + Capacitor 4.
I created one probe with 2 http post (by this way I can get "feedback" without waking up the devise in case of "screen off" or "doze mode". 2 http post: one using CapacitorHTTP (using native http request) and Axios because axios uses fetch and can be more easily switch off when entering in doze mode.
By default my app is in "optimized mode" (about battery).
I allowed the authorization, when I get in background mode I had no notifications and no update. When I came in foreground it was ok I received the location updates again.
I had to add the "foreground service" permission in order to be able to trigger the notification. I had a try after and it was ok with the foreground service permission (not in the doc).
In restricted mode when going in background: no update.
In "optimized mode" and doze mode (and background) location updates where OK.

The optimized mode is a good thing but I think it a mess because manufacturers have their own rules (battery left ? bettery unplug, etc...) to deal with that.

As mentionned I have to test with several real devices and other permissions...

Thanks for looking into this.

In "optimized mode" and doze mode (and background) location updates where OK.

The location updates did not stop after 5 minutes?

commented

I cannot confirm for the moment, I have to investigate again because I had this behavior (location updates Ok) but at the beginning I think I had a behavior where updates stopped. I'll try to reproduce again and again before confirm

I test this solution and the issue looks fixed 👍

@machao81 Did you test it with plugin v1.2.11 or v1.2.12, with or without battery optimizations? I am not happy with the fix I introduced in v1.2.12.

v1.2.12. the issue in background. I deployed the solution to two testers and they no longer have a problem. With the previous version the GPS worked for 10/15 minutes then nothing

So I had this issue initially, and have been testing this over the last couple of days. I don't believe this is an issue with the plugin. My fork is located here if anybody would like to verify my findings themselves. This was all tested using v1.2.11, the previous version, which does not include the recent WebView hack.

The fork has 3 directories of interest, as well as a Node.js echo server to externally monitor the app. In the main.js file of each directory, there is a ping function where you can enter your own IP or some other echo service of your choice. Make sure you start the echo server prior to any of these examples if you would like to monitor them externally.

These tests were done soley using the Android OS, as there were no reports of issues with IOS.

Note: The use of the usesCleartextTraffic declaration and android.permission.INTERNET permission in all 3 tests are only required for the ping function I added for these tests.


The example directory:

  • This works
  • This is our baseline, the initial example provided with this plugin. The only real difference here is the addition of the ping function.

When running this mobile app on a Pixel 6 emulator, select the +BG button to start running a background watcher. At this point you can send the app to the background (just return to the home screen), and the app will continue to run the background watcher indefinitely. The only time this does not seem to be the case is if the phone has aggressive battery optimizations, but these can be disabled through the settings on the phone itself.


The experiment1 directory:

  • This does not work, it will break after 5 minutes.

This is the original example modified to match my initial architecture for my background service. I had an idea of how I thought things worked, and in combination with this comment from issue #84, I naively assumed I could just spawn background watchers and they would work. This is not the case, as a background watcher must be running prior to the app being sent to the background. I wanted to include this in case this was a common misconception.


The experiment2 directory:

  • This works too

This provides a simple example of only acting upon the watcher at a given interval. The watcher is always running though. All in all, there is not much different from this than the original example.


Takeaways:

  • Make sure your background watcher is initialized prior to your app being sent to the background.
  • The android.permission.ACCESS_BACKGROUND_LOCATION is NOT required.
  • Verify how aggressive the battery optimizatioins are on the device you are using for development on https://dontkillmyapp.com/. Some devices will require you to disable battery optimizations for your app.

If none of these examples helped you, and you are still having an issue, please provide an example of how you are implementing this plugin.

If this did help, and there are no other issues/concerns/misconceptions, I would recommend reverting back to v1.2.11

Thank you @alexandermccormick for getting to the bottom of this. I have reverted the WebView hack as of v1.2.13. Ensure that background watchers are created whilst the app is in the foreground, or pin the plugin to v1.2.12 if you really want to rely on the hack.

commented

Hi everyone. I have this issue on Nokia Android 11. I have modified the handleOnPause() and it's worked fine. Is there another way to fix it
I am using "@capacitor-community/background-geolocation": "^1.2.13"

@taivo-digiex Ensure you add any background watchers while the app is still in the foreground.

commented

@taivo-digiex Ensure you add any background watchers while the app is still in the foreground.

Yes, I have. I'm using your example code and it working in background for about 5m before stop

Is your app sending each location in an HTTP request? Can you reproduce the problem using the demo app in the example/ directory of this repository?

commented

Is your app sending each location in an HTTP request? Can you reproduce the problem using the demo app in the example/ directory of this repository?

My app just received location's object and not sending to any database. Sorry if I misunderstand your first question

Is the /example is native app? If that so I don't know how to reproduce the problem in native app. My app is using ionic + angular

@taivo-digiex The example/ isn't any more or less "native" than using Ionic + Angular. Ionic is more of a component library, so the example/ only utilizes Capacitor. You will still use the same commands you do when working with an Ionic project, but instead of calling ionic cap [command] you will call capacitor directly with npx cap [command]. The example/ is more plain, as it does not use a web framework but instead simply uses one index.html file and one main.js. You'll find these located in the www directory inside example/.

By lightly modifying the example/ to better match your use case, it will help provide a more clear picture of what might be going on, either with the plugin or your specific architecture.

@taivo-digiex Does the notification remain after 5 minutes, or does it disappear?

commented

@taivo-digiex The example/ isn't any more or less "native" than using Ionic + Angular. Ionic is more of a component library, so the example/ only utilizes Capacitor. You will still use the same commands you do when working with an Ionic project, but instead of calling ionic cap [command] you will call capacitor directly with npx cap [command]. The example/ is more plain, as it does not use a web framework but instead simply uses one index.html file and one main.js. You'll find these located in the www directory inside example/.

By lightly modifying the example/ to better match your use case, it will help provide a more clear picture of what might be going on, either with the plugin or your specific architecture.

Thanks @alexandermccormick. I will try it

commented

@taivo-digiex Does the notification remain after 5 minutes, or does it disappear?

Its still appear with location icon on status bar.

Btw, I have a case when I modified handleOnPause() I had to add the background location permission. If not the app will stop all

When your application receives a location update, what does it do with it? Does it save it to disk? Display it on the screen in some way? How do you know exactly that it is stopping after 5 minutes?

commented

@diachedelic my app is getting location to show on screen only. I have used console.log(new Date)/count i++ to know when it stop on Android studio terminal

OK. Please try to reproduce your problem using the app in example/. When you add watchers, each location update is logged to the screen. The first column of each logged line is the time the location was generated, and second column is the time the location was received by the WebView.

commented

hi @diachedelic , I just run your example with only add console.log(new Date()) in log_locaiton() and modified packages.json for match with windows command
I start run in BG in 9:33 then stop at 9:38
image
image

UPDATE: after few minutes it show this msg
image

Have you disabled all battery saving optimizations on your phone? Please try doing that via the Settings app, and if that doesn't fix the problem follow the instructions at https://dontkillmyapp.com/hmd-global.

commented

yes, I have disabled battery saving optimizations and set example app to unrestricted. I have tested on Samsung A52s Android 13 and it's happened too
If the OS killed the app, why do the notification and the location icon remain? I am just curious this part

I believe the OS is probably suspending the app, rather than killing it entirely. Are you able to confirm?

commented

I don't know how to confirm that correctly, but the OS may just suspend the app as you said. As I mentioned before when I modified the handleOnPause() like your comment and added background location permission and it works perfectly

I have attempted to reproduce the problem on my Samsung A52, running Android 13. Initially, locations stopped after one minute in the background. But after changing battery optimizations to "Unrestricted" the locations keep coming. How can it be that we are running the same app, on the same device, with the same operating system and the behaviour is different?

commented

let's me check with other devices, and I will let you know the result later

@diachedelic I tried to add more details, you can look at my comment : ionic-team/capacitor#6234

Added a comment with a "solution" here: ionic-team/capacitor#6234 (comment)
(don't know why but my comment is hidden by default and marked as abuse.. )

ghimarcost was write, the bug has been introduced since Capacitor 4.0 =>

https://github.com/ionic-team/capacitor/releases/tag/4.0.0

"android: Use addWebMessageListener where available (ionic-team/capacitor#5427) (c2dfe80)"

@nemoneph has found a workaround for this problem: simply set android.useLegacyBridge to true in your Capacitor config (see https://capacitorjs.com/docs/config).

I added android.useLegacyBridge = true but still having the same issue.

@mohamadnagi Have you found any solution?