capacitor: bug: Capacitor listeners failing to be called from Android notifyListeners with foreground service

Bug Report

Capacitor Version

Latest Dependencies:

@capacitor/cli: 4.6.2 @capacitor/core: 4.6.2 @capacitor/android: 4.6.2 @capacitor/ios: 4.6.2

Installed Dependencies:

@capacitor/cli: 4.6.2 @capacitor/core: 4.6.2 @capacitor/android: 4.6.2 @capacitor/ios: 4.6.2

Platform(s)

  • Android

Current Behavior

I’m maintaining a capacitor plugin that emits events for listeners (https://capacitorjs.com/docs/plugins/android#plugin-events). It uses a native Android & iOS package that starts a foreground service (and on Android, adds a notification to status bar). While the app is in the foreground or background, the native plugin code calls notifyListeners, and the javascript listener callback is run as expected.

The issue is that on Android when the app is swiped away, the Android plugin code continues to run as desired due to the foreground service and status bar notification and calls notifyListeners, but the javascript listener callback is never called. In logcat after the AppDestroyed lifecycle event is seen, the Android `“Notifying listeners for event X” is still being output, but the javascript listener callback is never reached (nor is there a “no listeners found for event X”).

Expected Behavior

If the android plugin code is running and successfully calls notifyListeners, the javascript listener callback (via addListener) is expected to run.

Code Reproduction

I will create a sample application and update here, but wanted to see if it is a known issue in the meantime

The key components would be on Android to call startForeground and setup a notification like so https://medium.com/@engineermuse/foreground-services-in-android-e131a863a33d

emit the listener event

JSObject ret = new JSObject();
ret.put("value", "some value");
notifyListeners("myPluginEvent", ret);

and on the javascript side setup a listener callback

import { MyPlugin } from 'my-plugin';

MyPlugin.addListener('myPluginEvent', (info: any) => {
  console.log('myPluginEvent was fired');
});

Notice in the foreground and background the js listener will fire, but on swiping away the app, the Android code will continue to run and notify listeners but javascript listener doesn’t stay alive.


Update: https://github.com/corypisano/capacitor-listeners-issue Screen Shot 2023-01-25 at 2 19 55 AM Screen Shot 2023-01-25 at 2 20 16 AM

Other Technical Details

npm --version output: 8.1.0

node --version output: v16.13.0

pod --version output (iOS issues only):

Additional Context

About this issue

  • Original URL
  • State: open
  • Created a year ago
  • Comments: 27 (3 by maintainers)

Most upvoted comments

I’m the author of @transistorsoft/capacitor-background-geolocation. I have over 9 years experience operating location APIs in the background so I know what to expect when it comes to receiving events from my plugins when the app is running in the background. Nice work @nemoneph. I ended up here while testing my example app for tracking location in the background. My javascript event-listeners to add a marker to a map cease after exactly 5 minutes in the background (confirmed with stop-watch). Once the app returns to the foreground, all those queued event-listeners fire all-at-once.

useLegacyBridge: true makes my problems all go away.

📂 capacitor.config.ts:

const config: CapacitorConfig = {
  .
  .
  .
  android: {
    useLegacyBridge: true
  }
};

Moderator: This comment by @nemoneph is incorrectly marked as “abuse”.

Capacitor needs to find a way to fix this or developers are going to migrate to React Native and Flutter (where my background-geolocation plugins are waiting for them there).

Don’t know why, my previous message with a “solution” is hidden “This comment was marked as abuse.”

NB: use of promises may be significant, as most browsers will enqueue a Job for promise chains (usually via setImmediate or microtasks, sometimes via setTimeout(fn, 0)). This is something noted by the standards: https://tc39.es/ecma262/multipage/control-abstraction-objects.html#sec-promise-objects

Some discussion of this is here: https://stackoverflow.com/a/73745562/156169

Different of mine, but I understand your point of view about the hack with disableWebViewOptimizations. Currently it’s the only option, but may be we can find better option if we cleary understand the problem.

To add precision of what I mean when I say it works with cordova but not working with capacitor => I’m just talking about the event trigger system to communicate from native to js with the WebView (notifyListeners / addListener on capacitor) wich is not throttled on cordova.

If I set a setInterval, or xmlHttpRequest in cordova/capacitor/whatever-webview it will be throtlled when in use in the background; it’s the chrome/webview behavior.

But it’s seem, that cordova handle the communication differently from native => to webview JS context and it doesn’t get throttled.