transistorsoft / react-native-background-fetch

Periodic callbacks in the background for both IOS and Android
MIT License
1.44k stars 191 forks source link

Custom Tasks time interval issue when forceAlarmManager is set to false #430

Closed vtoupet closed 1 year ago

vtoupet commented 1 year ago

Your Environment

The basic BackgroundFetch is configure in a useEffect at startup only:

const initBackgroundFetch = async () => {
      const onEvent = async (taskId) => {
        console.log('[BackgroundFetch] task: ', taskId);
        if (taskId == 'MyCustomTask1')
          await updateWidget1();
        } else if (taskId == 'MyCustomTask2') {
          await updateWidget2();
        }
        BackgroundFetch.finish(taskId);
      };
      const onTimeout = async (taskId) => {
        console.warn('[BackgroundFetch] TIMEOUT task: ', taskId);
        BackgroundFetch.finish(taskId);
      };
      let status = await BackgroundFetch.configure(
        {
          enableHeadless: true,
          minimumFetchInterval: 15,
          startOnBoot: true,
          stopOnTerminate: false,
          requiredNetworkType: BackgroundFetch.NETWORK_TYPE_ANY,
        },
        onEvent,
        onTimeout,
      );

      console.log('[BackgroundFetch] configure status: ', status);
    };

on index.js, the headless task is properly registered.

The problem comes from custom tasks. When a task is scheduled like this:

BackgroundFetch.scheduleTask(
{
  taskId: 'MyCustomTask1',
  enableHeadless: true,
  minimumFetchInterval: 15,
  startOnBoot: true,
  stopOnTerminate: false,
  forceAlarmManager: false,
  requiredNetworkType: BackgroundFetch.NETWORK_TYPE_ANY,
},

I get this from logcat output:

01-19 15:13:46.181 20764 20764 D TSBackgroundFetch: - registerTask: MyCustomTask1
01-19 15:13:46.181 20764 20764 D TSBackgroundFetch: {
01-19 15:13:46.181 20764 20764 D TSBackgroundFetch:   "taskId": "MyCustomTask1",
01-19 15:13:46.181 20764 20764 D TSBackgroundFetch:   "isFetchTask": false,
01-19 15:13:46.181 20764 20764 D TSBackgroundFetch:   "minimumFetchInterval": 15,
01-19 15:13:46.181 20764 20764 D TSBackgroundFetch:   "stopOnTerminate": false,
01-19 15:13:46.181 20764 20764 D TSBackgroundFetch:   "requiredNetworkType": 1,
01-19 15:13:46.181 20764 20764 D TSBackgroundFetch:   "requiresBatteryNotLow": false,
01-19 15:13:46.181 20764 20764 D TSBackgroundFetch:   "requiresCharging": false,
01-19 15:13:46.181 20764 20764 D TSBackgroundFetch:   "requiresDeviceIdle": false,
01-19 15:13:46.181 20764 20764 D TSBackgroundFetch:   "requiresStorageNotLow": false,
01-19 15:13:46.181 20764 20764 D TSBackgroundFetch:   "startOnBoot": true,
01-19 15:13:46.181 20764 20764 D TSBackgroundFetch:   "jobService": "com.transistorsoft.rnbackgroundfetch.HeadlessTask",
01-19 15:13:46.181 20764 20764 D TSBackgroundFetch:   "forceAlarmManager": false,
01-19 15:13:46.181 20764 20764 D TSBackgroundFetch:   "periodic": true,
01-19 15:13:46.181 20764 20764 D TSBackgroundFetch:   "delay": -1
01-19 15:13:46.181 20764 20764 D TSBackgroundFetch: }
**01-19 15:13:46.181 20764 20764 W JobInfo : Requested interval -1ms for job -1796060099 is too small; raising to +15m0s0ms
01-19 15:13:46.181 20764 20764 W JobInfo : Requested flex -1ms for job -1796060099 is too small; raising to +5m0s0ms**

Expected Behavior

I would expect to see 15 minutes as the requested interval in JobInfo

Actual Behavior

Instead of using minimumFetchInterval value to configure the interval, it is using the delay which is incorrect when forceAlarmManager is set to false.

I think the problem comes from the transistor-background-fetch library: this line: long interval = (config.isFetchTask()) ? (TimeUnit.MINUTES.toMillis(config.getMinimumFetchInterval())) : config.getDelay();

christocracy commented 1 year ago

scheduleTask does not have an option minimumFetchInterval. That is for the built-in, recurring fetch task.

scheduleTask uses delay.

vtoupet commented 1 year ago

There is nothing preventing the usage of minimumFetchInterval with scheduleTask. The underlying java method expect a BackgroundFetchConfig object and uses more or less the same mechanism as the configure method.

I think that would be great to be able to create custom tasks that can benefit from the JobService for Android SDK >= LOLLiPOP. It would require minimal changes when computing interval value in BGTask class. Something like the following (in the function schedule of the BGTask class):

long interval = 0;
if (config.isFetchTask() || (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !config.getForceAlarmManager())) {
  interval = TimeUnit.MINUTES.toMillis(config.getMinimumFetchInterval());
} else {
  interval = config.getDelay();
} 

What do you think?

christocracy commented 1 year ago

There is nothing preventing the usage of minimumFetchInterval with scheduleTask

It doesn't make sense to use the word "minimumFetchInterval" with the method scheduleTask. scheduleTask uses delay.

Anyway, it's not necessary since scheduleTask already uses JobScheduler by default. It only uses AlarmManager when configured with forceAlarmManager: true.

christocracy commented 1 year ago

The config option is named forceAlarmManager to communicate to the developer that JobScheduler is the implied default and you must "force" the SDK to use AlarmManager.

vtoupet commented 1 year ago

Ok, I get it, thanks @christocracy.

2 other things (let me know if you want me to create other issues).

christocracy commented 1 year ago

Your last two points are fair. Go ahead and post two separate issues for those.

christocracy commented 1 year ago

btw, if you are using Typescript, the linter should flag using minimumFetchInterval with the method scheduleTask, which accepts TaskConfig

https://github.com/transistorsoft/react-native-background-fetch/blob/8a3ba2288200e07ef3e7d291d0de8ffd366c78cf/index.d.ts#L54-L71

vtoupet commented 1 year ago

I actually don't use scheduleTask in react-native side but rather in the Java side (from a pure Java Android widget configuration screen). So I am using this instead:

BackgroundFetchConfig.Builder config = new BackgroundFetchConfig.Builder();
config.setTaskId(taskId);
config.setIsFetchTask(false);
config.setDelay(TimeUnit.MINUTES.toMillis(interval));
config.setPeriodic(true);
config.setStartOnBoot(true);
config.setStopOnTerminate(false);
config.setJobService(JOB_SERVICE_CLASS);
config.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
BackgroundFetch adapter = getAdapter(context);
adapter.scheduleTask(config.build());

But my application is react-native. It's not conventional. I did not introduce it to you like this as you would have probably told me that t is out of the scope of this library ;-)

vtoupet commented 1 year ago

Your last two points are fair. Go ahead and post two separate issues for those.

Do you want me to create the issues in this repository or the native one (https://github.com/transistorsoft/transistor-background-fetch)

christocracy commented 1 year ago

Native one. The native lib is common to this RN version in addition to the Cordova, Capacitor and Flutter versions.