react-native-background-geolocation 4.17.6 → 4.18.1

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 (53) hide show
  1. package/android/build.gradle +8 -2
  2. package/android/libs/com/transistorsoft/{tslocationmanager-v21/3.6.3/tslocationmanager-v21-3.6.3.aar → tslocationmanager/3.6.4/tslocationmanager-3.6.4.aar} +0 -0
  3. package/android/libs/com/transistorsoft/tslocationmanager/3.6.4/tslocationmanager-3.6.4.aar.md5 +1 -0
  4. package/android/libs/com/transistorsoft/tslocationmanager/3.6.4/tslocationmanager-3.6.4.aar.sha1 +1 -0
  5. package/android/libs/com/transistorsoft/tslocationmanager/3.6.4/tslocationmanager-3.6.4.aar.sha256 +1 -0
  6. package/android/libs/com/transistorsoft/tslocationmanager/3.6.4/tslocationmanager-3.6.4.aar.sha512 +1 -0
  7. package/android/libs/com/transistorsoft/tslocationmanager/{3.6.3/tslocationmanager-3.6.3.pom → 3.6.4/tslocationmanager-3.6.4.pom} +1 -1
  8. package/android/libs/com/transistorsoft/tslocationmanager/3.6.4/tslocationmanager-3.6.4.pom.md5 +1 -0
  9. package/android/libs/com/transistorsoft/tslocationmanager/3.6.4/tslocationmanager-3.6.4.pom.sha1 +1 -0
  10. package/android/libs/com/transistorsoft/tslocationmanager/3.6.4/tslocationmanager-3.6.4.pom.sha256 +1 -0
  11. package/android/libs/com/transistorsoft/tslocationmanager/3.6.4/tslocationmanager-3.6.4.pom.sha512 +1 -0
  12. package/android/libs/com/transistorsoft/tslocationmanager/maven-metadata.xml +4 -3
  13. package/android/libs/com/transistorsoft/{tslocationmanager/3.6.3/tslocationmanager-3.6.3.aar → tslocationmanager-v21/3.6.4/tslocationmanager-v21-3.6.4.aar} +0 -0
  14. package/android/libs/com/transistorsoft/tslocationmanager-v21/3.6.4/tslocationmanager-v21-3.6.4.aar.md5 +1 -0
  15. package/android/libs/com/transistorsoft/tslocationmanager-v21/3.6.4/tslocationmanager-v21-3.6.4.aar.sha1 +1 -0
  16. package/android/libs/com/transistorsoft/tslocationmanager-v21/3.6.4/tslocationmanager-v21-3.6.4.aar.sha256 +1 -0
  17. package/android/libs/com/transistorsoft/tslocationmanager-v21/3.6.4/tslocationmanager-v21-3.6.4.aar.sha512 +1 -0
  18. package/android/libs/com/transistorsoft/tslocationmanager-v21/{3.6.3/tslocationmanager-v21-3.6.3.pom → 3.6.4/tslocationmanager-v21-3.6.4.pom} +1 -1
  19. package/android/libs/com/transistorsoft/tslocationmanager-v21/3.6.4/tslocationmanager-v21-3.6.4.pom.md5 +1 -0
  20. package/android/libs/com/transistorsoft/tslocationmanager-v21/3.6.4/tslocationmanager-v21-3.6.4.pom.sha1 +1 -0
  21. package/android/libs/com/transistorsoft/tslocationmanager-v21/3.6.4/tslocationmanager-v21-3.6.4.pom.sha256 +1 -0
  22. package/android/libs/com/transistorsoft/tslocationmanager-v21/3.6.4/tslocationmanager-v21-3.6.4.pom.sha512 +1 -0
  23. package/android/libs/com/transistorsoft/tslocationmanager-v21/maven-metadata.xml +4 -3
  24. package/android/proguard-rules.pro +16 -0
  25. package/android/src/main/AndroidManifest.xml +1 -4
  26. package/android/src/main/java/com/transistorsoft/rnbackgroundgeolocation/HeadlessTask.java +40 -85
  27. package/android/src/main/java/com/transistorsoft/rnbackgroundgeolocation/HeadlessTaskManager.java +460 -0
  28. package/android/src/main/java/com/transistorsoft/rnbackgroundgeolocation/RNBackgroundGeolocationModule.java +25 -0
  29. package/expo/plugin/build/androidPlugin.js +0 -8
  30. package/expo/plugin/build/androidPlugin.js.map +1 -1
  31. package/package.json +2 -2
  32. package/src/NativeModule.js +12 -1
  33. package/src/declarations/BackgroundGeolocation.d.ts +65 -14
  34. package/src/declarations/interfaces/Config.d.ts +4 -2
  35. package/src/declarations/interfaces/HeadlessEvent.d.ts +49 -0
  36. package/src/declarations/types.d.ts +3 -0
  37. package/src/index.js +36 -7
  38. package/android/libs/com/transistorsoft/tslocationmanager/3.6.3/tslocationmanager-3.6.3.aar.md5 +0 -1
  39. package/android/libs/com/transistorsoft/tslocationmanager/3.6.3/tslocationmanager-3.6.3.aar.sha1 +0 -1
  40. package/android/libs/com/transistorsoft/tslocationmanager/3.6.3/tslocationmanager-3.6.3.aar.sha256 +0 -1
  41. package/android/libs/com/transistorsoft/tslocationmanager/3.6.3/tslocationmanager-3.6.3.aar.sha512 +0 -1
  42. package/android/libs/com/transistorsoft/tslocationmanager/3.6.3/tslocationmanager-3.6.3.pom.md5 +0 -1
  43. package/android/libs/com/transistorsoft/tslocationmanager/3.6.3/tslocationmanager-3.6.3.pom.sha1 +0 -1
  44. package/android/libs/com/transistorsoft/tslocationmanager/3.6.3/tslocationmanager-3.6.3.pom.sha256 +0 -1
  45. package/android/libs/com/transistorsoft/tslocationmanager/3.6.3/tslocationmanager-3.6.3.pom.sha512 +0 -1
  46. package/android/libs/com/transistorsoft/tslocationmanager-v21/3.6.3/tslocationmanager-v21-3.6.3.aar.md5 +0 -1
  47. package/android/libs/com/transistorsoft/tslocationmanager-v21/3.6.3/tslocationmanager-v21-3.6.3.aar.sha1 +0 -1
  48. package/android/libs/com/transistorsoft/tslocationmanager-v21/3.6.3/tslocationmanager-v21-3.6.3.aar.sha256 +0 -1
  49. package/android/libs/com/transistorsoft/tslocationmanager-v21/3.6.3/tslocationmanager-v21-3.6.3.aar.sha512 +0 -1
  50. package/android/libs/com/transistorsoft/tslocationmanager-v21/3.6.3/tslocationmanager-v21-3.6.3.pom.md5 +0 -1
  51. package/android/libs/com/transistorsoft/tslocationmanager-v21/3.6.3/tslocationmanager-v21-3.6.3.pom.sha1 +0 -1
  52. package/android/libs/com/transistorsoft/tslocationmanager-v21/3.6.3/tslocationmanager-v21-3.6.3.pom.sha256 +0 -1
  53. package/android/libs/com/transistorsoft/tslocationmanager-v21/3.6.3/tslocationmanager-v21-3.6.3.pom.sha512 +0 -1
