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.
- package/CHANGELOG.md +4 -0
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/taskManager/TaskManagerInternalModule.java +1 -1
- package/android/src/main/java/expo/modules/taskManager/TaskManagerUtils.java +49 -51
- package/android/src/main/java/expo/modules/taskManager/TaskService.java +1 -5
- package/android/src/main/java/expo/modules/taskManager/Utils.java +10 -1
- package/expo-module.config.json +5 -1
- package/ios/EXTaskManager/EXTask.m +1 -1
- package/ios/EXTaskManager/EXTaskExecutionRequest.m +1 -1
- package/ios/EXTaskManager/EXTaskService.h +5 -4
- package/ios/EXTaskManager/EXTaskService.m +16 -5
- package/ios/ExpoTaskManager.podspec +31 -0
- package/ios/TaskManagerAppDelegateSubscriber.swift +16 -0
- package/ios/TaskManagerModule.swift +111 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/maven-metadata.xml +4 -4
- package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/maven-metadata.xml.md5 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/maven-metadata.xml.sha1 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/maven-metadata.xml.sha256 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/maven-metadata.xml.sha512 +1 -1
- package/package.json +4 -4
- package/ios/EXTaskManager/EXTaskManager.h +0 -13
- package/ios/EXTaskManager/EXTaskManager.m +0 -212
- package/ios/EXTaskManager/EXTaskManagerAppDelegate.h +0 -13
- package/ios/EXTaskManager/EXTaskManagerAppDelegate.m +0 -29
- package/ios/EXTaskManager.podspec +0 -31
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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._
|
package/android/build.gradle
CHANGED
|
@@ -4,13 +4,13 @@ plugins {
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
group = 'host.exp.exponent'
|
|
7
|
-
version = '14.0.10-canary-
|
|
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-
|
|
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.
|
|
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
|
|
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
|
-
|
|
40
|
+
// Leave buffer before Android's job limit to avoid edge cases.
|
|
41
|
+
private static final int JOB_LIMIT_BUFFER = 10;
|
|
44
42
|
|
|
45
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
163
|
-
|
|
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
|
|
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
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|
package/expo-module.config.json
CHANGED
|
@@ -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-
|
|
12
|
+
"version": "14.0.10-canary-20260113-0ce2b9c",
|
|
9
13
|
"repository": "local-maven-repo"
|
|
10
14
|
}
|
|
11
15
|
}
|
|
@@ -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 <
|
|
6
|
-
#import <
|
|
4
|
+
#import <ExpoTaskManager/EXTask.h>
|
|
5
|
+
#import <ExpoTaskManager/EXTaskExecutionRequest.h>
|
|
7
6
|
|
|
8
|
-
@interface EXTaskService :
|
|
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 <
|
|
7
|
-
#import <
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
61b4fd02dc0c66b951e7f16846a59b7b
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
75df1a72794b0b5bc43bb7a358f41a4935432f37
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
7068346a53195adaac8d873f1021cf442adf6d141c1ad2d38c729f61cdecb3da
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
81667fa2aa27c43b920cd63dfc7aee343eee898533c83873af8f21d8d214fa0b89b8e2ce3a22da3d495c05a743adf6965d798105f22d02f715dcb0286426e1dd
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
583e1fabefe72215de826c0511469a6f
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3ab23fc4ac57db1bcc463997c855364c31170dc7
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
75cd598721f9d8e0131765e3ea738d6d2359439b581a861ca53329185a26ff19
|
|
@@ -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-
|
|
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-
|
|
37
|
-
"url": "expo.modules.taskmanager-14.0.10-canary-
|
|
38
|
-
"size":
|
|
39
|
-
"sha512": "
|
|
40
|
-
"sha256": "
|
|
41
|
-
"sha1": "
|
|
42
|
-
"md5": "
|
|
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-
|
|
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-
|
|
80
|
-
"url": "expo.modules.taskmanager-14.0.10-canary-
|
|
81
|
-
"size":
|
|
82
|
-
"sha512": "
|
|
83
|
-
"sha256": "
|
|
84
|
-
"sha1": "
|
|
85
|
-
"md5": "
|
|
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-
|
|
100
|
-
"url": "expo.modules.taskmanager-14.0.10-canary-
|
|
101
|
-
"size":
|
|
102
|
-
"sha512": "
|
|
103
|
-
"sha256": "
|
|
104
|
-
"sha1": "
|
|
105
|
-
"md5": "
|
|
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
|
+
8a13431f5382336226f73a7409e0bc39
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
6bd606c847d2f48d7cceaa539883d308aa66d650
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
8c8965bfe6e9ec42d5d38ed82e39f88f6fea4bc7fc19b896f63936f779744d1a
|
|
@@ -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-
|
|
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-
|
|
43
|
+
<version>6.0.9-canary-20260113-0ce2b9c</version>
|
|
44
44
|
<scope>runtime</scope>
|
|
45
45
|
</dependency>
|
|
46
46
|
</dependencies>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
d6ad995b064334626fefb101b97de059
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
4b3526ef554c249f24300e27f9e901eb6cc63a10
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2fa29e17cd6f2424ff3d934e5bb57142887cbd547740a587cf3fe44ad4715734
|
|
@@ -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-
|
|
7
|
-
<release>14.0.10-canary-
|
|
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-
|
|
9
|
+
<version>14.0.10-canary-20260113-0ce2b9c</version>
|
|
10
10
|
</versions>
|
|
11
|
-
<lastUpdated>
|
|
11
|
+
<lastUpdated>20260113181513</lastUpdated>
|
|
12
12
|
</versioning>
|
|
13
13
|
</metadata>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
4da6051a2ac2718934ade22a11e0f114
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
4f58ac44f2bfdb6290b394961ce275eb83bd916c
|
package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/maven-metadata.xml.sha256
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
659ad79520f83ae393bffa8483490e91c1a9f6a003e60405ff933397a3ff9ecc
|
package/local-maven-repo/host/exp/exponent/expo.modules.taskmanager/maven-metadata.xml.sha512
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
b37841158633b640104f2627d8896d3902a7810d8b8dfe18709e8dc6483d4c2ade516361c213828ff3e0dbf5eadb3f1035dc1b7052f1735b96161b8180ecbdfd
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-task-manager",
|
|
3
|
-
"version": "14.0.10-canary-
|
|
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-
|
|
36
|
+
"unimodules-app-loader": "6.0.9-canary-20260113-0ce2b9c"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"expo-module-scripts": "5.1.0-canary-
|
|
39
|
+
"expo-module-scripts": "5.1.0-canary-20260113-0ce2b9c"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"expo": "55.0.0-canary-
|
|
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
|
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
c56a4cba148e230ef3f14439d3afd694
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
7ef651ce45f55ed6ccbc443d5c1b47dec40f640c
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
835897e4e38b3abc2084054d950204a7a812dee7c650c6665f7ed3e10ada565e
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
8b736d920f293730c6e21c622e290b98572a20da941a55cc2115d2557f75f1336ddc016e74c2490da6f28db1324ad47a31002f55a1a003129c0e084de554c38b
|
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
62c71d9ca2dfa51f3ba48bf73a8e1990
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
cfc7126eab7b60913ee982353ece061123565fdb
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
bb3e8c76dc8b2136da793dd000c07cacdd86b4bc211dace3bed921bab4cbbee3
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
770d465ed9a7f53291b9ab2d6ec2f863bbf808ea039001791e97da514d54264589d3872c4fed32b6d25ac357bf82a05ccaca9ae88fcf19e547f8d6e948fd7fd7
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
aa847a919e994d54efcff1a5888f0918
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
3467b8e5837c16b7c77943c255fc0c56458c4079
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
f4835c32a66fb69c26090a833245e1a5d8468b3eb99fa27fd227f854e3bf2465
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
72baa18ad2269539998eb9225b23ae447265717bd140e336e0d6e1d318a7765e751b6029ded0591c198b5f30164244ded0ca9924588c9683d2304979d5ed3cba
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
9fc848e2005ad7329292bb9135426e32
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
7aae8a78412c8fab2a770f7d50298e30828c5055
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
058714e7d364451c295b6472691d4ea4af93f2370d511502bcea2039ffaeea8a
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
2cd84909f05c62f8571b4a86e486f7cdba70716f01a08aeec6b0ae15d6ea2fbd48993f8ef7ed7175daaf0a1bdc8882c9802d4b21d10f1ccdcf7f84f395dd46f7
|