expo-task-manager 55.0.9 → 55.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/android/build.gradle +3 -2
  3. package/android/src/main/java/expo/modules/taskManager/TaskService.java +121 -2
  4. package/build/TaskManager.d.ts.map +1 -1
  5. package/build/TaskManager.js +8 -1
  6. package/build/TaskManager.js.map +1 -1
  7. package/expo-module.config.json +1 -1
  8. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/{55.0.9/expo.modules.taskmanager-55.0.9-sources.jar → 55.0.10/expo.modules.taskmanager-55.0.10-sources.jar} +0 -0
  9. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.10/expo.modules.taskmanager-55.0.10-sources.jar.md5 +1 -0
  10. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.10/expo.modules.taskmanager-55.0.10-sources.jar.sha1 +1 -0
  11. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.10/expo.modules.taskmanager-55.0.10-sources.jar.sha256 +1 -0
  12. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.10/expo.modules.taskmanager-55.0.10-sources.jar.sha512 +1 -0
  13. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/{55.0.9/expo.modules.taskmanager-55.0.9.aar → 55.0.10/expo.modules.taskmanager-55.0.10.aar} +0 -0
  14. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.10/expo.modules.taskmanager-55.0.10.aar.md5 +1 -0
  15. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.10/expo.modules.taskmanager-55.0.10.aar.sha1 +1 -0
  16. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.10/expo.modules.taskmanager-55.0.10.aar.sha256 +1 -0
  17. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.10/expo.modules.taskmanager-55.0.10.aar.sha512 +1 -0
  18. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/{55.0.9/expo.modules.taskmanager-55.0.9.module → 55.0.10/expo.modules.taskmanager-55.0.10.module} +22 -22
  19. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.10/expo.modules.taskmanager-55.0.10.module.md5 +1 -0
  20. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.10/expo.modules.taskmanager-55.0.10.module.sha1 +1 -0
  21. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.10/expo.modules.taskmanager-55.0.10.module.sha256 +1 -0
  22. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.10/expo.modules.taskmanager-55.0.10.module.sha512 +1 -0
  23. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/{55.0.9/expo.modules.taskmanager-55.0.9.pom → 55.0.10/expo.modules.taskmanager-55.0.10.pom} +1 -1
  24. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.10/expo.modules.taskmanager-55.0.10.pom.md5 +1 -0
  25. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.10/expo.modules.taskmanager-55.0.10.pom.sha1 +1 -0
  26. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.10/expo.modules.taskmanager-55.0.10.pom.sha256 +1 -0
  27. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.10/expo.modules.taskmanager-55.0.10.pom.sha512 +1 -0
  28. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/maven-metadata.xml +4 -4
  29. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/maven-metadata.xml.md5 +1 -1
  30. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/maven-metadata.xml.sha1 +1 -1
  31. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/maven-metadata.xml.sha256 +1 -1
  32. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/maven-metadata.xml.sha512 +1 -1
  33. package/package.json +2 -2
  34. package/src/TaskManager.ts +9 -1
  35. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.9/expo.modules.taskmanager-55.0.9-sources.jar.md5 +0 -1
  36. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.9/expo.modules.taskmanager-55.0.9-sources.jar.sha1 +0 -1
  37. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.9/expo.modules.taskmanager-55.0.9-sources.jar.sha256 +0 -1
  38. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.9/expo.modules.taskmanager-55.0.9-sources.jar.sha512 +0 -1
  39. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.9/expo.modules.taskmanager-55.0.9.aar.md5 +0 -1
  40. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.9/expo.modules.taskmanager-55.0.9.aar.sha1 +0 -1
  41. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.9/expo.modules.taskmanager-55.0.9.aar.sha256 +0 -1
  42. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.9/expo.modules.taskmanager-55.0.9.aar.sha512 +0 -1
  43. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.9/expo.modules.taskmanager-55.0.9.module.md5 +0 -1
  44. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.9/expo.modules.taskmanager-55.0.9.module.sha1 +0 -1
  45. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.9/expo.modules.taskmanager-55.0.9.module.sha256 +0 -1
  46. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.9/expo.modules.taskmanager-55.0.9.module.sha512 +0 -1
  47. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.9/expo.modules.taskmanager-55.0.9.pom.md5 +0 -1
  48. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.9/expo.modules.taskmanager-55.0.9.pom.sha1 +0 -1
  49. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.9/expo.modules.taskmanager-55.0.9.pom.sha256 +0 -1
  50. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/55.0.9/expo.modules.taskmanager-55.0.9.pom.sha512 +0 -1
