expo-task-manager 14.0.10-canary-20251230-fc48ddc → 14.0.10-canary-20260113-0ce2b9c

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 (63) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/expo/modules/taskManager/TaskManagerInternalModule.java +1 -1
  4. package/android/src/main/java/expo/modules/taskManager/TaskManagerUtils.java +49 -51
  5. package/android/src/main/java/expo/modules/taskManager/TaskService.java +1 -5
  6. package/android/src/main/java/expo/modules/taskManager/Utils.java +10 -1
  7. package/expo-module.config.json +5 -1
  8. package/ios/EXTaskManager/EXTask.m +1 -1
  9. package/ios/EXTaskManager/EXTaskExecutionRequest.m +1 -1
  10. package/ios/EXTaskManager/EXTaskService.h +5 -4
  11. package/ios/EXTaskManager/EXTaskService.m +16 -5
  12. package/ios/ExpoTaskManager.podspec +31 -0
  13. package/ios/TaskManagerAppDelegateSubscriber.swift +16 -0
  14. package/ios/TaskManagerModule.swift +111 -0
  15. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c-sources.jar +0 -0
  16. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c-sources.jar.md5 +1 -0
  17. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c-sources.jar.sha1 +1 -0
  18. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c-sources.jar.sha256 +1 -0
  19. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c-sources.jar.sha512 +1 -0
  20. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c.aar +0 -0
  21. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c.aar.md5 +1 -0
  22. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c.aar.sha1 +1 -0
  23. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c.aar.sha256 +1 -0
  24. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c.aar.sha512 +1 -0
  25. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/{14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc.module → 14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c.module} +23 -23
  26. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c.module.md5 +1 -0
  27. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c.module.sha1 +1 -0
  28. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c.module.sha256 +1 -0
  29. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c.module.sha512 +1 -0
  30. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/{14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc.pom → 14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c.pom} +2 -2
  31. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c.pom.md5 +1 -0
  32. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c.pom.sha1 +1 -0
  33. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c.pom.sha256 +1 -0
  34. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20260113-0ce2b9c/expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c.pom.sha512 +1 -0
  35. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/maven-metadata.xml +4 -4
  36. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/maven-metadata.xml.md5 +1 -1
  37. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/maven-metadata.xml.sha1 +1 -1
  38. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/maven-metadata.xml.sha256 +1 -1
  39. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/maven-metadata.xml.sha512 +1 -1
  40. package/package.json +4 -4
  41. package/ios/EXTaskManager/EXTaskManager.h +0 -13
  42. package/ios/EXTaskManager/EXTaskManager.m +0 -212
  43. package/ios/EXTaskManager/EXTaskManagerAppDelegate.h +0 -13
  44. package/ios/EXTaskManager/EXTaskManagerAppDelegate.m +0 -29
  45. package/ios/EXTaskManager.podspec +0 -31
  46. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc-sources.jar +0 -0
  47. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc-sources.jar.md5 +0 -1
  48. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc-sources.jar.sha1 +0 -1
  49. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc-sources.jar.sha256 +0 -1
  50. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc-sources.jar.sha512 +0 -1
  51. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc.aar +0 -0
  52. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc.aar.md5 +0 -1
  53. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc.aar.sha1 +0 -1
  54. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc.aar.sha256 +0 -1
  55. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc.aar.sha512 +0 -1
  56. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc.module.md5 +0 -1
  57. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc.module.sha1 +0 -1
  58. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc.module.sha256 +0 -1
  59. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc.module.sha512 +0 -1
  60. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc.pom.md5 +0 -1
  61. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc.pom.sha1 +0 -1
  62. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc.pom.sha256 +0 -1
  63. package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/14.0.10-canary-20251230-fc48ddc/expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc.pom.sha512 +0 -1
package/CHANGELOG.md CHANGED
@@ -8,8 +8,12 @@
8
8
 
9
9
  ### 🐛 Bug fixes
10
10
 