@@ -0,0 +1,460 @@
1
+ package com.transistorsoft.rnbackgroundgeolocation;
2
+
3
+ import android.content.Context;
4
+ import android.os.Handler;
5
+ import android.os.Looper;
6
+
7
+ import androidx.annotation.NonNull;
8
+ import androidx.annotation.Nullable;
9
+
10
+ import com.facebook.infer.annotation.Assertions;
11
+ import com.facebook.react.ReactApplication;
12
+ import com.facebook.react.ReactInstanceEventListener;
13
+ import com.facebook.react.ReactInstanceManager;
14
+ import com.facebook.react.ReactNativeHost;
15
+ import com.facebook.react.bridge.ReactContext;
16
+ import com.facebook.react.bridge.UiThreadUtil;
17
+ import com.facebook.react.bridge.WritableMap;
18
+ import com.facebook.react.jstasks.HeadlessJsTaskConfig;
19
+ import com.facebook.react.jstasks.HeadlessJsTaskContext;
20
+ import com.facebook.react.jstasks.HeadlessJsTaskEventListener;
21
+ import com.transistorsoft.locationmanager.logger.TSLog;
22
+
23
+ import java.lang.reflect.Method;
24
+
25
+ import java.util.Set;
26
+ import java.util.concurrent.CopyOnWriteArraySet;
27
+ import java.util.concurrent.atomic.AtomicBoolean;
28
+ import java.util.concurrent.atomic.AtomicInteger;
29
+
30
+ /**
31
+ * This is a general singleton for managing invoking RN headless-tasks. This class could be copied and implemented in any plugin.
32
+ *
33
+ * RN headless-tasks have no mechanism for the Javascript to signal completion of their tasks: you can either configure a timeout for
34
+ * your tasks (letting each task timeout) or provide no timeout at all, which will cause a memory leak in RN's HeadlessJsContext.java
35
+ * https://github.com/facebook/react-native/blob/bc0b5ca5df5d2cf12c791b0332ef2fb4e29d6d2d/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskContext.java#L53-L55
36
+ *
37
+ * Without providing a timeout for your headless-tasks, those collections in HeadlessJsContext will continue grow and never be cleared.
38
+ *
39
+ * Because there's only one instance of this class, we have to be mindful that we can possibly receive events rapidly,
40
+ * so we store them in a Queue (#mTaskQueue).
41
+ *
42
+ * We also have to be mindful that it's a heavy operation to do the initial launch the ReactNative Host, so several events
43
+ * might build up in the queue before the Host is finally launched, when we drain the queue (see #drainTaskQueue).
44
+ *
45
+ * For finally sending events to the client, we wrap the RN HeadlessJsTaskConfig with our own TaskConfig class. This class
46
+ * adds our own auto-incremented "taskId" field to maintain a mapping between our taskId and RN's. See #invokeStartTask.
47
+ * This class appends our custom taskId into the the event params sent to Javascript, for the following purpose:
48
+ *
49
+ * ```javascript
50
+ * const BackgroundGeolocationHeadlessTask = async (event) => {
51
+ * console.log('[HeadlessTask] taskId: ', event.taskId); // <-- here's our custom taskId.
52
+ *
53
+ * await doWork(); // <-- perform some arbitrarily long process (eg: http request).
54
+ *
55
+ * BackgroundGeolocation.finishHeadlessTask(event.taskId); // <-- $$$ Here's the money $$$
56
+ * }
57
+ * ```
58
+ *
59
+ * See "Here's the $money" above: We want to signal back to this native HeadlessTask instance , that our JS task is now complete.
60
+ * This is a pretty easy task to do via EventBus -- Just create a new instance of FinishHeadlessTaskEvent(params.taskId);
61
+ *
62
+ * The code then looks up a TaskConfig from mEventQueue using the given event.taskId.
63
+ *
64
+ * All this extra fussing with taking care to finish our RN HeadlessTasks seems to be more important with RN's "new architecture", where before,
65
+ * RN seemed to automatically complete its tasks seemingly when the Javascript function stopped executing. This is why it was always so
66
+ * important to await one's Promises and do all the work before the the last line of the function executed.
67
+ *
68
+ * Now, the Javascript must explicitly call back to the native side to say "I'M DONE" -- BackgroundGeolocation.finishHeadlessTask(taskId)
69
+ */
70
+ public class HeadlessTaskManager implements HeadlessJsTaskEventListener {
71
+ private static final String TAG = "TSLocationManager";
72
+
73
+ private static HeadlessTaskManager sInstance;
74
+ public static HeadlessTaskManager getInstance() {
75
+ if (sInstance == null) {
76
+ sInstance = getInstanceSynchronized();
77
+ }
78
+ return sInstance;
79
+ }
80
+
81
+ private static synchronized HeadlessTaskManager getInstanceSynchronized() {
82
+ if (sInstance == null) sInstance = new HeadlessTaskManager();
83
+ return sInstance;
84
+ }
85
+
86
+ private final Set<Task> mTaskQueue = new CopyOnWriteArraySet<>();
87
+ private final AtomicBoolean mIsReactContextInitialized = new AtomicBoolean(false);
88
+ private final AtomicBoolean mIsInitializingReactContext = new AtomicBoolean(false);
89
+ private final AtomicBoolean mIsHeadlessJsTaskListenerRegistered = new AtomicBoolean(false);
90
+
91
+ /**
92
+ * Start a task. This method handles starting a new React instance if required.
93
+ *
94
+ * Has to be called on the UI thread.
95
+ *
96
+ * @param context Application Context
97
+ * @param task The Task instance
98
+ */
99
+ public void startTask(Context context, Task task) throws AssertionError {
100
+ UiThreadUtil.assertOnUiThread();
101
+
102
+ addTask(task);
103
+
104
+ if (!mIsReactContextInitialized.get()) {
105
+ createReactContextAndScheduleTask(context);
106
+ } else {
107
+ boolean success = invokeStartTask(getReactContext(context), task);
108
+ if (!success) {
109
+ removeTask(task);
110
+ }
111
+ }
112
+ }
113
+
114
+ public void finishTask(Context context, int taskId) throws TaskNotFoundError, ContextError {
115
+ if (!mIsReactContextInitialized.get()) {
116
+ throw new ContextError(getClass().getName() + ".finishTask: ReactContext not initialized");
117
+ }
118
+ ReactContext reactContext = getReactContext(context.getApplicationContext());
119
+ if (reactContext != null) {
120
+ Task task = findTask(taskId);
121
+ if (task != null) {
122
+ HeadlessJsTaskContext headlessJsTaskContext = HeadlessJsTaskContext.getInstance(reactContext);
123
+ if (headlessJsTaskContext.isTaskRunning(task.getReactTaskId())) {
124
+ headlessJsTaskContext.finishTask(task.getReactTaskId());
125
+ }
126
+ } else {
127
+ throw new TaskNotFoundError(taskId);
128
+ }
129
+ } else {
130
+ throw new ContextError(getClass().getName() + ".finishTask ReactContext is null");
131
+ }
132
+ }
133
+
134
+ private boolean invokeStartTask(ReactContext reactContext, final Task task) {
135
+ final HeadlessJsTaskContext headlessJsTaskContext = HeadlessJsTaskContext.getInstance(reactContext);
136
+ if (mIsHeadlessJsTaskListenerRegistered.compareAndSet(false, true)) {
137
+ // Register the RN HeadlessJSTaskEventListener just once.
138
+ // TODO we might use a LifeCycle event-listener here to remove the listener when the app is launched to foreground.
139
+ headlessJsTaskContext.addTaskEventListener(this);
140
+ }
141
+ try {
142
+ return task.invoke(reactContext);
143
+ } catch (Exception e) {
144
+ task.onError(e);
145
+ return false;
146
+ }
147
+ }
148
+
149
+ @Override
150
+ public void onHeadlessJsTaskStart(int taskId) {}
151
+
152
+ // The only purpose of this listener is to clear events from the queue. The RN task is assumed to have had its .stopTask(taskId) method called, which is why this event has fired.
153
+ // WARNING: this listener seems to receive events from ANY OTHER plugin's Headless events.
154
+ @Override
155
+ public void onHeadlessJsTaskFinish(int taskId) {
156
+ Task task = findTaskByReactId(taskId);
157
+ if (task == null) {
158
+ return;
159
+ }
160
+ removeTask(task);
161
+ task.onFinish();
162
+
163
+ TSLog.logger.debug("[onHeadlessJsTaskFinish] taskId: " + taskId);
164
+ }
165
+
166
+ private ReactNativeHost getReactNativeHost(Context context) {
167
+ return ((ReactApplication) context.getApplicationContext()).getReactNativeHost();
168
+ }
169
+
170
+ /**
171
+ * Get the {ReactHost} used by this app. ure and returns null if not.
172
+ */
173
+ private @Nullable Object getReactHost(Context context) {
174
+ context = context.getApplicationContext();
175
+ try {
176
+ Method getReactHost = context.getClass().getMethod("getReactHost");
177
+ return getReactHost.invoke(context);
178
+ } catch (Exception e) {
179
+ return null;
180
+ }
181
+ }
182
+
183
+ private ReactContext getReactContext(Context context) {
184
+ if (isBridglessArchitectureEnabled()) {
185
+ Object reactHost = getReactHost(context);
186
+ Assertions.assertNotNull(reactHost, "getReactHost() is null in New Architecture");
187
+ try {
188
+ Method getCurrentReactContext = reactHost.getClass().getMethod("getCurrentReactContext");
189
+ return (ReactContext) getCurrentReactContext.invoke(reactHost);
190
+ } catch (Exception e) {
191
+ TSLog.logger.error(TSLog.error( "Reflection error getCurrentReactContext: " + e.getMessage()), e);
192
+ }
193
+ }
194
+ final ReactInstanceManager reactInstanceManager = getReactNativeHost(context).getReactInstanceManager();
195
+ return reactInstanceManager.getCurrentReactContext();
196
+ }
197
+
198
+ private void createReactContextAndScheduleTask(Context context) {
199
+ // ReactContext could have already been initialized by another plugin (eg: background-fetch).
200
+ // If we get a non-null ReactContext here, we're good to go!
201
+ ReactContext reactContext = getReactContext(context);
202
+ if (reactContext != null && !mIsInitializingReactContext.get()) {
203
+ mIsReactContextInitialized.set(true);
204
+ drainTaskQueue(reactContext);
205
+ return;
206
+ }
207
+ if (mIsInitializingReactContext.compareAndSet(false, true)) {
208
+ TSLog.logger.debug( "[createReactContextAndScheduleTask] initialize ReactContext");
209
+ final Object reactHost = getReactHost(context);
210
+ if (isBridglessArchitectureEnabled()) { // NEW arch
211
+ ReactInstanceEventListener callback = new ReactInstanceEventListener() {
212
+ @Override
213
+ public void onReactContextInitialized(@NonNull ReactContext reactContext) {
214
+ mIsReactContextInitialized.set(true);
215
+ drainTaskQueue(reactContext);
216
+ try {
217
+ Method removeReactInstanceEventListener = reactHost.getClass().getMethod("removeReactInstanceEventListener", ReactInstanceEventListener.class);
218
+ removeReactInstanceEventListener.invoke(reactHost, this);
219
+ } catch (Exception e) {
220
+ TSLog.logger.error(TSLog.error("HeadlessTask reflection error removeReactInstanceEventListener: ") + e);
221
+ }
222
+ }
223
+ };
224
+ try {
225
+ Method addReactInstanceEventListener = reactHost.getClass().getMethod("addReactInstanceEventListener", ReactInstanceEventListener.class);
226
+ addReactInstanceEventListener.invoke(reactHost, callback);
227
+ Method startReactHost = reactHost.getClass().getMethod("start");
228
+ startReactHost.invoke(reactHost);
229
+ } catch (Exception e) {
230
+ TSLog.logger.error(TSLog.error("HeadlessTask reflection error ReactHost start: " + e.getMessage()), e);
231
+ }
232
+ } else { // OLD arch
233
+ final ReactInstanceManager reactInstanceManager = getReactNativeHost(context).getReactInstanceManager();
234
+ reactInstanceManager.addReactInstanceEventListener(new ReactInstanceEventListener() {
235
+ @Override
236
+ public void onReactContextInitialized(@NonNull ReactContext reactContext) {
237
+ mIsReactContextInitialized.set(true);
238
+ drainTaskQueue(reactContext);
239
+ reactInstanceManager.removeReactInstanceEventListener(this);
240
+ }
241
+ });
242
+ reactInstanceManager.createReactContextInBackground();
243
+ }
244
+ }
245
+ }
246
+
247
+ /**
248
+ * Return true if this app is running with RN's bridgeless architecture.
249
+ * Cheers to @mikehardy for this idea.
250
+ * @return
251
+ */
252
+ private boolean isBridglessArchitectureEnabled() {
253
+ try {
254
+ Class<?> entryPoint = Class.forName("com.facebook.react.defaults.DefaultNewArchitectureEntryPoint");
255
+ Method bridgelessEnabled = entryPoint.getMethod("getBridgelessEnabled");
256
+ Object result = bridgelessEnabled.invoke(null);
257
+ return (result == Boolean.TRUE);
258
+ } catch (Exception e) {
259
+ return false;
260
+ }
261
+ }
262
+
263
+ /**
264
+ * Invokes HeadlessEvents queued while waiting for the ReactContext to initialize.
265
+ * @param reactContext
266
+ */
267
+ private void drainTaskQueue(final ReactContext reactContext) {
268
+ new Handler(Looper.getMainLooper()).postDelayed(() -> {
269
+ mTaskQueue.forEach((Task task) -> {
270
+ boolean success = invokeStartTask(reactContext, task);
271
+ if (!success) {
272
+ removeTask(task);
273
+ }
274
+ });
275
+ }, 250);
276
+ }
277
+
278
+ // Find a task in the queue.
279
+ public Task findTask(int taskId) {
280
+ Task found = null;
281
+ // Locate the TaskConfig instance by our local taskId.
282
+ synchronized (mTaskQueue) {
283
+ for (Task task : mTaskQueue) {
284
+ if (task.getId() == taskId) {
285
+ found = task;
286
+ break;
287
+ }
288
+ }
289
+ }
290
+ return found;
291
+ }
292
+
293
+ private Task findTaskByReactId(int reactTaskId) {
294
+ Task found = null;
295
+ // Locate the TaskConfig instance by our local taskId.
296
+ synchronized (mTaskQueue) {
297
+ for (Task config : mTaskQueue) {
298
+ if (config.getReactTaskId() == reactTaskId) {
299
+ found = config;
300
+ break;
301
+ }
302
+ }
303
+ }
304
+ return found;
305
+ }
306
+ // Add a task to queue.
307
+ private void addTask(Task config) {
308
+ // push this HeadlessEvent onto the taskQueue, to be drained once the React context is finished initializing,
309
+ // or executed immediately if Context exists currently.
310
+ synchronized (mTaskQueue) {
311
+ mTaskQueue.add(config);
312
+ }
313
+ }
314
+
315
+ // Remove TaskConfig from queue.
316
+ private void removeTask(Task task) {
317
+ synchronized (mTaskQueue) {
318
+ mTaskQueue.remove(task);
319
+ }
320
+ }
321
+
322
+ // Any tasks in the queue?
323
+ private boolean hasTasks() {
324
+ synchronized (mTaskQueue) {
325
+ return !mTaskQueue.isEmpty();
326
+ }
327
+ }
328
+
329
+ /**
330
+ * Wrapper for a client event. Inserts our custom taskId into the RN ClientEvent params.
331
+ */
332
+ public static class Task {
333
+ private static final AtomicInteger sLastTaskId = new AtomicInteger(0);
334
+ synchronized static int getNextTaskId() {
335
+ return sLastTaskId.incrementAndGet();
336
+ }
337
+
338
+ private final int mId;
339
+ private final String mTaskName;
340
+ private int mReactTaskId;
341
+ private final OnInvokeCallback mOnInvokeCallback;
342
+ private final OnFinishCallback mOnFinishCallback;
343
+ private final OnErrorCallback mOnErrorCallback;
344
+ private final int mTimeout;
345
+ private final WritableMap mParams;
346
+
347
+ Task(Builder builder) {
348
+ mTaskName = builder.name;
349
+ mId = getNextTaskId();
350
+ mOnInvokeCallback = builder.onInvokeCallback;
351
+ mOnFinishCallback = builder.onFinishCallback;
352
+ mOnErrorCallback = builder.onErrorCallback;
353
+ mTimeout = builder.timeout;
354
+ mParams = builder.params;
355
+ // append our custom headless taskId.
356
+ mParams.putInt("_transistorHeadlessTaskId", mId);
357
+ }
358
+
359
+
360
+ boolean invoke(ReactContext reactContext) throws IllegalStateException {
361
+ HeadlessJsTaskContext headlessJsTaskContext = HeadlessJsTaskContext.getInstance(reactContext);
362
+ // Provide the RN taskId to our private TaskConfig instance, mapping the RN taskId to our TaskConfig's internal taskId.
363
+
364
+ mReactTaskId = headlessJsTaskContext.startTask(buildTaskConfig());
365
+ if (mOnInvokeCallback != null) {
366
+ mOnInvokeCallback.onInvoke(reactContext, this);
367
+ }
368
+ return true;
369
+ }
370
+
371
+ public int getId() {
372
+ return mId;
373
+ }
374
+
375
+ private int getReactTaskId() {
376
+ return mReactTaskId;
377
+ }
378
+
379
+ private HeadlessJsTaskConfig buildTaskConfig() {
380
+ return new HeadlessJsTaskConfig(mTaskName, mParams, mTimeout);
381
+ }
382
+
383
+ void onFinish() {
384
+ if (mOnFinishCallback != null) {
385
+ mOnFinishCallback.onFinish(mId);
386
+ }
387
+ }
388
+
389
+ void onError(Exception e) {
390
+ if (mOnErrorCallback != null) {
391
+ mOnErrorCallback.onError(this, e);
392
+ }
393
+ }
394
+
395
+ public String toString() {
396
+ return "[HeadlessTaskManager.Task name: " + mTaskName + " " + mParams + "]";
397
+ }
398
+
399
+ public static class Builder {
400
+ private static final int DEFAULT_TIMEOUT = 60000;
401
+
402
+ private String name;
403
+ private OnInvokeCallback onInvokeCallback;
404
+ private OnFinishCallback onFinishCallback;
405
+ private OnErrorCallback onErrorCallback;
406
+ private WritableMap params;
407
+ private int timeout = DEFAULT_TIMEOUT;
408
+
409
+ public Builder setName(String name) {
410
+ this.name = name;
411
+ return this;
412
+ }
413
+ public Builder setOnInvokeCallback(OnInvokeCallback callback) {
414
+ this.onInvokeCallback = callback;
415
+ return this;
416
+ }
417
+ public Builder setOnFinishCallback(OnFinishCallback callback) {
418
+ this.onFinishCallback = callback;
419
+ return this;
420
+ }
421
+ public Builder setOnErrorCallback(OnErrorCallback callback) {
422
+ this.onErrorCallback = callback;
423
+ return this;
424
+ }
425
+ public Builder setParams(WritableMap params) {
426
+ this.params = params;
427
+ return this;
428
+ }
429
+ public Builder setTimeout(int timeout) {
430
+ this.timeout = timeout;
431
+ return this;
432
+ }
433
+ public Task build() {
434
+ return new Task(this);
435
+ }
436
+ }
437
+ }
438
+
439
+ public static class TaskNotFoundError extends Exception {
440
+ public TaskNotFoundError(int taskId) {
441
+ super(HeadlessTaskManager.class.getName() + " failed to find task: " + taskId);
442
+ }
443
+ }
444
+
445
+ public static class ContextError extends Exception {
446
+ public ContextError(String message) {
447
+ super(message);
448
+ }
449
+ }
450
+
451
+ public interface OnInvokeCallback {
452
+ void onInvoke(ReactContext reactContext, Task task);
453
+ }
454
+ public interface OnFinishCallback {
455
+ void onFinish(int taskId);
456
+ }
457
+ public interface OnErrorCallback {
458
+ void onError(Task task, Exception e);
459
+ }
460
+ }
@@ -23,10 +23,13 @@ import com.facebook.react.bridge.WritableNativeArray;
23
23
  import com.facebook.react.bridge.WritableNativeMap;
