transistorsoft / capacitor-background-fetch

Periodic callbacks in the background for both IOS and Android
78 stars 9 forks source link

Crash on Android from BGTask.fireHeadlessEvent #18

Closed JackMcKew closed 1 year ago

JackMcKew commented 1 year ago

Your Environment

Installed Dependencies:

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


* BackgroundFetch Plugin config provided to `configure`:
```javascript
const configureBackgroundFetch = checkCapacitorAndPluginsAvailable(
  ['BackgroundGeolocation', 'BackgroundFetch'],
  async () => {
    await BackgroundFetch.configure(
      {
        minimumFetchInterval: 15, // <-- default is 15
        // Android config
        stopOnTerminate: false,
        startOnBoot: true,
        enableHeadless: true,
        requiresCharging: false,
        requiresDeviceIdle: false,
        requiresBatteryNotLow: false,
        requiresStorageNotLow: false,
        requiredNetworkType: BackgroundFetch.NETWORK_TYPE_NONE,
      },
      (taskId) => {
        telemetry(
          telemetry.DEBUG,
          '[BackgroundFetch] - Received event:',
          taskId,
        );
        switch (taskId) {
          case 'com.transistorsoft.customtask':
            break;
          default:
            // Schedule another one-shot
            BackgroundFetch.scheduleTask({
              taskId: 'com.transistorsoft.customtask',
              delay: 5000,
              stopOnTerminate: false,
              enableHeadless: true,
              periodic: false,
              forceAlarmManager: true,
            });
            break;
        }
        BackgroundFetch.finish(taskId);
      },
      (taskId) => {
        telemetry(telemetry.WARN, '[BackgroundFetch] TIMEOUT: ', taskId);
        BackgroundFetch.finish(taskId);
      },
    );

    BackgroundFetch.scheduleTask({
      taskId: 'com.transistorsoft.customtask',
      delay: 10000,
      periodic: false,
      stopOnTerminate: false,
      enableHeadless: true,
      forceAlarmManager: true,
    });
  },
);

## Expected Behavior
No or very few crash reports in Google Play Console

## Actual Behavior
<!--- Tell us what happens instead -->
98% of users have crashes reported in Google Play Console

com.transistorsoft.tsbackgroundfetch.BGTask.fireHeadlessEvent

Exception java.lang.RuntimeException: com.transistorsoft.tsbackgroundfetch.BGTask$Error: com.deckee.app.BackgroundFetchHeadlessTask at android.app.job.JobServiceEngine$JobHandler.handleMessage (JobServiceEngine.java:145) at android.os.Handler.dispatchMessage (Handler.java:106) at android.os.Looper.loopOnce (Looper.java:240) at android.os.Looper.loop (Looper.java:351) at android.app.ActivityThread.main (ActivityThread.java:8364) at java.lang.reflect.Method.invoke at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:584) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1013) Caused by com.transistorsoft.tsbackgroundfetch.BGTask$Error: com.deckee.app.BackgroundFetchHeadlessTask at com.transistorsoft.tsbackgroundfetch.BGTask.fireHeadlessEvent (BGTask.java:231) at com.transistorsoft.tsbackgroundfetch.BGTask.onTimeout (BGTask.java:196) at com.transistorsoft.tsbackgroundfetch.FetchJobService.onStopJob (FetchJobService.java:50) at android.app.job.JobService$1.onStopJob (JobService.java:76) at android.app.job.JobServiceEngine$JobHandler.handleMessage (JobServiceEngine.java:141)


## BackgroundGeolocationHeadlessTask

package com.deckee.app;

import com.transistorsoft.locationmanager.adapter.BackgroundGeolocation; import com.transistorsoft.locationmanager.adapter.TSConfig; import com.transistorsoft.locationmanager.config.TSNotification; import com.transistorsoft.locationmanager.event.HeadlessEvent; import com.transistorsoft.locationmanager.http.HttpResponse; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode;

/**

/* This plugin will continue to operate with the settings as initalised with in Javascript while the app is terminated As long as a headless event is subscribed, any further custom implementation can be done in response to events while terminated inside the onHeadlessTask function /

// Thread for one liner to get position https://github.com/transistorsoft/capacitor-background-geolocation/issues/31

public class BackgroundGeolocationHeadlessTask {

boolean onTheWater = false;

@Subscribe(threadMode = ThreadMode.MAIN) public void onHeadlessTask(HeadlessEvent event) { // Get a reference to the BackgroundGeolocation Android API. BackgroundGeolocation bgGeo = BackgroundGeolocation.getInstance( event.getContext() );

String name = event.getName();
if (name.equals(BackgroundGeolocation.EVENT_HTTP)) {
  HttpResponse response = event.getHttpEvent();
  String responseText = response.getResponseText();
  boolean onTheWaterStatus = responseText.contains("\"water\":true");
  if (onTheWater != onTheWaterStatus) {
    TSConfig config = TSConfig.getInstance(event.getContext());
    if (onTheWaterStatus) {
      onTheWater = true;
      // User detected to be on the water

      // High frequency tracking config gathered from:
      // http://meta-store.production.svc.cluster.local/private/editor/app-main/feature/configuration-high-frequency-background-geolocation-settings

      config.updateWithBuilder().setStopTimeout(10L).commit();
    } else {
      onTheWater = false;
      // User detected to be off the water

      // Low frequency tracking config gathered from:
      // http://meta-store.production.svc.cluster.local/private/editor/app-main/feature/configuration-low-frequency-background-geolocation-settings

      config.updateWithBuilder().setStopTimeout(0L).commit();
    }
  }
}

} }


## BackgroundFetchHeadlessTask.java

package com.transistorsoft.cordova.backgroundfetch; import android.content.Context; import com.transistorsoft.tsbackgroundfetch.BackgroundFetch; import com.transistorsoft.tsbackgroundfetch.BGTask; import android.util.Log;

public class BackgroundFetchHeadlessTask implements HeadlessTask { @Override public void onFetch(Context context, BGTask task) { String taskId = task.getTaskId(); boolean isTimeout = task.getTimedOut(); if (isTimeout) { Log.d(BackgroundFetch.TAG, "My BackgroundFetchHeadlessTask TIMEOUT: " + taskId); BackgroundFetch.getInstance(context).finish(taskId); return; } Log.d(BackgroundFetch.TAG, "My BackgroundFetchHeadlessTask: onFetch: " + taskId); // Perform your work here....

    // Just as in Javascript callback, you must signal #finish
    BackgroundFetch.getInstance(context).finish(taskId);
}

}



## Context
<!--- What were you trying to do? -->
A change was made in that we alter the configuration of the background plugin determined by the current state (as returned from the server) so we introduced the headless event, which works as expected however is causing crashes
christocracy commented 1 year ago

You are providing BackgroundGeolocation Config in your issue description.

this is the background-fetch plug-in. You need to provide background-fetch Config.

christocracy commented 1 year ago

Plugin version: 4.11.4

This is not even a valid version of background-fetch. That’s a background-geolocation version.

Your error has nothing at all to do with background-geolocation. Your error is coming from background-fetch. I suggest you review the Background Fetch Headless Setup here.

https://github.com/transistorsoft/capacitor-background-fetch/blob/master/CHANGELOG.md

JackMcKew commented 1 year ago

My apologies, I've now updated the original issue with the relevant information for this repo

christocracy commented 1 year ago

I think you've migrated your App from Cordova and failed to properly migrate your BackgroundFetchHeadlessTask.java.

The package still references cordova.

package com.transistorsoft.cordova.backgroundfetch;  // <-------- THIS IS WRONG
import android.content.Context;
import com.transistorsoft.tsbackgroundfetch.BackgroundFetch;
import com.transistorsoft.tsbackgroundfetch.BGTask;
import android.util.Log;

public class BackgroundFetchHeadlessTask implements HeadlessTask {
   .
   .
   .
}

See API docs Config.enabledHeadless

JackMcKew commented 1 year ago

Thank you!

We've disabled background fetch for now but seems this was likely the problem