11
+ - [Android] Fix job scheduling ANR caused by cancel/reschedule pattern that prevented jobs from executing and accumulated data until exceeding Binder transaction limit. ([#41688](https://github.com/expo/expo/pull/41688) by [@tyrauber](https://github.com/tyrauber))
12
+
11
13
  ### 💡 Others
12
14
 
15
+ - [iOS] Migrated the native module to Swift. ([#41911](https://github.com/expo/expo/pull/41911) by [@tsapeta](https://github.com/tsapeta))
16
+
13
17
  ## 14.0.9 - 2025-12-05
14
18
 
15
19
  _This version does not introduce any user-facing changes._
@@ -4,13 +4,13 @@ plugins {
4
4
  }
5
5
 
6
6
  group = 'host.exp.exponent'
7
- version = '14.0.10-canary-20251230-fc48ddc'
7
+ version = '14.0.10-canary-20260113-0ce2b9c'
8
8
 
9
9
  android {
10
10
  namespace "expo.modules.taskmanager"
11
11
  defaultConfig {
12
12
  versionCode 23
13
- versionName "14.0.10-canary-20251230-fc48ddc"
13
+ versionName "14.0.10-canary-20260113-0ce2b9c"
14
14
  }
15
15
  }
16
16
 
@@ -49,7 +49,7 @@ public class TaskManagerInternalModule implements InternalModule, TaskManagerInt
49
49
  @Override
50
50
  public void onCreate(ModuleRegistry moduleRegistry) {
51
51
  mUIManager = moduleRegistry.getModule(UIManager.class);
52
- mConstants = moduleRegistry.getModule(ConstantsInterface.class);
52
+ mConstants = moduleRegistry.getAppContext().service(ConstantsInterface.class);
53
53
  mTaskService = moduleRegistry.getSingletonModule("TaskService", TaskServiceInterface.class);
54
54
 
55
55
  // Register in TaskService.
@@ -15,15 +15,11 @@ import android.os.PersistableBundle;
15
15
  import android.util.Log;
16
16
 
17
17
  import java.util.ArrayList;
18
- import java.util.Collections;
19
- import java.util.Comparator;
20
18
  import java.util.List;
21
19
  import java.util.Map;
22
- import java.util.Set;
23
20
 
24
21
  import androidx.annotation.NonNull;
25
22
  import androidx.annotation.Nullable;
26
- import androidx.collection.ArraySet;
27
23
 
28
24
  import expo.modules.interfaces.taskManager.TaskExecutionCallback;
29
25
  import expo.modules.interfaces.taskManager.TaskInterface;
@@ -31,7 +27,8 @@ import expo.modules.interfaces.taskManager.TaskManagerUtilsInterface;
31
27
 
32
28
  public class TaskManagerUtils implements TaskManagerUtilsInterface {
33
29
 
34
- // Key that every job created by the task manager must contain in its extras bundle.
30
+ // Key that every job created by the task manager must contain in its extras
31
+ // bundle.
35
32
  private static final String EXTRAS_REQUIRED_KEY = "expo.modules.taskManager";
36
33
  private static final String TAG = "TaskManagerUtils";
37
34
 
@@ -40,9 +37,15 @@ public class TaskManagerUtils implements TaskManagerUtilsInterface {
40
37
 
41
38
  private static final int DEFAULT_OVERRIDE_DEADLINE = 60 * 1000; // 1 minute
42
39
 
43
- private static final Set<TaskInterface> sTasksReschedulingJob = new ArraySet<>();
40
+ // Leave buffer before Android's job limit to avoid edge cases.
41
+ private static final int JOB_LIMIT_BUFFER = 10;
44
42
 
45
- //region TaskManagerUtilsInterface
43
+ private static int getJobLimit() {
44
+ // Android 12 (API 31+) increased limit from 100 to 150
45
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? 150 : 100;
46
+ }
47
+
48
+ // region TaskManagerUtilsInterface
46
49
 
47
50
  @Override
48
51
  public PendingIntent createTaskIntent(Context context, TaskInterface task) {
@@ -100,18 +103,6 @@ public class TaskManagerUtils implements TaskManagerUtilsInterface {
100
103
  }
101
104
 
102
105
  //endregion TaskManagerUtilsInterface
103
- //region static helpers
104
-
105
- static boolean notifyTaskJobCancelled(TaskInterface task) {
106
- boolean isRescheduled = sTasksReschedulingJob.contains(task);
107
-
108
- if (isRescheduled) {
109
- sTasksReschedulingJob.remove(task);
110
- }
111
- return isRescheduled;
112
- }
113
-
114
- //endregion static helpers
115
106
  //region private helpers
116
107
 
117
108
  private void updateOrScheduleJob(Context context, TaskInterface task, List<PersistableBundle> data) {
@@ -129,47 +120,41 @@ public class TaskManagerUtils implements TaskManagerUtilsInterface {
129
120
  pendingJobs = new ArrayList<>();
130
121
  }
131
122
 
132
- Collections.sort(pendingJobs, new Comparator<JobInfo>() {
133
- @Override
134
- public int compare(JobInfo a, JobInfo b) {
135
- return Integer.compare(a.getId(), b.getId());
136
- }
137
- });
138
-
139
- // We will be looking for the lowest number that is not being used yet.
123
+ // Find newest job for this task (for merging if needed) and next available ID
140
124
  int newJobId = 0;
125
+ JobInfo newestJob = null;
141
126
 
142
127
  for (JobInfo jobInfo : pendingJobs) {
143
128
  int jobId = jobInfo.getId();
144
-
129
+ if (jobId >= newJobId) {
130
+ newJobId = jobId + 1;
131
+ }
145
132
  if (isJobInfoRelatedToTask(jobInfo, task)) {
146
- JobInfo mergedJobInfo = createJobInfoByAddingData(jobInfo, data);
147
-
148
- // Add the task to the list of rescheduled tasks.
149
- sTasksReschedulingJob.add(task);
150
-
151
- try {
152
- // Cancel jobs with the same ID to let them be rescheduled.
153
- jobScheduler.cancel(jobId);
154
-
155
- // Reschedule job for given task.
156
- jobScheduler.schedule(mergedJobInfo);
157
- } catch (IllegalStateException e) {
158
- Log.e(this.getClass().getName(), "Unable to reschedule a job: " + e.getMessage());
133
+ if (newestJob == null || jobId > newestJob.getId()) {
134
+ newestJob = jobInfo;
159
135
  }
160
- return;
161
136
  }
162
- if (newJobId == jobId) {
163
- newJobId++;
137
+ }
138
+
139
+ // At Android's job limit? Merge into newest job for this task.
140
+ if (pendingJobs.size() >= getJobLimit() - JOB_LIMIT_BUFFER && newestJob != null) {
141
+ Log.i(TAG, "Approaching job limit (" + pendingJobs.size() + "). Merging data for task '" + task.getName() + "'.");
142
+ try {
143
+ JobInfo mergedJobInfo = createJobInfoByAddingData(newestJob, data);
144
+ jobScheduler.cancel(newestJob.getId());
145
+ jobScheduler.schedule(mergedJobInfo);
146
+ } catch (IllegalStateException e) {
147
+ Log.e(this.getClass().getName(), "Unable to merge job: " + e.getMessage());
164
148
  }
149
+ return;
165
150
  }
166
151
 
152
+ // Under limit: schedule as new job. Don't touch existing jobs.
167
153
  try {
168
- // Given task doesn't have any pending jobs yet, create a new JobInfo and schedule it then.
169
154
  JobInfo jobInfo = createJobInfo(context, task, newJobId, data);
170
155
  jobScheduler.schedule(jobInfo);
171
156
  } catch (IllegalStateException e) {
172
- Log.e(this.getClass().getName(), "Unable to schedule a new job: " + e.getMessage());
157
+ Log.e(this.getClass().getName(), "Unable to schedule job: " + e.getMessage());
173
158
  }
174
159
  }
175
160
 
@@ -215,11 +200,24 @@ public class TaskManagerUtils implements TaskManagerUtilsInterface {
215
200
  }
216
201
 
217
202
  private JobInfo createJobInfo(int jobId, ComponentName jobService, PersistableBundle extras) {
218
- return new JobInfo.Builder(jobId, jobService)
219
- .setExtras(extras)
220
- .setMinimumLatency(0)
221
- .setOverrideDeadline(DEFAULT_OVERRIDE_DEADLINE)
222
- .build();
203
+ JobInfo.Builder jobBuilder = new JobInfo.Builder(jobId, jobService)
204
+ .setExtras(extras)
205
+ .setPersisted(true)
206
+ .setRequiresDeviceIdle(false);
207
+
208
+ if (Build.VERSION.SDK_INT < 28) {
209
+ // For Android versions below 28 (Android 9 and below)
210
+ jobBuilder.setMinimumLatency(0)
211
+ .setOverrideDeadline(DEFAULT_OVERRIDE_DEADLINE);
212
+ } else if (Build.VERSION.SDK_INT < 31) {
213
+ // For Android 9 (API 28) to Android 11 (API 30)
214
+ jobBuilder.setImportantWhileForeground(true);
215
+ } else {
216
+ // For Android 12 (API 31) and above
217
+ jobBuilder.setExpedited(true);
218
+ }
219
+
220
+ return jobBuilder.build();
223
221
  }
224
222
 
225
223
  private JobInfo createJobInfo(Context context, TaskInterface task, int jobId, List<PersistableBundle> data) {
@@ -349,10 +349,7 @@ public class TaskService implements SingletonModule, TaskServiceInterface {
349
349
 
350
350
  TaskInterface task = getTask(taskName, appScopeKey);
351
351
 
352
- // `notifyTaskJobCancelled` notifies TaskManagerUtils about a job for task being cancelled.
353
- // It returns `true` if the job has been intentionally cancelled to be rescheduled,
354
- // in that case we don't want to inform the consumer about cancellation.
355
- if (task != null && !TaskManagerUtils.notifyTaskJobCancelled(task)) {
352
+ if (task != null) {
356
353
  TaskConsumerInterface consumer = task.getConsumer();
357
354
 
358
355
  if (consumer == null) {
@@ -361,7 +358,6 @@ public class TaskService implements SingletonModule, TaskServiceInterface {
361
358
 
362
359
  Log.i(TAG, "Job for task '" + taskName + "' has been cancelled by the system.");
363
360
 
364
- // cancels task
365
361
  return consumer.didCancelJob(jobService, params);
366
362
  }
367
363
 
@@ -103,7 +103,10 @@ public class Utils {
103
103
  for (int i = 0; i < json.length(); i++) {
104
104
  Object value = json.get(i);
105
105
 
106
- if (value instanceof JSONArray) {
106
+ // Handle JSONObject.NULL - convert to actual Java null
107
+ if (value == JSONObject.NULL) {
108
+ value = null;
109
+ } else if (value instanceof JSONArray) {
107
110
  value = jsonToList((JSONArray) value);
108
111
  } else if (value instanceof JSONObject) {
109
112
  value = jsonToMap((JSONObject) value);
@@ -117,6 +120,12 @@ public class Utils {
117
120
  }
118
121
 
119
122
  public static Object jsonObjectToObject(Object json) {
123
+ // Handle JSONObject.NULL - convert to actual Java null
124
+ // JSONObject.NULL is returned when a JSON key has a null value
125
+ // and it's an instance of a special singleton class (JSONObject$1)
126
+ if (json == null || json == JSONObject.NULL) {
127
+ return null;
128
+ }
120
129
  if (json instanceof JSONObject) {
121
130
  return jsonToMap((JSONObject) json);
122
131
  }
@@ -1,11 +1,15 @@
1
1
  {
2
2
  "platforms": ["apple", "android"],
3
+ "ios": {
4
+ "modules": ["TaskManagerModule"],
5
+ "appDelegateSubscribers": ["TaskManagerAppDelegateSubscriber"]
6
+ },
3
7
  "android": {
4
8
  "modules": ["expo.modules.taskManager.TaskManagerModule"],
5
9
  "publication": {
6
10
  "groupId": "host.exp.exponent",
7
11
  "artifactId": "expo.modules.taskmanager",
8
- "version": "14.0.10-canary-20251230-fc48ddc",
12
+ "version": "14.0.10-canary-20260113-0ce2b9c",
9
13
  "repository": "local-maven-repo"
10
14
  }
11
15
  }
@@ -1,6 +1,6 @@
1
1
  // Copyright 2018-present 650 Industries. All rights reserved.
2
2
 
3
- #import <EXTaskManager/EXTask.h>
3
+ #import <ExpoTaskManager/EXTask.h>
4
4
 
5
5
  @implementation EXTask
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Copyright 2018-present 650 Industries. All rights reserved.
2
2
 
3
- #import <EXTaskManager/EXTaskExecutionRequest.h>
3
+ #import <ExpoTaskManager/EXTaskExecutionRequest.h>
4
4
 
5
5
  @interface EXTaskExecutionRequest ()
6
6
 
@@ -1,11 +1,12 @@
1
1
  // Copyright 2018-present 650 Industries. All rights reserved.
2
2
 
3
- #import <ExpoModulesCore/EXSingletonModule.h>
4
3
  #import <ExpoModulesCore/EXTaskServiceInterface.h>
5
- #import <EXTaskManager/EXTask.h>
6
- #import <EXTaskManager/EXTaskExecutionRequest.h>
4
+ #import <ExpoTaskManager/EXTask.h>
5
+ #import <ExpoTaskManager/EXTaskExecutionRequest.h>
7
6
 
8
- @interface EXTaskService : EXSingletonModule <EXTaskServiceInterface, EXTaskDelegate>
7
+ @interface EXTaskService : NSObject <EXTaskServiceInterface, EXTaskDelegate>
8
+
9
+ @property (nonatomic, nonnull, readonly, class) EXTaskService *shared;
9
10
 
10
11
  + (BOOL)hasBackgroundModeEnabled:(nonnull NSString *)backgroundMode;
11
12
 
@@ -3,12 +3,14 @@
3
3
  #import <ExpoModulesCore/EXDefines.h>
4
4
  #import <ExpoModulesCore/EXTaskConsumerInterface.h>
5
5
 
6
- #import <EXTaskManager/EXTask.h>
7
- #import <EXTaskManager/EXTaskService.h>
6
+ #import <ExpoTaskManager/EXTask.h>
7
+ #import <ExpoTaskManager/EXTaskService.h>
8
8
 
9
9
  #import <UMAppLoader/UMAppLoaderProvider.h>
10
10
  #import <UMAppLoader/UMAppRecordInterface.h>
11
11
 
12
+ #import <React/RCTLog.h>
13
+
12
14
  @interface EXTaskService ()
13
15
 
14
16
  // Array of task requests that are being executed.
@@ -37,7 +39,16 @@
37
39
 
38
40
  @implementation EXTaskService
39
41
 
40
- EX_REGISTER_SINGLETON_MODULE(TaskService)
42
+ + (nonnull EXTaskService *)shared
43
+ {
44
+ static EXTaskService *sharedInstance = nil;
45
+ static dispatch_once_t onceToken;
46
+
47
+ dispatch_once(&onceToken, ^{
48
+ sharedInstance = [[EXTaskService alloc] init];
49
+ });
50
+ return sharedInstance;
51
+ }
41
52
 
42
53
  - (instancetype)init
43
54
  {
@@ -615,7 +626,7 @@ EX_REGISTER_SINGLETON_MODULE(TaskService)
615
626
  consumerClass:consumerClass
616
627
  options:taskConfig[@"options"]];
617
628
  } else {
618
- EXLogWarn(
629
+ RCTLogWarn(
619
630
  @"EXTaskService: Task consumer '%@' has version '%d' that is not compatible with the saved version '%d'.",
620
631
  consumerClassName,
621
632
  currentConsumerVersion,
@@ -624,7 +635,7 @@ EX_REGISTER_SINGLETON_MODULE(TaskService)
624
635
  [self _removeTaskFromConfig:taskName appId:appId];
625
636
  }
626
637
  } else {
627
- EXLogWarn(@"EXTaskService: Cannot restore task '%@' because consumer class doesn't exist.", taskName);
638
+ RCTLogWarn(@"EXTaskService: Cannot restore task '%@' because consumer class doesn't exist.", taskName);
628
639
  [self _removeTaskFromConfig:taskName appId:appId];
629
640
  }
630
641
  }
@@ -0,0 +1,31 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = 'ExpoTaskManager'
7
+ s.version = package['version']
8
+ s.summary = package['description']
9
+ s.description = package['description']
10
+ s.license = package['license']
11
+ s.author = package['author']
12
+ s.homepage = package['homepage']
13
+ s.platforms = {
14
+ :ios => '15.1',
15
+ :tvos => '15.1'
16
+ }
17
+ s.swift_version = '6.0'
18
+ s.source = { git: 'https://github.com/expo/expo.git' }
19
+ s.static_framework = true
20
+
21
+ s.dependency 'ExpoModulesCore'
22
+ s.dependency 'UMAppLoader'
23
+
24
+ s.pod_target_xcconfig = {
25
+ 'DEFINES_MODULE' => 'YES',
26
+ }
27
+ s.resource_bundles = {
28
+ 'ExpoTaskManager_privacy' => ['PrivacyInfo.xcprivacy']
29
+ }
30
+ s.source_files = '**/*.{h,m,mm,swift}'
31
+ end
@@ -0,0 +1,16 @@
1
+ import ExpoModulesCore
2
+
3
+ public class TaskManagerAppDelegateSubscriber: ExpoAppDelegateSubscriber {
4
+ public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
5
+ EXTaskService.shared.applicationDidFinishLaunching(options: launchOptions)
6
+ return false
7
+ }
8
+
9
+ public func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
10
+ EXTaskService.shared.runTasks(with: EXTaskLaunchReasonBackgroundFetch, userInfo: nil, completionHandler: completionHandler)
11
+ }
12
+
13
+ public func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
14
+ EXTaskService.shared.runTasks(with: EXTaskLaunchReasonRemoteNotification, userInfo: userInfo, completionHandler: completionHandler)
15
+ }
16
+ }
@@ -0,0 +1,111 @@
1
+ // Copyright 2025-present 650 Industries. All rights reserved.
2
+
3
+ import ExpoModulesCore
4
+
5
+ public typealias AppId = String
6
+ public typealias TaskName = String
7
+
8
+ private let EXECUTE_TASK_EVENT_NAME = "TaskManager.executeTask"
9
+
10
+ public final class TaskManagerModule: Module, EXTaskManagerInterface {
11
+ let appId: AppId = "mainApplication"
12
+ var eventsQueue: [[String: Any]]? = []
13
+
14
+ public func definition() -> ModuleDefinition {
15
+ Name("ExpoTaskManager")
16
+
17
+ Events(EXECUTE_TASK_EVENT_NAME)
18
+
19
+ OnCreate {
20
+ EXTaskService.shared.setTaskManager(self, forAppId: appId, withUrl: findAppUrl())
21
+ }
22
+
23
+ Constant("EVENT_NAME") {
24
+ return EXECUTE_TASK_EVENT_NAME
25
+ }
26
+
27
+ OnStartObserving(EXECUTE_TASK_EVENT_NAME) {
28
+ // When `OnStartObserving` is called, the app is ready to execute new tasks.
29
+ // It sends all events that were queued before this call.
30
+ if let eventsQueue {
31
+ for eventBody in eventsQueue {
32
+ sendEvent(EXECUTE_TASK_EVENT_NAME, eventBody)
33
+ }
34
+ }
35
+ // We will not need the queue anymore.
36
+ eventsQueue = nil
37
+ }
38
+
39
+ AsyncFunction("isAvailableAsync") {
40
+ return true
41
+ }
42
+
43
+ AsyncFunction("notifyTaskFinishedAsync") { (taskName: TaskName, response: [String: Any]) in
44
+ EXTaskService.shared.notifyTask(withName: taskName, forAppId: appId, didFinishWithResponse: response)
45
+ }
46
+
47
+ AsyncFunction("isTaskRegisteredAsync") { (taskName: TaskName) in
48
+ return hasRegisteredTask(withName: taskName)
49
+ }
50
+
51
+ AsyncFunction("getRegisteredTasksAsync") {
52
+ return EXTaskService.shared.getRegisteredTasks(forAppId: appId)
53
+ }
54
+
55
+ AsyncFunction("getTaskOptionsAsync") { (taskName: TaskName) in
56
+ return EXTaskService.shared.getOptionsForTaskName(taskName, forAppId: appId)
57
+ }
58
+
59
+ AsyncFunction("unregisterTaskAsync") { (taskName: TaskName) in
60
+ try EXUtilities.catchException {
61
+ self.unregisterTask(withName: taskName, consumerClass: nil)
62
+ }
63
+ }
64
+
65
+ AsyncFunction("unregisterAllTasksAsync") {
66
+ EXTaskService.shared.unregisterAllTasks(forAppId: appId)
67
+ }
68
+ }
69
+
70
+ // MARK: - EXTaskManagerInterface
71
+
72
+ public func hasRegisteredTask(withName taskName: TaskName) -> Bool {
73
+ return EXTaskService.shared.hasRegisteredTask(withName: taskName, forAppId: appId)
74
+ }
75
+
76
+ public func task(withName taskName: TaskName, hasConsumerOf consumerClass: AnyClass) -> Bool {
77
+ return EXTaskService.shared.task(withName: taskName, forAppId: appId, hasConsumerOf: consumerClass)
78
+ }
79
+
80
+ public func registerTask(withName taskName: TaskName, consumer consumerClass: AnyClass, options: [AnyHashable: Any] = [:]) {
81
+ let appUrl = findAppUrl()
82
+ EXTaskService.shared.registerTask(withName: taskName, appId: appId, appUrl: appUrl, consumerClass: consumerClass, options: options)
83
+ }
84
+
85
+ public func unregisterTask(withName taskName: TaskName, consumerClass: AnyClass?) {
86
+ EXTaskService.shared.unregisterTask(withName: taskName, forAppId: appId, consumerClass: consumerClass)
87
+ }
88
+
89
+ public func hasBackgroundModeEnabled(_ backgroundMode: String) -> Bool {
90
+ return EXTaskService.hasBackgroundModeEnabled(backgroundMode)
91
+ }
92
+
93
+ public func execute(withBody body: [String: Any]) {
94
+ if eventsQueue != nil {
95
+ // The module was created, but JS is not listening for events yet.
96
+ // In that case we need to queue them up.
97
+ eventsQueue?.append(body)
98
+ } else {
99
+ // JS is already listening to the event, we can emit it straight away.
100
+ sendEvent(EXECUTE_TASK_EVENT_NAME, body)
101
+ }
102
+ }
103
+
104
+ public func isRunningInHeadlessMode() -> Bool {
105
+ return appContext?.constants?.constants()["isHeadless"] as? Bool ?? false
106
+ }
107
+
108
+ private func findAppUrl() -> String? {
109
+ return appContext?.constants?.constants()["experienceUrl"] as? String
110
+ }
111
+ }
@@ -0,0 +1 @@
1
+ 81667fa2aa27c43b920cd63dfc7aee343eee898533c83873af8f21d8d214fa0b89b8e2ce3a22da3d495c05a743adf6965d798105f22d02f715dcb0286426e1dd
@@ -0,0 +1 @@
1
+ d54312456cab0ff0115fa2697669fd4cc8de1261e53af45e7a43467b8535643101afcccbe5d9545300caffe28d511351f29c3b9ea410450f36cfdaefe0e6ae87
@@ -3,7 +3,7 @@
3
3
  "component": {
4
4
  "group": "host.exp.exponent",
5
5
  "module": "expo.modules.taskmanager",
6
- "version": "14.0.10-canary-20251230-fc48ddc",
6
+ "version": "14.0.10-canary-20260113-0ce2b9c",
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-14.0.10-canary-20251230-fc48ddc.aar",
37
- "url": "expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc.aar",
38
- "size": 65074,
39
- "sha512": "770d465ed9a7f53291b9ab2d6ec2f863bbf808ea039001791e97da514d54264589d3872c4fed32b6d25ac357bf82a05ccaca9ae88fcf19e547f8d6e948fd7fd7",
40
- "sha256": "bb3e8c76dc8b2136da793dd000c07cacdd86b4bc211dace3bed921bab4cbbee3",
41
- "sha1": "cfc7126eab7b60913ee982353ece061123565fdb",
42
- "md5": "62c71d9ca2dfa51f3ba48bf73a8e1990"
36
+ "name": "expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c.aar",
37
+ "url": "expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c.aar",
38
+ "size": 64564,
39
+ "sha512": "d54312456cab0ff0115fa2697669fd4cc8de1261e53af45e7a43467b8535643101afcccbe5d9545300caffe28d511351f29c3b9ea410450f36cfdaefe0e6ae87",
40
+ "sha256": "75cd598721f9d8e0131765e3ea738d6d2359439b581a861ca53329185a26ff19",
41
+ "sha1": "3ab23fc4ac57db1bcc463997c855364c31170dc7",
42
+ "md5": "583e1fabefe72215de826c0511469a6f"
43
43
  }
44
44
  ]
45
45
  },
@@ -63,7 +63,7 @@
63
63
  "group": "host.exp.exponent",
64
64
  "module": "org.unimodules.apploader",
65
65
  "version": {
66
- "requires": "6.0.9-canary-20251230-fc48ddc"
66
+ "requires": "6.0.9-canary-20260113-0ce2b9c"
67
67
  }
68
68
  },
69
69
  {
@@ -76,13 +76,13 @@
76
76
  ],
77
77
  "files": [
78
78
  {
79
- "name": "expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc.aar",
80
- "url": "expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc.aar",
81
- "size": 65074,
82
- "sha512": "770d465ed9a7f53291b9ab2d6ec2f863bbf808ea039001791e97da514d54264589d3872c4fed32b6d25ac357bf82a05ccaca9ae88fcf19e547f8d6e948fd7fd7",
83
- "sha256": "bb3e8c76dc8b2136da793dd000c07cacdd86b4bc211dace3bed921bab4cbbee3",
84
- "sha1": "cfc7126eab7b60913ee982353ece061123565fdb",
85
- "md5": "62c71d9ca2dfa51f3ba48bf73a8e1990"
79
+ "name": "expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c.aar",
80
+ "url": "expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c.aar",
81
+ "size": 64564,
82
+ "sha512": "d54312456cab0ff0115fa2697669fd4cc8de1261e53af45e7a43467b8535643101afcccbe5d9545300caffe28d511351f29c3b9ea410450f36cfdaefe0e6ae87",
83
+ "sha256": "75cd598721f9d8e0131765e3ea738d6d2359439b581a861ca53329185a26ff19",
84
+ "sha1": "3ab23fc4ac57db1bcc463997c855364c31170dc7",
85
+ "md5": "583e1fabefe72215de826c0511469a6f"
86
86
  }
87
87
  ]
88
88
  },
@@ -96,13 +96,13 @@
96
96
  },
97
97
  "files": [
98
98
  {
99
- "name": "expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc-sources.jar",
100
- "url": "expo.modules.taskmanager-14.0.10-canary-20251230-fc48ddc-sources.jar",
101
- "size": 22851,
102
- "sha512": "8b736d920f293730c6e21c622e290b98572a20da941a55cc2115d2557f75f1336ddc016e74c2490da6f28db1324ad47a31002f55a1a003129c0e084de554c38b",
103
- "sha256": "835897e4e38b3abc2084054d950204a7a812dee7c650c6665f7ed3e10ada565e",
104
- "sha1": "7ef651ce45f55ed6ccbc443d5c1b47dec40f640c",
105
- "md5": "c56a4cba148e230ef3f14439d3afd694"
99
+ "name": "expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c-sources.jar",
100
+ "url": "expo.modules.taskmanager-14.0.10-canary-20260113-0ce2b9c-sources.jar",
101
+ "size": 22995,
102
+ "sha512": "81667fa2aa27c43b920cd63dfc7aee343eee898533c83873af8f21d8d214fa0b89b8e2ce3a22da3d495c05a743adf6965d798105f22d02f715dcb0286426e1dd",
103
+ "sha256": "7068346a53195adaac8d873f1021cf442adf6d141c1ad2d38c729f61cdecb3da",
104
+ "sha1": "75df1a72794b0b5bc43bb7a358f41a4935432f37",
105
+ "md5": "61b4fd02dc0c66b951e7f16846a59b7b"
106
106
  }
107
107
  ]
108
108
  }
@@ -0,0 +1 @@
1
+ d26a2f3bfbb185f157c4b3796ce6a337f0ce96e1c12e08fb0f30879e8423d59e94334b9cc8c40f4425a9d923346eab81fed78f376992a2beb88a42cbc2419508
@@ -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>14.0.10-canary-20251230-fc48ddc</version>
12
+ <version>14.0.10-canary-20260113-0ce2b9c</version>
13
13
  <packaging>aar</packaging>
14
14
  <name>expo.modules.taskmanager</name>
15
15
  <url>https://github.com/expo/expo</url>
@@ -40,7 +40,7 @@
40
40
  <dependency>
41
41
  <groupId>host.exp.exponent</groupId>
42
42
  <artifactId>org.unimodules.apploader</artifactId>
43
- <version>6.0.9-canary-20251230-fc48ddc</version>
43
+ <version>6.0.9-canary-20260113-0ce2b9c</version>
44
44
  <scope>runtime</scope>
45
45
  </dependency>
46
46
  </dependencies>
@@ -0,0 +1 @@
1
+ 83d15d29def72db11198fd3d7d1d8cc4d916b569aec3d6d132a225770af893a7e6e6864a43a297ae40ff9d4ae6e292affea267e22b5bfcb854981960a007f89e
@@ -3,11 +3,11 @@
3
3
  <groupId>host.exp.exponent</groupId>
4
4
  <artifactId>expo.modules.taskmanager</artifactId>
5
5
  <versioning>
6
- <latest>14.0.10-canary-20251230-fc48ddc</latest>
7
- <release>14.0.10-canary-20251230-fc48ddc</release>
6
+ <latest>14.0.10-canary-20260113-0ce2b9c</latest>
7
+ <release>14.0.10-canary-20260113-0ce2b9c</release>
8
8
  <versions>
9
- <version>14.0.10-canary-20251230-fc48ddc</version>
9
+ <version>14.0.10-canary-20260113-0ce2b9c</version>
10
10
  </versions>
11
- <lastUpdated>20251230162924</lastUpdated>
11
+ <lastUpdated>20260113181513</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -1 +1 @@
1
- da457a09f0cf19a5056a919554c757bc
1
+ 4da6051a2ac2718934ade22a11e0f114
@@ -1 +1 @@
1
- 9003513d3663e65fcac95ec5a19f5c62216777d3
1
+ 4f58ac44f2bfdb6290b394961ce275eb83bd916c
@@ -1 +1 @@
1
- 2a040c8f2c8bca9f539fe7e968536032d053d1ed07c0c2fbe0d63e4fe752ac26
1
+ 659ad79520f83ae393bffa8483490e91c1a9f6a003e60405ff933397a3ff9ecc
@@ -1 +1 @@
1
- 63782007deeec850102496abd3b64bfcd8ee5654355b8cd23564f229c3a7f0be07d9f7f48ca31f93cc4c2cd9c1e68b871eb72a55f2b0e5722a237fe3d012362b
1
+ b37841158633b640104f2627d8896d3902a7810d8b8dfe18709e8dc6483d4c2ade516361c213828ff3e0dbf5eadb3f1035dc1b7052f1735b96161b8180ecbdfd
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-task-manager",
3
- "version": "14.0.10-canary-20251230-fc48ddc",
3
+ "version": "14.0.10-canary-20260113-0ce2b9c",
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",
@@ -33,13 +33,13 @@
33
33
  "license": "MIT",
34
34
  "homepage": "https://docs.expo.dev/versions/latest/sdk/task-manager/",
35
35
  "dependencies": {
36
- "unimodules-app-loader": "6.0.9-canary-20251230-fc48ddc"
36
+ "unimodules-app-loader": "6.0.9-canary-20260113-0ce2b9c"
37
37
  },
38
38
  "devDependencies": {
39
- "expo-module-scripts": "5.1.0-canary-20251230-fc48ddc"
39
+ "expo-module-scripts": "5.1.0-canary-20260113-0ce2b9c"
40
40
  },
41
41
  "peerDependencies": {
42
- "expo": "55.0.0-canary-20251230-fc48ddc",
42
+ "expo": "55.0.0-canary-20260113-0ce2b9c",
43
43
  "react-native": "*"
44
44
  }
45
45
  }
@@ -1,13 +0,0 @@
1
- // Copyright 2018-present 650 Industries. All rights reserved.
2
-
3
- #import <ExpoModulesCore/EXEventEmitter.h>
4
- #import <ExpoModulesCore/EXExportedModule.h>
5
- #import <ExpoModulesCore/EXInternalModule.h>
6
- #import <ExpoModulesCore/EXModuleRegistryConsumer.h>
7
- #import <ExpoModulesCore/EXTaskManagerInterface.h>
8
-
9
- @interface EXTaskManager : EXExportedModule <EXInternalModule, EXEventEmitter, EXModuleRegistryConsumer, EXTaskManagerInterface>
10
-
11
- - (instancetype)initWithScopeKey:(NSString *)scopeKey NS_DESIGNATED_INITIALIZER;
12
-
13
- @end
@@ -1,212 +0,0 @@
1
- // Copyright 2018-present 650 Industries. All rights reserved.
2
-
3
- #import <ExpoModulesCore/EXDefines.h>
4
- #import <ExpoModulesCore/EXUtilities.h>
5
- #import <ExpoModulesCore/EXEventEmitterService.h>
6
- #import <ExpoModulesCore/EXConstantsInterface.h>
7
- #import <ExpoModulesCore/EXTaskServiceInterface.h>
8
-
9
- #import <EXTaskManager/EXTaskManager.h>
10
- #import <EXTaskManager/EXTaskService.h>
11
-
12
- NSString * const EXTaskManagerEventName = @"TaskManager.executeTask";
13
-
14
- @interface EXTaskManager ()
15
-
16
- @property (nonatomic, strong) NSString *appId;
17
- @property (nonatomic, strong) NSMutableArray<NSDictionary *> *eventsQueue;
18
- @property (nonatomic, weak) id<EXEventEmitterService> eventEmitter;
19
- @property (nonatomic, weak) id<EXConstantsInterface> constantsService;
20
- @property (nonatomic, weak) id<EXTaskServiceInterface> taskService;
21
-
22
- @end
23
-
24
- @implementation EXTaskManager
25
-
26
- EX_EXPORT_MODULE(ExpoTaskManager);
27
-
28
- + (const NSArray<Protocol *> *)exportedInterfaces
29
- {
30
- return @[@protocol(EXTaskManagerInterface)];
31
- }
32
-
33
- - (instancetype)init
34
- {
35
- return [self initWithScopeKey:@"mainApplication"];
36
- }
37
-
38
- // TODO: Remove when adding bare React Native support
39
- - (instancetype)initWithScopeKey:(NSString *)scopeKey
40
- {
41
- if (self = [super init]) {
42
- _appId = scopeKey;
43
- _eventsQueue = [NSMutableArray new];
44
- }
45
- return self;
46
- }
47
-
48
- - (void)setModuleRegistry:(EXModuleRegistry *)moduleRegistry
49
- {
50
- _eventEmitter = [moduleRegistry getModuleImplementingProtocol:@protocol(EXEventEmitterService)];
51
- _constantsService = [moduleRegistry getModuleImplementingProtocol:@protocol(EXConstantsInterface)];
52
- _taskService = [moduleRegistry getSingletonModuleForName:@"TaskService"];
53
-
54
- // Register task manager in task service.
55
- [_taskService setTaskManager:self forAppId:_appId withUrl:[self _findAppUrl]];
56
- }
57
-
58
- - (NSDictionary *)constantsToExport
59
- {
60
- return @{
61
- @"EVENT_NAME": EXTaskManagerEventName,
62
- };
63
- }
64
-
65
- # pragma mark - EXEventEmitter
66
-
67
- - (NSArray<NSString *> *)supportedEvents
68
- {
69
- return @[EXTaskManagerEventName];
70
- }
71
-
72
- /**
73
- * When `startObserving` is called, it means the app is ready to execute new tasks.
74
- * It also sends all events that were queued before this call.
75
- */
76
- - (void)startObserving
77
- {
78
- if (_eventsQueue && _eventsQueue.count > 0) {
79
- // Emit queued events
80
- for (NSDictionary *eventBody in _eventsQueue) {
81
- [_eventEmitter sendEventWithName:EXTaskManagerEventName body:eventBody];
82
- }
83
- }
84
- _eventsQueue = nil;
85
- }
86
-
87
- - (void)stopObserving {}
88
-
89
- # pragma mark - Exported methods
90
-
91
- EX_EXPORT_METHOD_AS(isAvailableAsync,
92
- isAvailable:(EXPromiseResolveBlock)resolve
93
- rejecter:(EXPromiseRejectBlock)reject)
94
- {
95
- resolve(@(_taskService != nil));
96
- }
97
-
98
- EX_EXPORT_METHOD_AS(notifyTaskFinishedAsync,
99
- notifyTaskFinished:(nonnull NSString *)taskName
100
- withResponse:(nonnull NSDictionary *)response
101
- resolve:(EXPromiseResolveBlock)resolve
102
- reject:(EXPromiseRejectBlock)reject)
103
- {
104
- [_taskService notifyTaskWithName:taskName forAppId:_appId didFinishWithResponse:response];
105
- resolve(nil);
106
- }
107
-
108
- EX_EXPORT_METHOD_AS(isTaskRegisteredAsync,
109
- isTaskRegistered:(nonnull NSString *)taskName
110
- resolve:(EXPromiseResolveBlock)resolve
111
- reject:(EXPromiseRejectBlock)reject)
112
- {
113
- resolve(@([self hasRegisteredTaskWithName:taskName]));
114
- }
115
-
116
- EX_EXPORT_METHOD_AS(getRegisteredTasksAsync,
117
- getRegisteredTasks:(EXPromiseResolveBlock)resolve
118
- reject:(EXPromiseRejectBlock)reject)
119
- {
120
- resolve([_taskService getRegisteredTasksForAppId:_appId]);
121
- }
122
-
123
- EX_EXPORT_METHOD_AS(getTaskOptionsAsync,
124
- getConfigurationForTaskName:(nonnull NSString *)taskName
125
- resolve:(EXPromiseResolveBlock)resolve
126
- reject:(EXPromiseRejectBlock)reject)
127
- {
128
- resolve(EXNullIfNil([_taskService getOptionsForTaskName:taskName forAppId:_appId]));
129
- }
130
-
131
- EX_EXPORT_METHOD_AS(unregisterTaskAsync,
132
- unregisterTaskWithName:(nonnull NSString *)taskName
133
- resolve:(EXPromiseResolveBlock)resolve
134
- reject:(EXPromiseRejectBlock)reject)
135
- {
136
- @try {
137
- [self unregisterTaskWithName:taskName consumerClass:nil];
138
- } @catch (NSException *e) {
139
- return reject(e.name, e.reason, nil);
140
- }
141
- resolve(nil);
142
- }
143
-
144
- EX_EXPORT_METHOD_AS(unregisterAllTasksAsync,
145
- unregisterAllTasks:(EXPromiseResolveBlock)resolve
146
- reject:(EXPromiseRejectBlock)reject)
147
- {
148
- [_taskService unregisterAllTasksForAppId:_appId];
149
- resolve(nil);
150
- }
151
-
152
- # pragma mark - EXTaskManagerInterface
153
-
154
- - (BOOL)hasRegisteredTaskWithName:(nonnull NSString *)taskName
155
- {
156
- return [_taskService hasRegisteredTaskWithName:taskName forAppId:_appId];
157
- }
158
-
159
- - (BOOL)taskWithName:(nonnull NSString *)taskName hasConsumerOfClass:(Class)consumerClass
160
- {
161
- return [_taskService taskWithName:taskName forAppId:_appId hasConsumerOfClass:consumerClass];
162
- }
163
-
164
- - (void)registerTaskWithName:(nonnull NSString *)taskName
165
- consumer:(Class)consumerClass
166
- options:(nonnull NSDictionary *)options
167
- {
168
- NSString *appUrl = [self _findAppUrl];
169
-
170
- [_taskService registerTaskWithName:taskName
171
- appId:_appId
172
- appUrl:appUrl
173
- consumerClass:consumerClass
174
- options:options];
175
- }
176
-
177
- - (void)unregisterTaskWithName:(nonnull NSString *)taskName
178
- consumerClass:(Class)consumerClass
179
- {
180
- [_taskService unregisterTaskWithName:taskName forAppId:_appId consumerClass:consumerClass];
181
- }
182
-
183
- - (BOOL)hasBackgroundModeEnabled:(nonnull NSString *)backgroundMode
184
- {
185
- return [EXTaskService hasBackgroundModeEnabled:backgroundMode];
186
- }
187
-
188
- - (void)executeWithBody:(NSDictionary *)body
189
- {
190
- if (!_eventsQueue) {
191
- // Module's event emitter is already being observed, so we can send events.
192
- [_eventEmitter sendEventWithName:EXTaskManagerEventName body:body];
193
- } else {
194
- // Otherwise add event body to the queue (it will be sent in `startObserving`).
195
- [_eventsQueue addObject:body];
196
- }
197
- }
198
-
199
- - (BOOL)isRunningInHeadlessMode
200
- {
201
- return [[_constantsService constants][@"isHeadless"] boolValue];
202
- }
203
-
204
- # pragma mark - internals
205
-
206
- - (NSString *)_findAppUrl
207
- {
208
- // TODO(@tsapeta): find app url for vanilla RN apps
209
- return [_constantsService constants][@"experienceUrl"];
210
- }
211
-
212
- @end
@@ -1,13 +0,0 @@
1
- // Copyright 2018-present 650 Industries. All rights reserved.
2
-
3
- #import <Foundation/Foundation.h>
4
- #import <UIKit/UIKit.h>
5
- #import <ExpoModulesCore/EXSingletonModule.h>
6
-
7
- NS_ASSUME_NONNULL_BEGIN
8
-
9
- @interface EXTaskManagerAppDelegate : EXSingletonModule <UIApplicationDelegate>
10
-
11
- @end
12
-
13
- NS_ASSUME_NONNULL_END
@@ -1,29 +0,0 @@
1
- // Copyright 2018-present 650 Industries. All rights reserved.
2
-
3
- #import <EXTaskManager/EXTaskManagerAppDelegate.h>
4
- #import <ExpoModulesCore/EXDefines.h>
5
- #import <EXTaskManager/EXTaskService.h>
6
- #import <ExpoModulesCore/EXModuleRegistryProvider.h>
7
-
8
- @implementation EXTaskManagerAppDelegate
9
-
10
- EX_REGISTER_SINGLETON_MODULE(EXTaskManagerAppDelegate)
11
-
12
- - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(nullable NSDictionary *)launchOptions
13
- {
14
- [(EXTaskService *)[EXModuleRegistryProvider getSingletonModuleForClass:EXTaskService.class] applicationDidFinishLaunchingWithOptions:launchOptions];
15
-
16
- return NO;
17
- }
18
-
19
- - (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
20
- {
21
- [(EXTaskService *)[EXModuleRegistryProvider getSingletonModuleForClass:EXTaskService.class] runTasksWithReason:EXTaskLaunchReasonBackgroundFetch userInfo:nil completionHandler:completionHandler];
22
- }
23
-
24
- - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
25
- {
26
- [(EXTaskService *)[EXModuleRegistryProvider getSingletonModuleForClass:EXTaskService.class] runTasksWithReason:EXTaskLaunchReasonRemoteNotification userInfo:userInfo completionHandler:completionHandler];
27
- }
28
-
29
- @end
@@ -1,31 +0,0 @@
1
- require 'json'
2
-
3
- package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
4
-
5
- Pod::Spec.new do |s|
6
- s.name = 'EXTaskManager'
7
- s.version = package['version']
8
- s.summary = package['description']
9
- s.description = package['description']
10
- s.license = package['license']
11
- s.author = package['author']
12
- s.homepage = package['homepage']
13
- s.platforms = {
14
- :ios => '15.1',
15
- :tvos => '15.1'
16
- }
17
- s.source = { git: 'https://github.com/expo/expo-task-manager.git' }
18
- s.static_framework = true
19
-
20
- s.dependency 'ExpoModulesCore'
21
- s.dependency 'UMAppLoader'
22
-
23
- s.resource_bundles = {'ExpoTaskManager_privacy' => ['PrivacyInfo.xcprivacy']}
24
-
25
- if !$ExpoUseSources&.include?(package['name']) && ENV['EXPO_USE_SOURCE'].to_i == 0 && File.exist?("#{s.name}.xcframework") && Gem::Version.new(Pod::VERSION) >= Gem::Version.new('1.10.0')
26
- s.source_files = "#{s.name}/**/*.h"
27
- s.vendored_frameworks = "#{s.name}.xcframework"
28
- else
29
- s.source_files = "#{s.name}/**/*.{h,m}"
30
- end
31
- end
@@ -1 +0,0 @@
1
- 8b736d920f293730c6e21c622e290b98572a20da941a55cc2115d2557f75f1336ddc016e74c2490da6f28db1324ad47a31002f55a1a003129c0e084de554c38b
@@ -1 +0,0 @@
1
- 770d465ed9a7f53291b9ab2d6ec2f863bbf808ea039001791e97da514d54264589d3872c4fed32b6d25ac357bf82a05ccaca9ae88fcf19e547f8d6e948fd7fd7
@@ -1 +0,0 @@
1
- 72baa18ad2269539998eb9225b23ae447265717bd140e336e0d6e1d318a7765e751b6029ded0591c198b5f30164244ded0ca9924588c9683d2304979d5ed3cba
@@ -1 +0,0 @@
1
- 2cd84909f05c62f8571b4a86e486f7cdba70716f01a08aeec6b0ae15d6ea2fbd48993f8ef7ed7175daaf0a1bdc8882c9802d4b21d10f1ccdcf7f84f395dd46f7