24
24
  import com.facebook.react.modules.core.RCTNativeAppEventEmitter;
25
25
 
26
+ import org.greenrobot.eventbus.EventBus;
26
27
  import org.json.JSONArray;
27
28
  import org.json.JSONException;
28
29
  import org.json.JSONObject;
29
30
 
31
+ import com.transistorsoft.locationmanager.event.FinishHeadlessTaskEvent;
32
+ import com.transistorsoft.locationmanager.event.HeadlessEvent;
30
33
  import com.transistorsoft.xms.g.common.ExtensionApiAvailability;
31
34
 
32
35
  import com.transistorsoft.locationmanager.adapter.BackgroundGeolocation;
@@ -822,6 +825,28 @@ public class RNBackgroundGeolocationModule extends ReactContextBaseJavaModule im
822
825
  success.invoke(taskId);
823
826
  }
824
827
 
828
+ /**
829
+ * Called by user's registered HeadlessTask when they call BackgroundGeolocation.finishHeadlessTask(event.taskId)
830
+ * @param taskId
831
+ * @param success
832
+ * @param failure
833
+ */
834
+ @ReactMethod
835
+ public void finishHeadlessTask(int taskId, Callback success, Callback failure) {
836
+ EventBus eventBus = EventBus.getDefault();
837
+ if (!eventBus.hasSubscriberForEvent(HeadlessEvent.class)) {
838
+ // This shouldn't happen. In order for this method to even be called, it MUST have been executed from within the consumer's
839
+ // registered HeadlessTask. In order for that headless-task to have even be called, HeadlessEvent MUST have been registered with EventBus.
840
+ String message = "finishHeadlessTask failed to find an EventBus subscriber for HeadlessEvent";
841
+ TSLog.error(TSLog.warn(message));
842
+ failure.invoke(message);
843
+ return;
844
+ }
845
+ FinishHeadlessTaskEvent event = new FinishHeadlessTaskEvent(getReactApplicationContext(), taskId);
846
+ eventBus.post(event);
847
+ success.invoke();
848
+ }
849
+
825
850
  @ReactMethod
