@ammarahmed/react-native-background-fetch 4.2.2 → 4.2.3
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/android/src/main/java/com/transistorsoft/rnbackgroundfetch/HeadlessTask.java +98 -61
- package/android/src/main/java/com/transistorsoft/tsbackgroundfetch/BGTask.java +18 -4
- package/android/src/main/java/com/transistorsoft/tsbackgroundfetch/BackgroundFetch.java +0 -0
- package/android/src/main/java/com/transistorsoft/tsbackgroundfetch/BackgroundFetchConfig.java +0 -0
- package/android/src/main/java/com/transistorsoft/tsbackgroundfetch/BootReceiver.java +0 -0
- package/android/src/main/java/com/transistorsoft/tsbackgroundfetch/FetchAlarmReceiver.java +0 -0
- package/android/src/main/java/com/transistorsoft/tsbackgroundfetch/FetchJobService.java +0 -0
- package/android/src/main/java/com/transistorsoft/tsbackgroundfetch/LifecycleManager.java +0 -0
- package/package.json +1 -1
|
@@ -4,7 +4,12 @@ import android.content.Context;
|
|
|
4
4
|
import android.os.Handler;
|
|
5
5
|
import android.util.Log;
|
|
6
6
|
|
|
7
|
+
import androidx.annotation.NonNull;
|
|
8
|
+
import androidx.annotation.Nullable;
|
|
9
|
+
|
|
10
|
+
import com.facebook.infer.annotation.Assertions;
|
|
7
11
|
import com.facebook.react.ReactApplication;
|
|
12
|
+
import com.facebook.react.ReactInstanceEventListener;
|
|
8
13
|
import com.facebook.react.ReactInstanceManager;
|
|
9
14
|
import com.facebook.react.ReactNativeHost;
|
|
10
15
|
import com.facebook.react.bridge.ReactContext;
|
|
@@ -13,50 +18,34 @@ import com.facebook.react.bridge.WritableMap;
|
|
|
13
18
|
import com.facebook.react.bridge.WritableNativeMap;
|
|
14
19
|
import com.facebook.react.jstasks.HeadlessJsTaskConfig;
|
|
15
20
|
import com.facebook.react.jstasks.HeadlessJsTaskContext;
|
|
16
|
-
|
|
21
|
+
|
|
17
22
|
import com.transistorsoft.tsbackgroundfetch.BGTask;
|
|
18
23
|
import com.transistorsoft.tsbackgroundfetch.BackgroundFetch;
|
|
19
24
|
import com.facebook.react.common.LifecycleState;
|
|
20
25
|
|
|
26
|
+
import java.lang.reflect.Method;
|
|
27
|
+
|
|
21
28
|
/**
|
|
22
29
|
* Created by chris on 2018-01-17.
|
|
23
30
|
*/
|
|
24
31
|
|
|
25
|
-
public class HeadlessTask
|
|
26
|
-
private static String HEADLESS_TASK_NAME = "BackgroundFetch";
|
|
27
|
-
private static Handler mHandler = new Handler();
|
|
28
|
-
private ReactNativeHost mReactNativeHost;
|
|
29
|
-
private HeadlessJsTaskContext mActiveTaskContext;
|
|
32
|
+
public class HeadlessTask {
|
|
33
|
+
private static final String HEADLESS_TASK_NAME = "BackgroundFetch";
|
|
34
|
+
private static final Handler mHandler = new Handler();
|
|
30
35
|
|
|
36
|
+
private final BGTask mBGTask;
|
|
31
37
|
public HeadlessTask(Context context, BGTask task) {
|
|
32
|
-
|
|
33
|
-
ReactApplication reactApplication = ((ReactApplication) context.getApplicationContext());
|
|
34
|
-
mReactNativeHost = reactApplication.getReactNativeHost();
|
|
35
|
-
} catch (AssertionError | ClassCastException e) {
|
|
36
|
-
Log.e(BackgroundFetch.TAG, "Failed to fetch ReactApplication. Task ignored.");
|
|
37
|
-
return; // <-- Do nothing. Just return
|
|
38
|
-
}
|
|
38
|
+
mBGTask = task;
|
|
39
39
|
WritableMap clientEvent = new WritableNativeMap();
|
|
40
40
|
clientEvent.putString("taskId", task.getTaskId());
|
|
41
41
|
clientEvent.putBoolean("timeout", task.getTimedOut());
|
|
42
42
|
HeadlessJsTaskConfig config = new HeadlessJsTaskConfig(HEADLESS_TASK_NAME, clientEvent, 30000);
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (mActiveTaskContext != null) {
|
|
48
|
-
mActiveTaskContext.removeTaskEventListener(this);
|
|
43
|
+
try {
|
|
44
|
+
startTask(config, context);
|
|
45
|
+
} catch (AssertionError e) {
|
|
46
|
+
Log.d(BackgroundFetch.TAG, "[HeadlessTask] Failed invoke HeadlessTask: " + e.getMessage());
|
|
49
47
|
}
|
|
50
48
|
}
|
|
51
|
-
@Override
|
|
52
|
-
public void onHeadlessJsTaskStart(int taskId) {
|
|
53
|
-
Log.d(BackgroundFetch.TAG,"onHeadlessJsTaskStart: " + taskId);
|
|
54
|
-
}
|
|
55
|
-
@Override
|
|
56
|
-
public void onHeadlessJsTaskFinish(int taskId) {
|
|
57
|
-
Log.d(BackgroundFetch.TAG, "onHeadlessJsTaskFinish: " + taskId);
|
|
58
|
-
mActiveTaskContext.removeTaskEventListener(this);
|
|
59
|
-
}
|
|
60
49
|
|
|
61
50
|
/**
|
|
62
51
|
* Start a task. This method handles starting a new React instance if required.
|
|
@@ -65,27 +54,13 @@ public class HeadlessTask implements HeadlessJsTaskEventListener {
|
|
|
65
54
|
*
|
|
66
55
|
* @param taskConfig describes what task to start and the parameters to pass to it
|
|
67
56
|
*/
|
|
68
|
-
protected void startTask(final HeadlessJsTaskConfig taskConfig) {
|
|
57
|
+
protected void startTask(final HeadlessJsTaskConfig taskConfig, Context context) {
|
|
69
58
|
UiThreadUtil.assertOnUiThread();
|
|
70
|
-
|
|
71
|
-
ReactContext reactContext =
|
|
59
|
+
|
|
60
|
+
ReactContext reactContext = getReactContext(context);
|
|
61
|
+
|
|
72
62
|
if (reactContext == null) {
|
|
73
|
-
|
|
74
|
-
@Override
|
|
75
|
-
public void onReactContextInitialized(final ReactContext reactContext) {
|
|
76
|
-
// Hack to fix unknown problem executing asynchronous BackgroundTask when ReactContext is created *first time*. Fixed by adding short delay before #invokeStartTask
|
|
77
|
-
mHandler.postDelayed(new Runnable() {
|
|
78
|
-
@Override
|
|
79
|
-
public void run() {
|
|
80
|
-
invokeStartTask(reactContext, taskConfig);
|
|
81
|
-
}
|
|
82
|
-
}, 500);
|
|
83
|
-
reactInstanceManager.removeReactInstanceEventListener(this);
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
if (!reactInstanceManager.hasStartedCreatingInitialContext()) {
|
|
87
|
-
reactInstanceManager.createReactContextInBackground();
|
|
88
|
-
}
|
|
63
|
+
createReactContextAndScheduleTask(taskConfig, context);
|
|
89
64
|
} else {
|
|
90
65
|
invokeStartTask(reactContext, taskConfig);
|
|
91
66
|
}
|
|
@@ -96,24 +71,86 @@ public class HeadlessTask implements HeadlessJsTaskEventListener {
|
|
|
96
71
|
return;
|
|
97
72
|
}
|
|
98
73
|
final HeadlessJsTaskContext headlessJsTaskContext = HeadlessJsTaskContext.getInstance(reactContext);
|
|
99
|
-
|
|
100
|
-
|
|
74
|
+
|
|
75
|
+
UiThreadUtil.runOnUiThread(() -> {
|
|
76
|
+
try {
|
|
77
|
+
final int taskId = headlessJsTaskContext.startTask(taskConfig);
|
|
78
|
+
Log.d(BackgroundFetch.TAG, "[HeadlessTask] start taskId: " + taskId);
|
|
79
|
+
// Add a BGTask.finish(taskId) listener. This is executed when the user runs BackgroundFetch.finish(taskId).
|
|
80
|
+
// We use this to finish the RN headless task.
|
|
81
|
+
mBGTask.setCompletionHandler(() -> {
|
|
82
|
+
Log.d(BackgroundFetch.TAG, "[HeadlessTask] end taskId: " + taskId);
|
|
83
|
+
if (headlessJsTaskContext.isTaskRunning(taskId)) {
|
|
84
|
+
headlessJsTaskContext.finishTask(taskId);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
} catch (IllegalStateException exception) {
|
|
88
|
+
Log.e(BackgroundFetch.TAG, "[HeadlessTask] task attempted to run in the foreground. Task ignored.");
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private ReactNativeHost getReactNativeHost(Context context) {
|
|
94
|
+
return ((ReactApplication) context.getApplicationContext()).getReactNativeHost();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Get the {ReactHost} used by this app. ure and returns null if not.
|
|
99
|
+
*/
|
|
100
|
+
private @Nullable Object getReactHost(Context context) {
|
|
101
|
+
context = context.getApplicationContext();
|
|
101
102
|
try {
|
|
102
|
-
|
|
103
|
+
Method getReactHost = context.getClass().getMethod("getReactHost");
|
|
104
|
+
return getReactHost.invoke(context);
|
|
105
|
+
// Original non-reflection return:
|
|
106
|
+
//return ((ReactApplication) context.getApplicationContext()).getReactHost();
|
|
107
|
+
} catch (Exception e) {
|
|
108
|
+
Log.d(BackgroundFetch.TAG, "[HeadlessTask] Reflection error ReactHost: " + e);
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private ReactContext getReactContext(Context context) {
|
|
114
|
+
|
|
115
|
+
Object reactHost = getReactHost(context);
|
|
116
|
+
Assertions.assertNotNull(reactHost, "getReactHost() is null in New Architecture");
|
|
117
|
+
try {
|
|
118
|
+
Method getCurrentReactContext = reactHost.getClass().getMethod("getCurrentReactContext");
|
|
119
|
+
return (ReactContext) getCurrentReactContext.invoke(reactHost);
|
|
120
|
+
} catch (Exception e) {
|
|
121
|
+
Log.e(BackgroundFetch.TAG, "[HeadlessTask] Reflection error getCurrentReactContext: " + e);
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private void createReactContextAndScheduleTask(final HeadlessJsTaskConfig taskConfig, Context context) {
|
|
127
|
+
Log.d(BackgroundFetch.TAG, "[HeadlessTask] initializing ReactContext");
|
|
128
|
+
|
|
129
|
+
final Object reactHost = getReactHost(context);
|
|
130
|
+
|
|
131
|
+
ReactInstanceEventListener callback = new ReactInstanceEventListener() {
|
|
103
132
|
@Override
|
|
104
|
-
public void
|
|
133
|
+
public void onReactContextInitialized(@NonNull ReactContext reactContext) {
|
|
134
|
+
mHandler.postDelayed(() -> invokeStartTask(reactContext, taskConfig), 500);
|
|
105
135
|
try {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
136
|
+
Method removeReactInstanceEventListener = reactHost.getClass().getMethod("removeReactInstanceEventListener", ReactInstanceEventListener.class);
|
|
137
|
+
removeReactInstanceEventListener.invoke(reactHost, this);
|
|
138
|
+
} catch (Exception e) {
|
|
139
|
+
Log.e(BackgroundFetch.TAG, "[HeadlessTask] reflection error removeReactInstanceEventListener" + e);
|
|
110
140
|
}
|
|
111
141
|
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
Method addReactInstanceEventListener = reactHost.getClass().getMethod("addReactInstanceEventListener", ReactInstanceEventListener.class);
|
|
146
|
+
addReactInstanceEventListener.invoke(reactHost, callback);
|
|
147
|
+
Method startReactHost = reactHost.getClass().getMethod("start");
|
|
148
|
+
startReactHost.invoke(reactHost);
|
|
149
|
+
} catch (Exception e) {
|
|
150
|
+
Log.e(BackgroundFetch.TAG, "[HeadlessTask] reflection error addReactInstanceEventListener: " + e);
|
|
151
|
+
}
|
|
117
152
|
|
|
118
153
|
}
|
|
119
|
-
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
}
|
|
@@ -65,6 +65,7 @@ public class BGTask {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
private final List<FetchJobService.CompletionHandler> mCompletionHandlers = new ArrayList<>();
|
|
68
69
|
private FetchJobService.CompletionHandler mCompletionHandler;
|
|
69
70
|
private String mTaskId;
|
|
70
71
|
private int mJobId;
|
|
@@ -73,7 +74,8 @@ public class BGTask {
|
|
|
73
74
|
|
|
74
75
|
BGTask(final Context context, String taskId, FetchJobService.CompletionHandler handler, int jobId) {
|
|
75
76
|
mTaskId = taskId;
|
|
76
|
-
mCompletionHandler = handler;
|
|
77
|
+
//mCompletionHandler = handler;
|
|
78
|
+
mCompletionHandlers.add(handler);
|
|
77
79
|
mJobId = jobId;
|
|
78
80
|
|
|
79
81
|
mTimeoutTask = new Runnable() {
|
|
@@ -96,18 +98,30 @@ public class BGTask {
|
|
|
96
98
|
return ((mTaskId != null) && mTaskId.equalsIgnoreCase(taskId));
|
|
97
99
|
}
|
|
98
100
|
|
|
99
|
-
void setCompletionHandler(FetchJobService.CompletionHandler handler) {
|
|
100
|
-
|
|
101
|
+
public void setCompletionHandler(FetchJobService.CompletionHandler handler) {
|
|
102
|
+
synchronized (mCompletionHandlers) {
|
|
103
|
+
mCompletionHandlers.add(handler);
|
|
104
|
+
}
|
|
105
|
+
//mCompletionHandler = handler;
|
|
101
106
|
}
|
|
102
107
|
|
|
103
108
|
void finish() {
|
|
109
|
+
synchronized (mCompletionHandlers) {
|
|
110
|
+
for (FetchJobService.CompletionHandler handler : mCompletionHandlers) {
|
|
111
|
+
handler.finish();
|
|
112
|
+
}
|
|
113
|
+
mCompletionHandlers.clear();
|
|
114
|
+
}
|
|
115
|
+
/*
|
|
104
116
|
if (mCompletionHandler != null) {
|
|
105
117
|
mCompletionHandler.finish();
|
|
106
118
|
}
|
|
119
|
+
*/
|
|
107
120
|
if (mTimeoutTask != null) {
|
|
108
121
|
BackgroundFetch.getUiHandler().removeCallbacks(mTimeoutTask);
|
|
109
122
|
}
|
|
110
|
-
|
|
123
|
+
|
|
124
|
+
//mCompletionHandler = null;
|
|
111
125
|
removeTask(mTaskId);
|
|
112
126
|
}
|
|
113
127
|
|
|
File without changes
|
package/android/src/main/java/com/transistorsoft/tsbackgroundfetch/BackgroundFetchConfig.java
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|