@capgo/capacitor-uploader 8.3.7 → 8.3.9
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.
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package ee.forgr.capacitor.uploader;
|
|
2
2
|
|
|
3
|
+
import android.app.Application;
|
|
3
4
|
import android.app.NotificationChannel;
|
|
4
5
|
import android.app.NotificationManager;
|
|
5
6
|
import android.content.Context;
|
|
@@ -14,14 +15,18 @@ import com.getcapacitor.Plugin;
|
|
|
14
15
|
import com.getcapacitor.PluginCall;
|
|
15
16
|
import com.getcapacitor.PluginMethod;
|
|
16
17
|
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
18
|
+
import java.lang.ref.WeakReference;
|
|
17
19
|
import java.util.ArrayList;
|
|
18
20
|
import java.util.HashMap;
|
|
19
21
|
import java.util.Iterator;
|
|
20
22
|
import java.util.Map;
|
|
23
|
+
import java.util.Set;
|
|
21
24
|
import java.util.UUID;
|
|
25
|
+
import java.util.concurrent.ConcurrentHashMap;
|
|
26
|
+
import kotlin.jvm.functions.Function1;
|
|
22
27
|
import net.gotev.uploadservice.data.UploadInfo;
|
|
23
28
|
import net.gotev.uploadservice.network.ServerResponse;
|
|
24
|
-
import net.gotev.uploadservice.observer.request.
|
|
29
|
+
import net.gotev.uploadservice.observer.request.GlobalRequestObserver;
|
|
25
30
|
import net.gotev.uploadservice.observer.request.RequestObserverDelegate;
|
|
26
31
|
import org.json.JSONException;
|
|
27
32
|
import org.json.JSONObject;
|
|
@@ -33,7 +38,7 @@ public class UploaderPlugin extends Plugin {
|
|
|
33
38
|
|
|
34
39
|
private static final String CAPACITOR_CONTENT_PATH_PREFIX = "/_capacitor_content_";
|
|
35
40
|
|
|
36
|
-
private final String pluginVersion = "8.3.
|
|
41
|
+
private final String pluginVersion = "8.3.9";
|
|
37
42
|
|
|
38
43
|
private Uploader implementation;
|
|
39
44
|
|
|
@@ -45,44 +50,60 @@ public class UploaderPlugin extends Plugin {
|
|
|
45
50
|
private static final String PENDING_EVENTS_KEY = "pending_events";
|
|
46
51
|
private static final String TAG = "UploaderPlugin";
|
|
47
52
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
// Process-scoped: one observer for the process, filtered to plugin-owned uploads.
|
|
54
|
+
private static final Set<String> OWNED_UPLOAD_IDS = ConcurrentHashMap.newKeySet();
|
|
55
|
+
private static final Object PENDING_EVENTS_LOCK = new Object();
|
|
56
|
+
private static final Object OBSERVER_LOCK = new Object();
|
|
57
|
+
private static GlobalRequestObserver processObserver;
|
|
58
|
+
private static Uploader processUploader;
|
|
59
|
+
private static WeakReference<UploaderPlugin> activePlugin = new WeakReference<>(null);
|
|
60
|
+
// Cleared in handleOnDestroy so emitEvent no-ops while Activity/Bridge is tearing down.
|
|
61
|
+
private static volatile boolean pluginAttached = false;
|
|
62
|
+
|
|
63
|
+
private static void saveEventToPrefs(Context context, String eventId, JSObject event) {
|
|
64
|
+
synchronized (PENDING_EVENTS_LOCK) {
|
|
65
|
+
SharedPreferences prefs = context.getApplicationContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
|
66
|
+
String existingJson = prefs.getString(PENDING_EVENTS_KEY, "{}");
|
|
67
|
+
try {
|
|
68
|
+
JSONObject pendingEvents = new JSONObject(existingJson);
|
|
69
|
+
pendingEvents.put(eventId, new JSONObject(event.toString()));
|
|
70
|
+
prefs.edit().putString(PENDING_EVENTS_KEY, pendingEvents.toString()).apply();
|
|
71
|
+
} catch (JSONException e) {
|
|
72
|
+
Log.e(TAG, "Failed to persist upload event", e);
|
|
73
|
+
}
|
|
57
74
|
}
|
|
58
75
|
}
|
|
59
76
|
|
|
60
|
-
private void removeEventFromPrefs(String eventId) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
77
|
+
private static void removeEventFromPrefs(Context context, String eventId) {
|
|
78
|
+
synchronized (PENDING_EVENTS_LOCK) {
|
|
79
|
+
SharedPreferences prefs = context.getApplicationContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
|
80
|
+
String existingJson = prefs.getString(PENDING_EVENTS_KEY, "{}");
|
|
81
|
+
try {
|
|
82
|
+
JSONObject pendingEvents = new JSONObject(existingJson);
|
|
83
|
+
pendingEvents.remove(eventId);
|
|
84
|
+
prefs.edit().putString(PENDING_EVENTS_KEY, pendingEvents.toString()).apply();
|
|
85
|
+
} catch (JSONException e) {
|
|
86
|
+
Log.e(TAG, "Failed to remove upload event from prefs", e);
|
|
87
|
+
}
|
|
69
88
|
}
|
|
70
89
|
}
|
|
71
90
|
|
|
72
91
|
private void replayPendingEvents() {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
92
|
+
synchronized (PENDING_EVENTS_LOCK) {
|
|
93
|
+
SharedPreferences prefs = getContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
|
94
|
+
String existingJson = prefs.getString(PENDING_EVENTS_KEY, "{}");
|
|
95
|
+
try {
|
|
96
|
+
JSONObject pendingEvents = new JSONObject(existingJson);
|
|
97
|
+
Iterator<String> keys = pendingEvents.keys();
|
|
98
|
+
while (keys.hasNext()) {
|
|
99
|
+
String eventId = keys.next();
|
|
100
|
+
JSONObject eventJson = pendingEvents.getJSONObject(eventId);
|
|
101
|
+
JSObject event = JSObject.fromJSONObject(eventJson);
|
|
102
|
+
notifyListeners("events", event, true);
|
|
103
|
+
}
|
|
104
|
+
} catch (JSONException e) {
|
|
105
|
+
Log.e(TAG, "Failed to replay pending upload events", e);
|
|
83
106
|
}
|
|
84
|
-
} catch (JSONException e) {
|
|
85
|
-
Log.e(TAG, "Failed to replay pending upload events", e);
|
|
86
107
|
}
|
|
87
108
|
}
|
|
88
109
|
|
|
@@ -97,76 +118,135 @@ public class UploaderPlugin extends Plugin {
|
|
|
97
118
|
}
|
|
98
119
|
}
|
|
99
120
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
// Create a request observer for all uploads
|
|
105
|
-
RequestObserver observer = new RequestObserver(
|
|
106
|
-
getContext().getApplicationContext(),
|
|
107
|
-
getActivity(),
|
|
108
|
-
new RequestObserverDelegate() {
|
|
109
|
-
@Override
|
|
110
|
-
public void onProgress(Context context, UploadInfo uploadInfo) {
|
|
111
|
-
JSObject event = new JSObject();
|
|
112
|
-
event.put("name", "uploading");
|
|
113
|
-
JSObject payload = new JSObject();
|
|
114
|
-
payload.put("percent", uploadInfo.getProgressPercent());
|
|
115
|
-
event.put("payload", payload);
|
|
116
|
-
event.put("id", uploadInfo.getUploadId());
|
|
117
|
-
notifyListeners("events", event);
|
|
118
|
-
}
|
|
121
|
+
private static UploaderPlugin currentPlugin() {
|
|
122
|
+
return activePlugin.get();
|
|
123
|
+
}
|
|
119
124
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
125
|
+
private static void emitEvent(String name, JSObject event, boolean retainUntilConsumed) {
|
|
126
|
+
if (!pluginAttached) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
UploaderPlugin plugin = currentPlugin();
|
|
130
|
+
if (plugin == null || plugin.getBridge() == null) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (retainUntilConsumed) {
|
|
134
|
+
plugin.notifyListeners(name, event, true);
|
|
135
|
+
} else {
|
|
136
|
+
plugin.notifyListeners(name, event);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
134
139
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
JSObject payload = new JSObject();
|
|
141
|
-
payload.put("error", exception.getMessage());
|
|
142
|
-
event.put("payload", payload);
|
|
143
|
-
event.put("id", uploadInfo.getUploadId());
|
|
144
|
-
String eventId = UUID.randomUUID().toString();
|
|
145
|
-
event.put("eventId", eventId);
|
|
146
|
-
saveEventToPrefs(eventId, event);
|
|
147
|
-
notifyListeners("events", event);
|
|
148
|
-
}
|
|
140
|
+
private static void clearTempBody(String uploadId) {
|
|
141
|
+
if (processUploader != null) {
|
|
142
|
+
processUploader.clearTempMultipartBody(uploadId);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
149
145
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
event.put("name", "finished");
|
|
155
|
-
event.put("id", uploadInfo.getUploadId());
|
|
156
|
-
notifyListeners("events", event);
|
|
157
|
-
}
|
|
146
|
+
private static void releaseUpload(String uploadId) {
|
|
147
|
+
clearTempBody(uploadId);
|
|
148
|
+
OWNED_UPLOAD_IDS.remove(uploadId);
|
|
149
|
+
}
|
|
158
150
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
151
|
+
private static void ensureProcessObserver(Application application) {
|
|
152
|
+
synchronized (OBSERVER_LOCK) {
|
|
153
|
+
if (processObserver != null) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (processUploader == null) {
|
|
157
|
+
processUploader = new Uploader(application);
|
|
163
158
|
}
|
|
164
|
-
|
|
159
|
+
// Keep observer for process lifetime. Weak plugin ref avoids retaining Bridge/WebView
|
|
160
|
+
// after Activity destroy; register once to avoid duplicate receivers.
|
|
161
|
+
processObserver = new GlobalRequestObserver(
|
|
162
|
+
application,
|
|
163
|
+
new RequestObserverDelegate() {
|
|
164
|
+
@Override
|
|
165
|
+
public void onProgress(Context context, UploadInfo uploadInfo) {
|
|
166
|
+
JSObject event = new JSObject();
|
|
167
|
+
event.put("name", "uploading");
|
|
168
|
+
JSObject payload = new JSObject();
|
|
169
|
+
payload.put("percent", uploadInfo.getProgressPercent());
|
|
170
|
+
event.put("payload", payload);
|
|
171
|
+
event.put("id", uploadInfo.getUploadId());
|
|
172
|
+
emitEvent("events", event, false);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@Override
|
|
176
|
+
public void onSuccess(Context context, UploadInfo uploadInfo, ServerResponse serverResponse) {
|
|
177
|
+
clearTempBody(uploadInfo.getUploadId());
|
|
178
|
+
JSObject event = new JSObject();
|
|
179
|
+
event.put("name", "completed");
|
|
180
|
+
JSObject payload = new JSObject();
|
|
181
|
+
payload.put("statusCode", serverResponse.getCode());
|
|
182
|
+
event.put("payload", payload);
|
|
183
|
+
event.put("id", uploadInfo.getUploadId());
|
|
184
|
+
String eventId = UUID.randomUUID().toString();
|
|
185
|
+
event.put("eventId", eventId);
|
|
186
|
+
saveEventToPrefs(context, eventId, event);
|
|
187
|
+
emitEvent("events", event, true);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@Override
|
|
191
|
+
public void onError(Context context, UploadInfo uploadInfo, Throwable exception) {
|
|
192
|
+
clearTempBody(uploadInfo.getUploadId());
|
|
193
|
+
JSObject event = new JSObject();
|
|
194
|
+
event.put("name", "failed");
|
|
195
|
+
JSObject payload = new JSObject();
|
|
196
|
+
payload.put("error", exception.getMessage());
|
|
197
|
+
event.put("payload", payload);
|
|
198
|
+
event.put("id", uploadInfo.getUploadId());
|
|
199
|
+
String eventId = UUID.randomUUID().toString();
|
|
200
|
+
event.put("eventId", eventId);
|
|
201
|
+
saveEventToPrefs(context, eventId, event);
|
|
202
|
+
emitEvent("events", event, true);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
@Override
|
|
206
|
+
public void onCompleted(Context context, UploadInfo uploadInfo) {
|
|
207
|
+
releaseUpload(uploadInfo.getUploadId());
|
|
208
|
+
JSObject event = new JSObject();
|
|
209
|
+
event.put("name", "finished");
|
|
210
|
+
event.put("id", uploadInfo.getUploadId());
|
|
211
|
+
emitEvent("events", event, false);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
@Override
|
|
215
|
+
public void onCompletedWhileNotObserving() {
|
|
216
|
+
if (!pluginAttached) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
UploaderPlugin plugin = currentPlugin();
|
|
220
|
+
if (plugin != null && plugin.getBridge() != null) {
|
|
221
|
+
plugin.replayPendingEvents();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
(Function1<UploadInfo, Boolean>) (uploadInfo) -> OWNED_UPLOAD_IDS.contains(uploadInfo.getUploadId())
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
165
229
|
|
|
166
|
-
|
|
230
|
+
@Override
|
|
231
|
+
public void load() {
|
|
232
|
+
createNotificationChannel();
|
|
233
|
+
activePlugin = new WeakReference<>(this);
|
|
234
|
+
pluginAttached = true;
|
|
235
|
+
ensureProcessObserver(getActivity().getApplication());
|
|
236
|
+
implementation = processUploader;
|
|
167
237
|
replayPendingEvents();
|
|
168
238
|
}
|
|
169
239
|
|
|
240
|
+
@Override
|
|
241
|
+
protected void handleOnDestroy() {
|
|
242
|
+
// Detach the plugin sink only — keep processObserver registered for background uploads.
|
|
243
|
+
if (activePlugin.get() == this) {
|
|
244
|
+
pluginAttached = false;
|
|
245
|
+
activePlugin.clear();
|
|
246
|
+
}
|
|
247
|
+
super.handleOnDestroy();
|
|
248
|
+
}
|
|
249
|
+
|
|
170
250
|
public static String getMimeType(String url) {
|
|
171
251
|
String type = null;
|
|
172
252
|
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
|
|
@@ -250,6 +330,7 @@ public class UploaderPlugin extends Plugin {
|
|
|
250
330
|
maxRetries,
|
|
251
331
|
uploadType
|
|
252
332
|
);
|
|
333
|
+
OWNED_UPLOAD_IDS.add(id);
|
|
253
334
|
JSObject result = new JSObject();
|
|
254
335
|
result.put("id", id);
|
|
255
336
|
call.resolve(result);
|
|
@@ -290,6 +371,7 @@ public class UploaderPlugin extends Plugin {
|
|
|
290
371
|
filesToUpload.add(new Uploader.UploadFile(localFilePath, fieldName, mimeType));
|
|
291
372
|
|
|
292
373
|
String id = implementation.startUpload(filesToUpload, serverUrl, headers, fields, "POST", "File Upload", 2, "multipart");
|
|
374
|
+
OWNED_UPLOAD_IDS.add(id);
|
|
293
375
|
JSObject result = new JSObject();
|
|
294
376
|
result.put("id", id);
|
|
295
377
|
call.resolve(result);
|
|
@@ -306,6 +388,7 @@ public class UploaderPlugin extends Plugin {
|
|
|
306
388
|
return;
|
|
307
389
|
}
|
|
308
390
|
try {
|
|
391
|
+
OWNED_UPLOAD_IDS.remove(id);
|
|
309
392
|
implementation.removeUpload(id);
|
|
310
393
|
call.resolve();
|
|
311
394
|
} catch (Exception e) {
|
|
@@ -369,7 +452,7 @@ public class UploaderPlugin extends Plugin {
|
|
|
369
452
|
call.reject("Missing required parameter: eventId");
|
|
370
453
|
return;
|
|
371
454
|
}
|
|
372
|
-
removeEventFromPrefs(eventId);
|
|
455
|
+
removeEventFromPrefs(getContext(), eventId);
|
|
373
456
|
call.resolve();
|
|
374
457
|
}
|
|
375
458
|
|
|
@@ -3,7 +3,7 @@ import Capacitor
|
|
|
3
3
|
|
|
4
4
|
@objc(UploaderPlugin)
|
|
5
5
|
public class UploaderPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
6
|
-
private let pluginVersion: String = "8.3.
|
|
6
|
+
private let pluginVersion: String = "8.3.9"
|
|
7
7
|
public let identifier = "UploaderPlugin"
|
|
8
8
|
public let jsName = "Uploader"
|
|
9
9
|
public let pluginMethods: [CAPPluginMethod] = [
|