package/CHANGELOG.md CHANGED
@@ -10,6 +10,12 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 55.0.10 — 2026-03-17
14
+
15
+ ### 🐛 Bug fixes
16
+
17
+ - Fixed JS timers hanging during background task execution on Android by registering with `HeadlessJsTaskContext`. ([#43821](https://github.com/expo/expo/pull/43821) by [@janicduplessis](https://github.com/janicduplessis))
18
+
13
19
  ## 55.0.9 — 2026-02-25
14
20
 
15
21
  _This version does not introduce any user-facing changes._
@@ -4,17 +4,18 @@ plugins {
4
4
  }
5
5
 
6
6
  group = 'host.exp.exponent'
7
- version = '55.0.9'
7
+ version = '55.0.10'
8
8
 
9
9
  android {
10
10
  namespace "expo.modules.taskmanager"
11
11
  defaultConfig {
12
12
  versionCode 23
13
- versionName "55.0.9"
13
+ versionName "55.0.10"
14
14
  }
15
15
  }
16
16
 
17
17
  dependencies {
18
18
  implementation project(':unimodules-app-loader')
19
19
  api "androidx.core:core:1.17.0"
20
+ compileOnly "com.facebook.react:react-android"
20
21
  }
@@ -21,7 +21,16 @@ import java.util.List;
21
21
  import java.util.Map;
22
22
  import java.util.UUID;
23
23
 
24
+ import androidx.annotation.NonNull;
24
25
  import androidx.annotation.Nullable;
26
+ import com.facebook.react.ReactApplication;
27
+ import com.facebook.react.ReactHost;
28
+ import com.facebook.react.ReactInstanceEventListener;
29
+ import com.facebook.react.bridge.ReactContext;
30
+ import com.facebook.react.bridge.UiThreadUtil;
31
+ import com.facebook.react.bridge.WritableNativeMap;
32
+ import com.facebook.react.jstasks.HeadlessJsTaskConfig;
33
+ import com.facebook.react.jstasks.HeadlessJsTaskContext;
25
34
  import expo.modules.apploader.AppLoaderProvider;
26
35
  import expo.modules.apploader.HeadlessAppLoader;
27
36
  import expo.modules.core.interfaces.SingletonModule;
@@ -67,6 +76,10 @@ public class TaskService implements SingletonModule, TaskServiceInterface {
67
76
  // Map of callbacks for task execution events. Schema: { "<eventId>": TaskExecutionCallback }
68
77
  private static final Map<String, TaskExecutionCallback> sTaskCallbacks = new HashMap<>();
69
78
 
79
+ // Tracks headless JS task IDs per appScopeKey, used to keep JS timers alive
80
+ // during background task execution. See maybeStartHeadlessTask().
81
+ private static final Map<String, Integer> sHeadlessTaskIds = new HashMap<>();
82
+
70
83
  public TaskService(Context context) {
71
84
  super();
72
85
  mContextRef = new WeakReference<>(context);
@@ -204,6 +217,7 @@ public class TaskService implements SingletonModule, TaskServiceInterface {
204
217
 
205
218
  if (appEvents.isEmpty()) {
206
219
  sEvents.remove(appScopeKey);
220
+ maybeFinishHeadlessTask(appScopeKey);
207
221
 
208
222
  // Invalidate app record but after 2 seconds delay so we can still take batched events.
209
223
  Handler handler = new Handler();
@@ -378,16 +392,25 @@ public class TaskService implements SingletonModule, TaskServiceInterface {
378
392
  sTaskCallbacks.put(eventId, callback);
379
393
  }
380
394
 
395
+ boolean isFirstEvent = sEvents.get(appScopeKey) == null;
381
396
  final List<String> appEvents;
382
- if (sEvents.get(appScopeKey) == null) {
397
+ if (isFirstEvent) {
383
398
  appEvents = new ArrayList<>();
384
399
  appEvents.add(eventId);
385
400
  sEvents.put(appScopeKey, appEvents);
386
401
  } else {
387
- appEvents = new ArrayList<>();
402
+ appEvents = sEvents.get(appScopeKey);
388
403
  appEvents.add(eventId);
389
404
  }
390
405
 
406
+ // Register with HeadlessJsTaskContext to keep JS timers alive while
407
+ // the app is backgrounded. Without this, JavaTimerManager pauses all
408
+ // timers when the Activity is paused (isPaused=true && isRunningTasks=false),
409
+ // causing all async JS operations (promises, setTimeout) to hang.
410
+ if (isFirstEvent) {
411
+ maybeStartHeadlessTask(appScopeKey);
412
+ }
413
+
391
414
  if (taskManager != null) {
392
415
  taskManager.executeTaskWithBody(body);
393
416
  return;
@@ -598,4 +621,100 @@ public class TaskService implements SingletonModule, TaskServiceInterface {
598
621
  Handler handler = new Handler();
599
622
  handler.postDelayed(() -> jobService.jobFinished(params, false), timeout);
600
623
  }
624
+
625
+ /**
626
+ * Registers a headless JS task with React Native's HeadlessJsTaskContext to signal that
627
+ * background work is in progress. This prevents JavaTimerManager from pausing JS timers
628
+ * when the Activity is backgrounded (isPaused=true), which would cause all async JS
629
+ * operations (promises, setTimeout, etc.) to hang indefinitely.
630
+ *
631
+ * @see <a href="https://github.com/facebook/react-native/blob/63800af9438ea9ddaec84b6f17793a4f1bffe342/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/JavaTimerManager.kt#L291">JavaTimerManager timer guard</a>
632
+ */
633
+ private void maybeStartHeadlessTask(String appScopeKey) {
634
+ try {
635
+ Context context = mContextRef.get();
636
+ if (context == null) return;
637
+
638
+ ReactContext reactContext = getReactContext(context);
639
+ if (reactContext != null) {
640
+ invokeStartHeadlessTask(reactContext, appScopeKey);
641
+ } else {
642
+ // App was killed — context not ready yet. Listen for creation and start then.
643
+ waitForReactContextAndStartTask(context, appScopeKey);
644
+ }
645
+ } catch (Exception e) {
646
+ Log.w(TAG, "Failed to start headless task: " + e.getMessage());
647
+ }
648
+ }
649
+
650
+ private void invokeStartHeadlessTask(ReactContext reactContext, String appScopeKey) {
651
+ HeadlessJsTaskContext headlessContext = HeadlessJsTaskContext.getInstance(reactContext);
652
+ HeadlessJsTaskConfig taskConfig = new HeadlessJsTaskConfig(
653
+ "expo-task-manager",
654
+ new WritableNativeMap(),
655
+ 0, // no timeout, managed by the task consumer
656
+ true // allow in foreground to avoid exceptions if app returns
657
+ );
658
+
659
+ UiThreadUtil.runOnUiThread(() -> {
660
+ try {
661
+ int taskId = headlessContext.startTask(taskConfig);
662
+ sHeadlessTaskIds.put(appScopeKey, taskId);
663
+ Log.i(TAG, "Started headless task " + taskId + " to keep JS timers alive for '" + appScopeKey + "'");
664
+ } catch (Exception e) {
665
+ Log.w(TAG, "Failed to start headless task: " + e.getMessage());
666
+ }
667
+ });
668
+ }
669
+
670
+ private void waitForReactContextAndStartTask(Context context, String appScopeKey) {
671
+ ReactApplication app = (ReactApplication) context.getApplicationContext();
672
+ ReactHost reactHost = app.getReactHost();
673
+ if (reactHost == null) return;
674
+
675
+ reactHost.addReactInstanceEventListener(new ReactInstanceEventListener() {
676
+ @Override
677
+ public void onReactContextInitialized(@NonNull ReactContext reactContext) {
678
+ invokeStartHeadlessTask(reactContext, appScopeKey);
679
+ reactHost.removeReactInstanceEventListener(this);
680
+ }
681
+ });
682
+ }
683
+
684
+ /**
685
+ * Finishes the headless JS task for the given appScopeKey, allowing JavaTimerManager
686
+ * to pause timers again when all background tasks are complete.
687
+ */
688
+ private void maybeFinishHeadlessTask(String appScopeKey) {
689
+ // Run on UI thread to match startTask and ensure sHeadlessTaskIds
690
+ // is only accessed from the UI thread.
691
+ UiThreadUtil.runOnUiThread(() -> {
692
+ Integer taskId = sHeadlessTaskIds.remove(appScopeKey);
693
+ if (taskId == null) return;
694
+
695
+ try {
696
+ Context context = mContextRef.get();
697
+ if (context == null) return;
698
+
699
+ ReactContext reactContext = getReactContext(context);
700
+ if (reactContext == null) return;
701
+
702
+ HeadlessJsTaskContext headlessContext = HeadlessJsTaskContext.getInstance(reactContext);
703
+ headlessContext.finishTask(taskId);
704
+ Log.i(TAG, "Finished headless task " + taskId + " for '" + appScopeKey + "'");
705
+ } catch (Exception e) {
706
+ Log.w(TAG, "Failed to finish headless task: " + e.getMessage());
707
+ }
708
+ });
709
+ }
710
+
711
+ /**
712
+ * Gets the current ReactContext via ReactHost.
713
+ */
714
+ @Nullable
715
+ private ReactContext getReactContext(Context context) {
716
+ ReactApplication app = (ReactApplication) context.getApplicationContext();
717
+ ReactHost reactHost = app.getReactHost();
718
+ return reactHost != null ? reactHost.getCurrentReactContext() : null;
719
+ }
601
720
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TaskManager.d.ts","sourceRoot":"","sources":["../src/TaskManager.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAGD;;GAEG;AACH,MAAM,WAAW,mBAAmB,CAAC,CAAC,GAAG,OAAO;IAC9C;;OAEG;IACH,IAAI,EAAE,CAAC,CAAC;IAER;;OAEG;IACH,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAE/B;;OAEG;IACH,aAAa,EAAE,gCAAgC,CAAC;CACjD;AAGD;;GAEG;AACH,MAAM,WAAW,gCAAgC;IAC/C;;;OAGG;IACH,QAAQ,CAAC,EAAE,QAAQ,GAAG,YAAY,GAAG,UAAU,CAAC;IAChD;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB;AAGD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,OAAO,EAAE,GAAG,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,cAAe,SAAQ,eAAe;CAAG;AAG1D;;GAEG;AACH,MAAM,MAAM,uBAAuB,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;AAc9F;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,CAAC,GAAG,OAAO,EACpC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,uBAAuB,CAAC,CAAC,CAAC,QAWzC;AAGD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEvD;AAGD;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO9E;AAGD;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAO7F;AAGD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAM1E;AAGD;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOzE;AAGD;;;;GAIG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,IAAI,CAAC,CAM7D;AAoCD;;;;;;GAMG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAEzD"}
1
+ {"version":3,"file":"TaskManager.d.ts","sourceRoot":"","sources":["../src/TaskManager.ts"],"names":[],"mappings":"AAaA;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAGD;;GAEG;AACH,MAAM,WAAW,mBAAmB,CAAC,CAAC,GAAG,OAAO;IAC9C;;OAEG;IACH,IAAI,EAAE,CAAC,CAAC;IAER;;OAEG;IACH,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAE/B;;OAEG;IACH,aAAa,EAAE,gCAAgC,CAAC;CACjD;AAGD;;GAEG;AACH,MAAM,WAAW,gCAAgC;IAC/C;;;OAGG;IACH,QAAQ,CAAC,EAAE,QAAQ,GAAG,YAAY,GAAG,UAAU,CAAC;IAChD;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB;AAGD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,OAAO,EAAE,GAAG,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,cAAe,SAAQ,eAAe;CAAG;AAG1D;;GAEG;AACH,MAAM,MAAM,uBAAuB,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;AAc9F;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,CAAC,GAAG,OAAO,EACpC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,uBAAuB,CAAC,CAAC,CAAC,QAWzC;AAGD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEvD;AAGD;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO9E;AAGD;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAO7F;AAGD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAM1E;AAGD;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOzE;AAGD;;;;GAIG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,IAAI,CAAC,CAM7D;AAoCD;;;;;;GAMG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAEzD"}
@@ -1,5 +1,12 @@
1
- import { LegacyEventEmitter, UnavailabilityError } from 'expo-modules-core';
1
+ import { LegacyEventEmitter, Platform, UnavailabilityError } from 'expo-modules-core';
2
+ import { AppRegistry } from 'react-native';
2
3
  import ExpoTaskManager from './ExpoTaskManager';
4
+ // Register a no-op headless task so that HeadlessJsTaskContext.startTask()
5
+ // doesn't log a warning. On Android, TaskService registers a headless task
6
+ // in native code to keep JS timers alive during background task execution.
7
+ if (Platform.OS === 'android') {
8
+ AppRegistry.registerHeadlessTask('expo-task-manager', () => async () => { });
9
+ }
3
10
  const tasks = new Map();
4
11
  function _validate(taskName) {
5
12
  if (!taskName || typeof taskName !== 'string') {
@@ -1 +1 @@
1
- {"version":3,"file":"TaskManager.js","sourceRoot":"","sources":["../src/TaskManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { LegacyEventEmitter, UnavailabilityError } from 'expo-modules-core';\n\nimport ExpoTaskManager from './ExpoTaskManager';\n\n// @needsAudit @docsMissing\n/**\n * Error object that can be received through [`TaskManagerTaskBody`](#taskmanagertaskbody) when the\n * task fails.\n */\nexport interface TaskManagerError {\n code: string | number;\n message: string;\n}\n\n// @needsAudit\n/**\n * Represents the object that is passed to the task executor.\n */\nexport interface TaskManagerTaskBody<T = unknown> {\n /**\n * An object of data passed to the task executor. Its properties depend on the type of the task.\n */\n data: T;\n\n /**\n * Error object if the task failed or `null` otherwise.\n */\n error: TaskManagerError | null;\n\n /**\n * Additional details containing unique ID of task event and name of the task.\n */\n executionInfo: TaskManagerTaskBodyExecutionInfo;\n}\n\n// @needsAudit\n/**\n * Additional details about execution provided in `TaskManagerTaskBody`.\n */\nexport interface TaskManagerTaskBodyExecutionInfo {\n /**\n * State of the application.\n * @platform ios\n */\n appState?: 'active' | 'background' | 'inactive';\n /**\n * Unique ID of task event.\n */\n eventId: string;\n /**\n * Name of the task.\n */\n taskName: string;\n}\n\n// @needsAudit\n/**\n * Represents an already registered task.\n */\nexport interface TaskManagerTask {\n /**\n * Name that the task is registered with.\n */\n taskName: string;\n\n /**\n * Type of the task which depends on how the task was registered.\n */\n taskType: string;\n\n /**\n * Provides `options` that the task was registered with.\n */\n options: any;\n}\n\n/**\n * @deprecated Use `TaskManagerTask` instead.\n * @hidden\n */\nexport interface RegisteredTask extends TaskManagerTask {}\n\n// @needsAudit\n/**\n * Type of task executor – a function that handles the task.\n */\nexport type TaskManagerTaskExecutor<T = any> = (body: TaskManagerTaskBody<T>) => Promise<any>;\n\nconst tasks: Map<string, TaskManagerTaskExecutor<any>> = new Map<\n string,\n TaskManagerTaskExecutor<any>\n>();\n\nfunction _validate(taskName: unknown) {\n if (!taskName || typeof taskName !== 'string') {\n throw new TypeError('`taskName` must be a non-empty string.');\n }\n}\n\n// @needsAudit\n/**\n * Defines task function. It must be called in the global scope of your JavaScript bundle.\n * In particular, it cannot be called in any of React lifecycle methods like `componentDidMount`.\n * This limitation is due to the fact that when the application is launched in the background,\n * we need to spin up your JavaScript app, run your task and then shut down — no views are mounted\n * in this scenario.\n *\n * @param taskName Name of the task. It must be the same as the name you provided when registering the task.\n * @param taskExecutor A function that will be invoked when the task with given `taskName` is executed.\n */\nexport function defineTask<T = unknown>(\n taskName: string,\n taskExecutor: TaskManagerTaskExecutor<T>\n) {\n if (!taskName || typeof taskName !== 'string') {\n console.warn(`TaskManager.defineTask: 'taskName' argument must be a non-empty string.`);\n return;\n }\n if (!taskExecutor || typeof taskExecutor !== 'function') {\n console.warn(`TaskManager.defineTask: 'task' argument must be a function.`);\n return;\n }\n tasks.set(taskName, taskExecutor);\n}\n\n// @needsAudit\n/**\n * Checks whether the task is already defined.\n *\n * @param taskName Name of the task.\n */\nexport function isTaskDefined(taskName: string): boolean {\n return tasks.has(taskName);\n}\n\n// @needsAudit\n/**\n * Determine whether the task is registered. Registered tasks are stored in a persistent storage and\n * preserved between sessions.\n *\n * @param taskName Name of the task.\n * @returns A promise which resolves to `true` if a task with the given name is registered, otherwise `false`.\n */\nexport async function isTaskRegisteredAsync(taskName: string): Promise<boolean> {\n if (!ExpoTaskManager.isTaskRegisteredAsync) {\n throw new UnavailabilityError('TaskManager', 'isTaskRegisteredAsync');\n }\n\n _validate(taskName);\n return ExpoTaskManager.isTaskRegisteredAsync(taskName);\n}\n\n// @needsAudit\n/**\n * Retrieves `options` associated with the task, that were passed to the function registering the task\n * (e.g. `Location.startLocationUpdatesAsync`).\n *\n * @param taskName Name of the task.\n * @return A promise which fulfills with the `options` object that was passed while registering task\n * with given name or `null` if task couldn't be found.\n */\nexport async function getTaskOptionsAsync<TaskOptions>(taskName: string): Promise<TaskOptions> {\n if (!ExpoTaskManager.getTaskOptionsAsync) {\n throw new UnavailabilityError('TaskManager', 'getTaskOptionsAsync');\n }\n\n _validate(taskName);\n return ExpoTaskManager.getTaskOptionsAsync(taskName);\n}\n\n// @needsAudit\n/**\n * Provides information about tasks registered in the app.\n *\n * @returns A promise which fulfills with an array of tasks registered in the app.\n * @example\n * ```js\n * [\n * {\n * taskName: 'location-updates-task-name',\n * taskType: 'location',\n * options: {\n * accuracy: Location.Accuracy.High,\n * showsBackgroundLocationIndicator: false,\n * },\n * },\n * {\n * taskName: 'geofencing-task-name',\n * taskType: 'geofencing',\n * options: {\n * regions: [...],\n * },\n * },\n * ]\n * ```\n */\nexport async function getRegisteredTasksAsync(): Promise<TaskManagerTask[]> {\n if (!ExpoTaskManager.getRegisteredTasksAsync) {\n throw new UnavailabilityError('TaskManager', 'getRegisteredTasksAsync');\n }\n\n return ExpoTaskManager.getRegisteredTasksAsync();\n}\n\n// @needsAudit\n/**\n * Unregisters task from the app, so the app will not be receiving updates for that task anymore.\n * _It is recommended to use methods specialized by modules that registered the task, eg.\n * [`Location.stopLocationUpdatesAsync`](./location/#expolocationstoplocationupdatesasynctaskname)._\n *\n * @param taskName Name of the task to unregister.\n * @return A promise which fulfills as soon as the task is unregistered.\n */\nexport async function unregisterTaskAsync(taskName: string): Promise<void> {\n if (!ExpoTaskManager.unregisterTaskAsync) {\n throw new UnavailabilityError('TaskManager', 'unregisterTaskAsync');\n }\n\n _validate(taskName);\n await ExpoTaskManager.unregisterTaskAsync(taskName);\n}\n\n// @needsAudit\n/**\n * Unregisters all tasks registered for the running app. You may want to call this when the user is\n * signing out and you no longer need to track his location or run any other background tasks.\n * @return A promise which fulfills as soon as all tasks are completely unregistered.\n */\nexport async function unregisterAllTasksAsync(): Promise<void> {\n if (!ExpoTaskManager.unregisterAllTasksAsync) {\n throw new UnavailabilityError('TaskManager', 'unregisterAllTasksAsync');\n }\n\n await ExpoTaskManager.unregisterAllTasksAsync();\n}\n\nif (ExpoTaskManager) {\n const eventEmitter = new LegacyEventEmitter(ExpoTaskManager);\n eventEmitter.addListener<TaskManagerTaskBody>(\n ExpoTaskManager.EVENT_NAME,\n async ({ data, error, executionInfo }) => {\n const { eventId, taskName } = executionInfo;\n const taskExecutor = tasks.get(taskName);\n let result: any = null;\n\n if (taskExecutor) {\n try {\n // Execute JS task\n result = await taskExecutor({ data, error, executionInfo });\n } catch (error) {\n console.error(`TaskManager: Task \"${taskName}\" failed:`, error);\n } finally {\n // Notify manager the task is finished.\n await ExpoTaskManager.notifyTaskFinishedAsync(taskName, { eventId, result });\n }\n } else {\n console.warn(\n `TaskManager: Execution of \"${taskName}\" was requested but looks like it is not defined. Available tasks: [${[...tasks.keys()].join(', ')}]. Make sure that \"TaskManager.defineTask\" is called during initialization phase.`\n );\n // No tasks defined -> we need to notify about finish anyway.\n await ExpoTaskManager.notifyTaskFinishedAsync(taskName, { eventId, result });\n // We should also unregister such tasks automatically as the task might have been removed\n // from the app or just renamed - in that case it needs to be registered again (with the new name).\n await ExpoTaskManager.unregisterTaskAsync(taskName);\n }\n }\n );\n}\n\n// @needsAudit\n/**\n * Determine if the `TaskManager` API can be used in this app.\n * @return A promise which fulfills with `true` if the API can be used, and `false` otherwise.\n * With Expo Go, `TaskManager` is not available on Android, and does not support background execution on iOS.\n * Use a development build to avoid limitations: https://expo.fyi/dev-client.\n * On the web, it always returns `false`.\n */\nexport async function isAvailableAsync(): Promise<boolean> {\n return ExpoTaskManager.isAvailableAsync();\n}\n"]}
1
+ {"version":3,"file":"TaskManager.js","sourceRoot":"","sources":["../src/TaskManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { LegacyEventEmitter, Platform, UnavailabilityError } from 'expo-modules-core';\nimport { AppRegistry } from 'react-native';\n\nimport ExpoTaskManager from './ExpoTaskManager';\n\n// Register a no-op headless task so that HeadlessJsTaskContext.startTask()\n// doesn't log a warning. On Android, TaskService registers a headless task\n// in native code to keep JS timers alive during background task execution.\nif (Platform.OS === 'android') {\n AppRegistry.registerHeadlessTask('expo-task-manager', () => async () => {});\n}\n\n// @needsAudit @docsMissing\n/**\n * Error object that can be received through [`TaskManagerTaskBody`](#taskmanagertaskbody) when the\n * task fails.\n */\nexport interface TaskManagerError {\n code: string | number;\n message: string;\n}\n\n// @needsAudit\n/**\n * Represents the object that is passed to the task executor.\n */\nexport interface TaskManagerTaskBody<T = unknown> {\n /**\n * An object of data passed to the task executor. Its properties depend on the type of the task.\n */\n data: T;\n\n /**\n * Error object if the task failed or `null` otherwise.\n */\n error: TaskManagerError | null;\n\n /**\n * Additional details containing unique ID of task event and name of the task.\n */\n executionInfo: TaskManagerTaskBodyExecutionInfo;\n}\n\n// @needsAudit\n/**\n * Additional details about execution provided in `TaskManagerTaskBody`.\n */\nexport interface TaskManagerTaskBodyExecutionInfo {\n /**\n * State of the application.\n * @platform ios\n */\n appState?: 'active' | 'background' | 'inactive';\n /**\n * Unique ID of task event.\n */\n eventId: string;\n /**\n * Name of the task.\n */\n taskName: string;\n}\n\n// @needsAudit\n/**\n * Represents an already registered task.\n */\nexport interface TaskManagerTask {\n /**\n * Name that the task is registered with.\n */\n taskName: string;\n\n /**\n * Type of the task which depends on how the task was registered.\n */\n taskType: string;\n\n /**\n * Provides `options` that the task was registered with.\n */\n options: any;\n}\n\n/**\n * @deprecated Use `TaskManagerTask` instead.\n * @hidden\n */\nexport interface RegisteredTask extends TaskManagerTask {}\n\n// @needsAudit\n/**\n * Type of task executor – a function that handles the task.\n */\nexport type TaskManagerTaskExecutor<T = any> = (body: TaskManagerTaskBody<T>) => Promise<any>;\n\nconst tasks: Map<string, TaskManagerTaskExecutor<any>> = new Map<\n string,\n TaskManagerTaskExecutor<any>\n>();\n\nfunction _validate(taskName: unknown) {\n if (!taskName || typeof taskName !== 'string') {\n throw new TypeError('`taskName` must be a non-empty string.');\n }\n}\n\n// @needsAudit\n/**\n * Defines task function. It must be called in the global scope of your JavaScript bundle.\n * In particular, it cannot be called in any of React lifecycle methods like `componentDidMount`.\n * This limitation is due to the fact that when the application is launched in the background,\n * we need to spin up your JavaScript app, run your task and then shut down — no views are mounted\n * in this scenario.\n *\n * @param taskName Name of the task. It must be the same as the name you provided when registering the task.\n * @param taskExecutor A function that will be invoked when the task with given `taskName` is executed.\n */\nexport function defineTask<T = unknown>(\n taskName: string,\n taskExecutor: TaskManagerTaskExecutor<T>\n) {\n if (!taskName || typeof taskName !== 'string') {\n console.warn(`TaskManager.defineTask: 'taskName' argument must be a non-empty string.`);\n return;\n }\n if (!taskExecutor || typeof taskExecutor !== 'function') {\n console.warn(`TaskManager.defineTask: 'task' argument must be a function.`);\n return;\n }\n tasks.set(taskName, taskExecutor);\n}\n\n// @needsAudit\n/**\n * Checks whether the task is already defined.\n *\n * @param taskName Name of the task.\n */\nexport function isTaskDefined(taskName: string): boolean {\n return tasks.has(taskName);\n}\n\n// @needsAudit\n/**\n * Determine whether the task is registered. Registered tasks are stored in a persistent storage and\n * preserved between sessions.\n *\n * @param taskName Name of the task.\n * @returns A promise which resolves to `true` if a task with the given name is registered, otherwise `false`.\n */\nexport async function isTaskRegisteredAsync(taskName: string): Promise<boolean> {\n if (!ExpoTaskManager.isTaskRegisteredAsync) {\n throw new UnavailabilityError('TaskManager', 'isTaskRegisteredAsync');\n }\n\n _validate(taskName);\n return ExpoTaskManager.isTaskRegisteredAsync(taskName);\n}\n\n// @needsAudit\n/**\n * Retrieves `options` associated with the task, that were passed to the function registering the task\n * (e.g. `Location.startLocationUpdatesAsync`).\n *\n * @param taskName Name of the task.\n * @return A promise which fulfills with the `options` object that was passed while registering task\n * with given name or `null` if task couldn't be found.\n */\nexport async function getTaskOptionsAsync<TaskOptions>(taskName: string): Promise<TaskOptions> {\n if (!ExpoTaskManager.getTaskOptionsAsync) {\n throw new UnavailabilityError('TaskManager', 'getTaskOptionsAsync');\n }\n\n _validate(taskName);\n return ExpoTaskManager.getTaskOptionsAsync(taskName);\n}\n\n// @needsAudit\n/**\n * Provides information about tasks registered in the app.\n *\n * @returns A promise which fulfills with an array of tasks registered in the app.\n * @example\n * ```js\n * [\n * {\n * taskName: 'location-updates-task-name',\n * taskType: 'location',\n * options: {\n * accuracy: Location.Accuracy.High,\n * showsBackgroundLocationIndicator: false,\n * },\n * },\n * {\n * taskName: 'geofencing-task-name',\n * taskType: 'geofencing',\n * options: {\n * regions: [...],\n * },\n * },\n * ]\n * ```\n */\nexport async function getRegisteredTasksAsync(): Promise<TaskManagerTask[]> {\n if (!ExpoTaskManager.getRegisteredTasksAsync) {\n throw new UnavailabilityError('TaskManager', 'getRegisteredTasksAsync');\n }\n\n return ExpoTaskManager.getRegisteredTasksAsync();\n}\n\n// @needsAudit\n/**\n * Unregisters task from the app, so the app will not be receiving updates for that task anymore.\n * _It is recommended to use methods specialized by modules that registered the task, eg.\n * [`Location.stopLocationUpdatesAsync`](./location/#expolocationstoplocationupdatesasynctaskname)._\n *\n * @param taskName Name of the task to unregister.\n * @return A promise which fulfills as soon as the task is unregistered.\n */\nexport async function unregisterTaskAsync(taskName: string): Promise<void> {\n if (!ExpoTaskManager.unregisterTaskAsync) {\n throw new UnavailabilityError('TaskManager', 'unregisterTaskAsync');\n }\n\n _validate(taskName);\n await ExpoTaskManager.unregisterTaskAsync(taskName);\n}\n\n// @needsAudit\n/**\n * Unregisters all tasks registered for the running app. You may want to call this when the user is\n * signing out and you no longer need to track his location or run any other background tasks.\n * @return A promise which fulfills as soon as all tasks are completely unregistered.\n */\nexport async function unregisterAllTasksAsync(): Promise<void> {\n if (!ExpoTaskManager.unregisterAllTasksAsync) {\n throw new UnavailabilityError('TaskManager', 'unregisterAllTasksAsync');\n }\n\n await ExpoTaskManager.unregisterAllTasksAsync();\n}\n\nif (ExpoTaskManager) {\n const eventEmitter = new LegacyEventEmitter(ExpoTaskManager);\n eventEmitter.addListener<TaskManagerTaskBody>(\n ExpoTaskManager.EVENT_NAME,\n async ({ data, error, executionInfo }) => {\n const { eventId, taskName } = executionInfo;\n const taskExecutor = tasks.get(taskName);\n let result: any = null;\n\n if (taskExecutor) {\n try {\n // Execute JS task\n result = await taskExecutor({ data, error, executionInfo });\n } catch (error) {\n console.error(`TaskManager: Task \"${taskName}\" failed:`, error);\n } finally {\n // Notify manager the task is finished.\n await ExpoTaskManager.notifyTaskFinishedAsync(taskName, { eventId, result });\n }\n } else {\n console.warn(\n `TaskManager: Execution of \"${taskName}\" was requested but looks like it is not defined. Available tasks: [${[...tasks.keys()].join(', ')}]. Make sure that \"TaskManager.defineTask\" is called during initialization phase.`\n );\n // No tasks defined -> we need to notify about finish anyway.\n await ExpoTaskManager.notifyTaskFinishedAsync(taskName, { eventId, result });\n // We should also unregister such tasks automatically as the task might have been removed\n // from the app or just renamed - in that case it needs to be registered again (with the new name).\n await ExpoTaskManager.unregisterTaskAsync(taskName);\n }\n }\n );\n}\n\n// @needsAudit\n/**\n * Determine if the `TaskManager` API can be used in this app.\n * @return A promise which fulfills with `true` if the API can be used, and `false` otherwise.\n * With Expo Go, `TaskManager` is not available on Android, and does not support background execution on iOS.\n * Use a development build to avoid limitations: https://expo.fyi/dev-client.\n * On the web, it always returns `false`.\n */\nexport async function isAvailableAsync(): Promise<boolean> {\n return ExpoTaskManager.isAvailableAsync();\n}\n"]}
@@ -9,7 +9,7 @@
9
9
  "publication": {
10
10
  "groupId": "host.exp.exponent",
11
11
  "artifactId": "expo.modules.taskmanager",
12
- "version": "55.0.9",
12
+ "version": "55.0.10",
13
13
  "repository": "local-maven-repo"
14
14
  }
15
15
  }
@@ -0,0 +1 @@
1
+ ff54d12878b8c372e3a44b7de50a4ffda59a6b95e0a6b5892ab4ebd117279b8d
@@ -0,0 +1 @@
1
+ 981f984ba5e43c5bf3b0762f68772154da6ac53255876854ee11172dc6a6e61ff088168985432f8afd7b52cbb51f3829311ce437c93750438c8b05169dbcdbba
@@ -0,0 +1 @@
1
+ be28fd8efcf562566557851a25ca74f812633678b67428ce4228a7b5b8a4f0ea
@@ -0,0 +1 @@
1
+ 4f33007a612a32cb636d0b6b857b5697e8a9b9773414b0751631cefb1cd04e6b5238c904e346dbcf7fe51080fcfbe4d0953fa9bbda05c93f94d5dbf589ca798f
@@ -3,7 +3,7 @@
3
3
  "component": {
4
4
  "group": "host.exp.exponent",
5
5
  "module": "expo.modules.taskmanager",
6
- "version": "55.0.9",
6
+ "version": "55.0.10",
7
7
  "attributes": {
8
8
  "org.gradle.status": "release"
9
9
  }
@@ -33,13 +33,13 @@
33
33
  ],
34
34
  "files": [
35
35
  {
36
- "name": "expo.modules.taskmanager-55.0.9.aar",
37
- "url": "expo.modules.taskmanager-55.0.9.aar",
38
- "size": 63242,
39
- "sha512": "cd82576f43c8b2300966dff0c640590cc4c00933cd6ede6d682a2d46b13a47a12798d8e547e3693be3211651f5c3879b14754be054e683a54e59a1e44bc930a9",
40
- "sha256": "a1243705ad1e8528fb334a20d31756ff78f1a7ab0ee15406890004f92f653993",
41
- "sha1": "86d96fac2316eea17764907e879ba885d2adeb18",
42
- "md5": "fc74e9e574a5be051bdbafe46d563e08"
36
+ "name": "expo.modules.taskmanager-55.0.10.aar",
37
+ "url": "expo.modules.taskmanager-55.0.10.aar",
38
+ "size": 65649,
39
+ "sha512": "4f33007a612a32cb636d0b6b857b5697e8a9b9773414b0751631cefb1cd04e6b5238c904e346dbcf7fe51080fcfbe4d0953fa9bbda05c93f94d5dbf589ca798f",
40
+ "sha256": "be28fd8efcf562566557851a25ca74f812633678b67428ce4228a7b5b8a4f0ea",
41
+ "sha1": "2c202a226c8de0f2f8c2ba9c1e66b16c3637ca74",
42
+ "md5": "758a53c78e427f104485da9c2acc336c"
43
43
  }
44
44
  ]
45
45
  },
@@ -76,13 +76,13 @@
76
76
  ],
77
77
  "files": [
78
78
  {
79
- "name": "expo.modules.taskmanager-55.0.9.aar",
80
- "url": "expo.modules.taskmanager-55.0.9.aar",
81
- "size": 63242,
82
- "sha512": "cd82576f43c8b2300966dff0c640590cc4c00933cd6ede6d682a2d46b13a47a12798d8e547e3693be3211651f5c3879b14754be054e683a54e59a1e44bc930a9",
83
- "sha256": "a1243705ad1e8528fb334a20d31756ff78f1a7ab0ee15406890004f92f653993",
84
- "sha1": "86d96fac2316eea17764907e879ba885d2adeb18",
85
- "md5": "fc74e9e574a5be051bdbafe46d563e08"
79
+ "name": "expo.modules.taskmanager-55.0.10.aar",
80
+ "url": "expo.modules.taskmanager-55.0.10.aar",
81
+ "size": 65649,
82
+ "sha512": "4f33007a612a32cb636d0b6b857b5697e8a9b9773414b0751631cefb1cd04e6b5238c904e346dbcf7fe51080fcfbe4d0953fa9bbda05c93f94d5dbf589ca798f",
83
+ "sha256": "be28fd8efcf562566557851a25ca74f812633678b67428ce4228a7b5b8a4f0ea",
84
+ "sha1": "2c202a226c8de0f2f8c2ba9c1e66b16c3637ca74",
85
+ "md5": "758a53c78e427f104485da9c2acc336c"
86
86
  }
87
87
  ]
88
88
  },
@@ -96,13 +96,13 @@
96
96
  },
97
97
  "files": [
98
98
  {
99
- "name": "expo.modules.taskmanager-55.0.9-sources.jar",
100
- "url": "expo.modules.taskmanager-55.0.9-sources.jar",
101
- "size": 22873,
102
- "sha512": "755c124c19182bd5f33e1ef1f9061190b731e8e3137f094edfaee8ed0a880fccab5f1011e1a5c48205c86df424e9776bb9e59020e062dea6c8db1a8bca4af50d",
103
- "sha256": "1a13d4a1c5042d7b5296e9db9937989f7f1fe3d3620bdfffffd2e243292fbcf5",
104
- "sha1": "200a9dbd20ac61a820c7e2f25a0b3d88add38684",
105
- "md5": "a495364d98cfab4cfdd72dcc40ded29f"
99
+ "name": "expo.modules.taskmanager-55.0.10-sources.jar",
100
+ "url": "expo.modules.taskmanager-55.0.10-sources.jar",
101
+ "size": 24108,
102
+ "sha512": "981f984ba5e43c5bf3b0762f68772154da6ac53255876854ee11172dc6a6e61ff088168985432f8afd7b52cbb51f3829311ce437c93750438c8b05169dbcdbba",
103
+ "sha256": "ff54d12878b8c372e3a44b7de50a4ffda59a6b95e0a6b5892ab4ebd117279b8d",
104
+ "sha1": "c94c865c679390da383bfdaa0a2e99d3d2d58e19",
105
+ "md5": "342e4cf635e65d5098667d442ef9669c"
106
106
  }
107
107
  ]
108
108
  }
@@ -0,0 +1 @@
1
+ 1edca8c346947444ab689a475dd96388e746a8d4b469776ea2903df818d4e628
@@ -0,0 +1 @@
1
+ 376a617210aff84ea40ef5db9faf8a59bf4a6db80d5ff1d4fc733b1cfc9b5065746a03f7082bc3a370a3500834a5ed26ae4d3c98438b2875b5b6b1ce18ff7a4c
@@ -9,7 +9,7 @@
9
9
  <modelVersion>4.0.0</modelVersion>
10
10
  <groupId>host.exp.exponent</groupId>
11
11
  <artifactId>expo.modules.taskmanager</artifactId>
12
- <version>55.0.9</version>
12
+ <version>55.0.10</version>
13
13
  <packaging>aar</packaging>
14
14
  <name>expo.modules.taskmanager</name>
15
15
  <url>https://github.com/expo/expo</url>
@@ -0,0 +1 @@
1
+ 00acc1a69d167e7e01dc9cb5f82c4b0e49553cc19e57777b6271512f49b17a6d
@@ -0,0 +1 @@
1
+ f61c2355eb59a41ac20c8904e90f585519efeca03879eda82649d30c135859e5a1bafbfaca7237d789d8b08dd37d107c6c2228db04103c57d734eb303cb62979
@@ -3,11 +3,11 @@
3
3
  <groupId>host.exp.exponent</groupId>
4
4
  <artifactId>expo.modules.taskmanager</artifactId>
5
5
  <versioning>
6
- <latest>55.0.9</latest>
7
- <release>55.0.9</release>
6
+ <latest>55.0.10</latest>
7
+ <release>55.0.10</release>
8
8
  <versions>
9
- <version>55.0.9</version>
9
+ <version>55.0.10</version>
10
10
  </versions>
11
- <lastUpdated>20260225012630</lastUpdated>
11
+ <lastUpdated>20260317165310</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -1 +1 @@
1
- 1238093353be89262db46d8f035133b6
1
+ d8e399bddb9b6e43f90f200e287e3336
@@ -1 +1 @@
1
- fa77faef1385089f02e4b355a0f7c1e417997de5
1
+ 9f28052ab1b3d4efbc2eb5e520112fcf80497354
@@ -1 +1 @@
1
- a18c30b4c72ce5e84f8b85d0b38b7682e274f237064e93f885056d4d1d515fa0
1
+ 9fce977db89a139b4d673fd5a7e83a9650a71e537e98d8591276b6cb0e59a8f1
@@ -1 +1 @@
1
- e19d4d433b8f78f625b54f0eeefdc6378a5a5e1124e1b270abce958157cc4afdf17333719cd4cf463648546f2941488db3bcf7d84fa397960a18253cb0717475
1
+ e0d7fd85b52c68f38d365503b99b3742e4ac5846c482facbfe3b9c8d74a2a9600e4857bfe56d3ea20aba51377f95150af5b828fc440280b6ef2ca955a46ab6f4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-task-manager",
3
- "version": "55.0.9",
3
+ "version": "55.0.10",
4
4
  "description": "Expo module that provides support for tasks that can run in the background.",
5
5
  "main": "build/TaskManager.js",
6
6
  "types": "build/TaskManager.d.ts",
@@ -42,5 +42,5 @@
42
42
  "expo": "*",
43
43
  "react-native": "*"
44
44
  },
45
- "gitHead": "b183e5cbd95eb6ee54a878291c7077d8d63e4850"
45
+ "gitHead": "9260ae10a08271027d85792b7128e0d4883dca4d"
46
46
  }
@@ -1,7 +1,15 @@
1
- import { LegacyEventEmitter, UnavailabilityError } from 'expo-modules-core';
1
+ import { LegacyEventEmitter, Platform, UnavailabilityError } from 'expo-modules-core';
2
+ import { AppRegistry } from 'react-native';
2
3
 
3
4
  import ExpoTaskManager from './ExpoTaskManager';
4
5
 
6
+ // Register a no-op headless task so that HeadlessJsTaskContext.startTask()
7
+ // doesn't log a warning. On Android, TaskService registers a headless task
8
+ // in native code to keep JS timers alive during background task execution.
9
+ if (Platform.OS === 'android') {
10
+ AppRegistry.registerHeadlessTask('expo-task-manager', () => async () => {});
11
+ }
12
+
5
13
  // @needsAudit @docsMissing
6
14
  /**
7
15
  * Error object that can be received through [`TaskManagerTaskBody`](#taskmanagertaskbody) when the
@@ -1 +0,0 @@
1
- 1a13d4a1c5042d7b5296e9db9937989f7f1fe3d3620bdfffffd2e243292fbcf5
@@ -1 +0,0 @@
1
- 755c124c19182bd5f33e1ef1f9061190b731e8e3137f094edfaee8ed0a880fccab5f1011e1a5c48205c86df424e9776bb9e59020e062dea6c8db1a8bca4af50d
@@ -1 +0,0 @@
1
- a1243705ad1e8528fb334a20d31756ff78f1a7ab0ee15406890004f92f653993
@@ -1 +0,0 @@
1
- cd82576f43c8b2300966dff0c640590cc4c00933cd6ede6d682a2d46b13a47a12798d8e547e3693be3211651f5c3879b14754be054e683a54e59a1e44bc930a9
@@ -1 +0,0 @@
1
- aa27ac772033a80a41e76aae202338bd8c384722dba656e317dea2cb05e0f430
@@ -1 +0,0 @@
1
- 26154d8a9ef18aae2aeb434c47b627893dd92b5b8cda7212dd24d69d1e85e08881442472eb9441df9f11dbc8a3927c7b4381a4e4d883a14133ed46bc00742518
@@ -1 +0,0 @@
1
- de4a2eebc489b50f7d3add5b59cff244f995d66376d0c12e2937eda698bf7676
@@ -1 +0,0 @@
1
- 4dcb5c619680678188aa2b73532d478806a855c1d8098139acb11e88fddc78a63ffe94bdce087c3e90a9b6ade11fb5be84629e69c259f96c36b4af9d8b42d52a