826
851
  public void getTransistorToken(String orgname, String username, String url, final Callback success, final Callback failure) {
827
852
 
@@ -83,14 +83,6 @@ const applyAppGradle = (buildGradle) => {
83
83
  offset: 1,
84
84
  comment: "//",
85
85
  }).contents;
86
- buildGradle = (0, generateCode_1.mergeContents)({
87
- tag: `${MODULE_NAME}-proguard`,
88
- src: buildGradle,
89
- newSrc: `\t proguardFiles "\${background_geolocation.projectDir}/proguard-rules.pro"`,
90
- anchor: /\"proguard-rules.pro\"/,
91
- offset: 1,
92
- comment: "//",
93
- }).contents;
94
86
  return buildGradle;
95
87
  };
96
88
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"androidPlugin.js","sourceRoot":"","sources":["../src/androidPlugin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"androidPlugin.js","sourceRoot":"","sources":["../src/androidPlugin.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-background-geolocation",
3
- "version": "4.17.6",
3
+ "version": "4.18.1",
4
4
  "description": "The most sophisticated cross-platform background location-tracking & geofencing module with battery-conscious motion-detection intelligence",
5
5
  "scripts": {
6
6
  "build": "yarn run build:expo",
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "homepage": "https://www.transistorsoft.com/shop/products/react-native-background-geolocation",
32
32
  "dependencies": {
33
- "react-native-background-fetch": "~4.2.5"
33
+ "react-native-background-fetch": "~4.2.6"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@expo/config-plugins": "^4.1.0",
@@ -309,7 +309,6 @@ export default class NativeModule {
309
309
  });
310
310
  }
311
311
 
312
- // TODO Rename native methods #finish -> #stopBackgroundTask
313
312
  static stopBackgroundTask(taskId) {
314
313
  return new Promise((resolve, reject) => {
315
314
  if (!taskId) {
@@ -322,6 +321,18 @@ export default class NativeModule {
322
321
  });
323
322
  }
324
323
 
324
+ static finishHeadlessTask(taskId) {
325
+ return new Promise((resolve, reject) => {
326
+ if (!taskId) {
327
+ reject('INVALID_TASK_ID: ' + taskId);
328
+ return;
329
+ }
330
+ let success = () => { resolve() }
331
+ let failure = (error) => { reject(error) }
332
+ RNBackgroundGeolocation.finishHeadlessTask(taskId, success, failure);
333
+ });
334
+ }
335
+
325
336
  /**
326
337
  * Geolocation Methods
327
338
  */