@capgo/capacitor-updater 6.7.5 → 6.7.7-alpha.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.
- package/android/src/main/AndroidManifest.xml +5 -1
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdater.java +10 -15
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +1 -1
- package/android/src/main/java/ee/forgr/capacitor_updater/DownloadService.java +142 -159
- package/ios/Plugin/CapacitorUpdaterPlugin.swift +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
2
|
+
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
|
3
|
+
|
|
2
4
|
<application>
|
|
3
|
-
<service
|
|
5
|
+
<service
|
|
6
|
+
android:name="ee.forgr.capacitor_updater.DownloadService"
|
|
7
|
+
android:exported="false" />
|
|
4
8
|
</application>
|
|
5
9
|
</manifest>
|
|
@@ -482,11 +482,7 @@ public class CapacitorUpdater {
|
|
|
482
482
|
intent.putExtra(DownloadService.IS_MANIFEST, true);
|
|
483
483
|
}
|
|
484
484
|
|
|
485
|
-
|
|
486
|
-
this.activity.startForegroundService(intent);
|
|
487
|
-
} else {
|
|
488
|
-
this.activity.startService(intent);
|
|
489
|
-
}
|
|
485
|
+
this.activity.startService(intent);
|
|
490
486
|
}
|
|
491
487
|
|
|
492
488
|
private void downloadFile(
|
|
@@ -502,28 +498,27 @@ public class CapacitorUpdater {
|
|
|
502
498
|
target.createNewFile();
|
|
503
499
|
|
|
504
500
|
final long totalLength = connection.getContentLength();
|
|
505
|
-
|
|
506
|
-
final byte[] buffer = new byte[bufferSize];
|
|
507
|
-
int length;
|
|
508
|
-
|
|
509
|
-
int bytesRead = bufferSize;
|
|
501
|
+
int bytesRead = 0;
|
|
510
502
|
int percent = 0;
|
|
511
503
|
this.notifyDownload(id, 10);
|
|
504
|
+
|
|
512
505
|
try (
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
506
|
+
InputStream is = connection.getInputStream();
|
|
507
|
+
DataInputStream dis = new DataInputStream(is);
|
|
508
|
+
FileOutputStream fos = new FileOutputStream(target)
|
|
516
509
|
) {
|
|
510
|
+
byte[] buffer = new byte[8192];
|
|
511
|
+
int length;
|
|
517
512
|
while ((length = dis.read(buffer)) > 0) {
|
|
518
513
|
fos.write(buffer, 0, length);
|
|
514
|
+
bytesRead += length;
|
|
519
515
|
final int newPercent = (int) ((bytesRead / (float) totalLength) * 100);
|
|
520
516
|
if (totalLength > 1 && newPercent != percent) {
|
|
521
517
|
percent = newPercent;
|
|
522
518
|
this.notifyDownload(id, this.calcTotalPercent(percent, 10, 70));
|
|
523
519
|
}
|
|
524
|
-
bytesRead += length;
|
|
525
520
|
}
|
|
526
|
-
if (bytesRead ==
|
|
521
|
+
if (bytesRead == 0) {
|
|
527
522
|
throw new IOException("Failed to download: No data read from URL");
|
|
528
523
|
}
|
|
529
524
|
} catch (OutOfMemoryError e) {
|
|
@@ -57,7 +57,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
57
57
|
private static final String channelUrlDefault =
|
|
58
58
|
"https://plugin.capgo.app/channel_self";
|
|
59
59
|
|
|
60
|
-
private final String PLUGIN_VERSION = "6.7.
|
|
60
|
+
private final String PLUGIN_VERSION = "6.7.7-alpha.1";
|
|
61
61
|
private static final String DELAY_CONDITION_PREFERENCES = "";
|
|
62
62
|
|
|
63
63
|
private SharedPreferences.Editor editor;
|
|
@@ -6,13 +6,8 @@
|
|
|
6
6
|
package ee.forgr.capacitor_updater;
|
|
7
7
|
|
|
8
8
|
import android.app.IntentService;
|
|
9
|
-
import android.app.Notification;
|
|
10
|
-
import android.app.NotificationChannel;
|
|
11
|
-
import android.app.NotificationManager;
|
|
12
9
|
import android.content.Intent;
|
|
13
|
-
import android.os.
|
|
14
|
-
import android.os.Handler;
|
|
15
|
-
import android.os.Looper;
|
|
10
|
+
import android.os.PowerManager;
|
|
16
11
|
import android.util.Log;
|
|
17
12
|
import java.io.*;
|
|
18
13
|
import java.io.FileInputStream;
|
|
@@ -23,7 +18,6 @@ import java.security.MessageDigest;
|
|
|
23
18
|
import java.util.ArrayList;
|
|
24
19
|
import java.util.Arrays;
|
|
25
20
|
import java.util.List;
|
|
26
|
-
import java.util.concurrent.CompletableFuture;
|
|
27
21
|
import java.util.concurrent.ExecutorService;
|
|
28
22
|
import java.util.concurrent.Executors;
|
|
29
23
|
import java.util.concurrent.Future;
|
|
@@ -56,15 +50,11 @@ public class DownloadService extends IntentService {
|
|
|
56
50
|
public static final String IS_MANIFEST = "is_manifest";
|
|
57
51
|
public static final String MANIFEST = "manifest";
|
|
58
52
|
private static final String UPDATE_FILE = "update.dat";
|
|
59
|
-
private static final int NOTIFICATION_ID = 1;
|
|
60
|
-
private static final long NOTIFICATION_DELAY_MS = 4000; // 4 seconds
|
|
61
53
|
|
|
62
54
|
private final OkHttpClient client = new OkHttpClient.Builder()
|
|
63
55
|
.protocols(Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1))
|
|
64
56
|
.build();
|
|
65
|
-
private
|
|
66
|
-
private Runnable notificationRunnable;
|
|
67
|
-
private boolean isNotificationShown = false;
|
|
57
|
+
private PowerManager.WakeLock wakeLock;
|
|
68
58
|
|
|
69
59
|
public DownloadService() {
|
|
70
60
|
super("Background DownloadService");
|
|
@@ -73,40 +63,20 @@ public class DownloadService extends IntentService {
|
|
|
73
63
|
@Override
|
|
74
64
|
public void onCreate() {
|
|
75
65
|
super.onCreate();
|
|
76
|
-
|
|
77
|
-
|
|
66
|
+
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
|
|
67
|
+
wakeLock = powerManager.newWakeLock(
|
|
68
|
+
PowerManager.PARTIAL_WAKE_LOCK,
|
|
69
|
+
"CapacitorUpdater::DownloadWakeLock"
|
|
70
|
+
);
|
|
78
71
|
}
|
|
79
72
|
|
|
80
73
|
@Override
|
|
81
74
|
public void onDestroy() {
|
|
82
75
|
super.onDestroy();
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
private void startForeground() {
|
|
87
|
-
isNotificationShown = true;
|
|
88
|
-
String channelId = createNotificationChannel();
|
|
89
|
-
Notification.Builder builder = new Notification.Builder(this, channelId)
|
|
90
|
-
.setContentTitle("Downloading Update")
|
|
91
|
-
.setContentText("Download in progress")
|
|
92
|
-
.setSmallIcon(android.R.drawable.stat_sys_download)
|
|
93
|
-
.setOngoing(true);
|
|
94
|
-
|
|
95
|
-
startForeground(NOTIFICATION_ID, builder.build());
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
private String createNotificationChannel() {
|
|
99
|
-
String channelId = "capacitor_updater_channel";
|
|
100
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
101
|
-
NotificationChannel channel = new NotificationChannel(
|
|
102
|
-
channelId,
|
|
103
|
-
"Capacitor Updater Downloads",
|
|
104
|
-
NotificationManager.IMPORTANCE_LOW
|
|
105
|
-
);
|
|
106
|
-
NotificationManager manager = getSystemService(NotificationManager.class);
|
|
107
|
-
manager.createNotificationChannel(channel);
|
|
76
|
+
Log.w(TAG + " DownloadService", "DownloadService killed/destroyed");
|
|
77
|
+
if (wakeLock != null && wakeLock.isHeld()) {
|
|
78
|
+
wakeLock.release();
|
|
108
79
|
}
|
|
109
|
-
return channelId;
|
|
110
80
|
}
|
|
111
81
|
|
|
112
82
|
private int calcTotalPercent(long downloadedBytes, long contentLength) {
|
|
@@ -121,50 +91,58 @@ public class DownloadService extends IntentService {
|
|
|
121
91
|
|
|
122
92
|
@Override
|
|
123
93
|
protected void onHandleIntent(Intent intent) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
94
|
+
try {
|
|
95
|
+
wakeLock.acquire(10 * 60 * 1000L);
|
|
96
|
+
assert intent != null;
|
|
97
|
+
String url = intent.getStringExtra(URL);
|
|
98
|
+
String id = intent.getStringExtra(ID);
|
|
99
|
+
String documentsDir = intent.getStringExtra(DOCDIR);
|
|
100
|
+
String dest = intent.getStringExtra(FILEDEST);
|
|
101
|
+
String version = intent.getStringExtra(VERSION);
|
|
102
|
+
String sessionKey = intent.getStringExtra(SESSIONKEY);
|
|
103
|
+
String checksum = intent.getStringExtra(CHECKSUM);
|
|
104
|
+
boolean isManifest = intent.getBooleanExtra(IS_MANIFEST, false);
|
|
105
|
+
|
|
106
|
+
Log.d(
|
|
107
|
+
TAG + " DownloadService",
|
|
108
|
+
"onHandleIntent isManifest: " + isManifest
|
|
109
|
+
);
|
|
110
|
+
if (isManifest) {
|
|
111
|
+
JSONArray manifest = DataManager.getInstance().getAndClearManifest();
|
|
112
|
+
if (manifest != null) {
|
|
113
|
+
handleManifestDownload(
|
|
114
|
+
id,
|
|
115
|
+
documentsDir,
|
|
116
|
+
dest,
|
|
117
|
+
version,
|
|
118
|
+
sessionKey,
|
|
119
|
+
manifest.toString()
|
|
120
|
+
);
|
|
121
|
+
} else {
|
|
122
|
+
Log.e(TAG + " DownloadService", "Manifest is null");
|
|
123
|
+
publishResults(
|
|
124
|
+
"",
|
|
125
|
+
id,
|
|
126
|
+
version,
|
|
127
|
+
checksum,
|
|
128
|
+
sessionKey,
|
|
129
|
+
"Manifest is null",
|
|
130
|
+
false
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
handleSingleFileDownload(
|
|
135
|
+
url,
|
|
139
136
|
id,
|
|
140
137
|
documentsDir,
|
|
141
138
|
dest,
|
|
142
139
|
version,
|
|
143
140
|
sessionKey,
|
|
144
|
-
|
|
145
|
-
);
|
|
146
|
-
} else {
|
|
147
|
-
Log.e(TAG + " DownloadService", "Manifest is null");
|
|
148
|
-
publishResults(
|
|
149
|
-
"",
|
|
150
|
-
id,
|
|
151
|
-
version,
|
|
152
|
-
checksum,
|
|
153
|
-
sessionKey,
|
|
154
|
-
"Manifest is null",
|
|
155
|
-
false
|
|
141
|
+
checksum
|
|
156
142
|
);
|
|
157
143
|
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
url,
|
|
161
|
-
id,
|
|
162
|
-
documentsDir,
|
|
163
|
-
dest,
|
|
164
|
-
version,
|
|
165
|
-
sessionKey,
|
|
166
|
-
checksum
|
|
167
|
-
);
|
|
144
|
+
} finally {
|
|
145
|
+
wakeLock.release();
|
|
168
146
|
}
|
|
169
147
|
}
|
|
170
148
|
|
|
@@ -299,7 +277,6 @@ public class DownloadService extends IntentService {
|
|
|
299
277
|
Log.e(TAG + " DownloadService", "Error in handleManifestDownload", e);
|
|
300
278
|
publishResults("", id, version, "", sessionKey, e.getMessage(), true);
|
|
301
279
|
}
|
|
302
|
-
stopForegroundIfNeeded();
|
|
303
280
|
}
|
|
304
281
|
|
|
305
282
|
private void handleSingleFileDownload(
|
|
@@ -317,89 +294,107 @@ public class DownloadService extends IntentService {
|
|
|
317
294
|
File tempFile = new File(documentsDir, "temp" + ".tmp"); // Temp file, where the downloaded data is stored
|
|
318
295
|
try {
|
|
319
296
|
URL u = new URL(url);
|
|
320
|
-
HttpURLConnection httpConn =
|
|
297
|
+
HttpURLConnection httpConn = null;
|
|
298
|
+
try {
|
|
299
|
+
httpConn = (HttpURLConnection) u.openConnection();
|
|
321
300
|
|
|
322
|
-
|
|
323
|
-
|
|
301
|
+
// Reading progress file (if exist)
|
|
302
|
+
long downloadedBytes = 0;
|
|
324
303
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
304
|
+
if (infoFile.exists() && tempFile.exists()) {
|
|
305
|
+
try (
|
|
306
|
+
BufferedReader reader = new BufferedReader(new FileReader(infoFile))
|
|
307
|
+
) {
|
|
308
|
+
String updateVersion = reader.readLine();
|
|
309
|
+
if (!updateVersion.equals(version)) {
|
|
310
|
+
clearDownloadData(documentsDir);
|
|
311
|
+
downloadedBytes = 0;
|
|
312
|
+
} else {
|
|
313
|
+
downloadedBytes = tempFile.length();
|
|
314
|
+
}
|
|
335
315
|
}
|
|
316
|
+
} else {
|
|
317
|
+
clearDownloadData(documentsDir);
|
|
318
|
+
downloadedBytes = 0;
|
|
336
319
|
}
|
|
337
|
-
} else {
|
|
338
|
-
clearDownloadData(documentsDir);
|
|
339
|
-
downloadedBytes = 0;
|
|
340
|
-
}
|
|
341
320
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
321
|
+
if (downloadedBytes > 0) {
|
|
322
|
+
httpConn.setRequestProperty(
|
|
323
|
+
"Range",
|
|
324
|
+
"bytes=" + downloadedBytes + "-"
|
|
325
|
+
);
|
|
326
|
+
}
|
|
345
327
|
|
|
346
|
-
|
|
328
|
+
int responseCode = httpConn.getResponseCode();
|
|
347
329
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
330
|
+
if (
|
|
331
|
+
responseCode == HttpURLConnection.HTTP_OK ||
|
|
332
|
+
responseCode == HttpURLConnection.HTTP_PARTIAL
|
|
333
|
+
) {
|
|
334
|
+
String contentType = httpConn.getContentType();
|
|
335
|
+
long contentLength = httpConn.getContentLength() + downloadedBytes;
|
|
354
336
|
|
|
355
|
-
InputStream inputStream = httpConn.getInputStream();
|
|
356
|
-
FileOutputStream outputStream = new FileOutputStream(
|
|
357
|
-
tempFile,
|
|
358
|
-
downloadedBytes > 0
|
|
359
|
-
);
|
|
360
|
-
if (downloadedBytes == 0) {
|
|
361
337
|
try (
|
|
362
|
-
|
|
338
|
+
InputStream inputStream = httpConn.getInputStream();
|
|
339
|
+
FileOutputStream outputStream = new FileOutputStream(
|
|
340
|
+
tempFile,
|
|
341
|
+
downloadedBytes > 0
|
|
342
|
+
)
|
|
363
343
|
) {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
344
|
+
if (downloadedBytes == 0) {
|
|
345
|
+
try (
|
|
346
|
+
BufferedWriter writer = new BufferedWriter(
|
|
347
|
+
new FileWriter(infoFile)
|
|
348
|
+
)
|
|
349
|
+
) {
|
|
350
|
+
writer.write(String.valueOf(version));
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
// Updating the info file
|
|
354
|
+
try (
|
|
355
|
+
BufferedWriter writer = new BufferedWriter(
|
|
356
|
+
new FileWriter(infoFile)
|
|
357
|
+
)
|
|
358
|
+
) {
|
|
359
|
+
writer.write(String.valueOf(version));
|
|
360
|
+
}
|
|
373
361
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
362
|
+
int bytesRead = -1;
|
|
363
|
+
byte[] buffer = new byte[4096];
|
|
364
|
+
int lastNotifiedPercent = 0;
|
|
365
|
+
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
|
366
|
+
outputStream.write(buffer, 0, bytesRead);
|
|
367
|
+
downloadedBytes += bytesRead;
|
|
368
|
+
// Saving progress (flushing every 100 Ko)
|
|
369
|
+
if (downloadedBytes % 102400 == 0) {
|
|
370
|
+
outputStream.flush();
|
|
371
|
+
}
|
|
372
|
+
// Computing percentage
|
|
373
|
+
int percent = calcTotalPercent(downloadedBytes, contentLength);
|
|
374
|
+
while (lastNotifiedPercent + 10 <= percent) {
|
|
375
|
+
lastNotifiedPercent += 10;
|
|
376
|
+
// Artificial delay using CPU-bound calculation to take ~5 seconds
|
|
377
|
+
double result = 0;
|
|
378
|
+
notifyDownload(id, lastNotifiedPercent);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
391
381
|
|
|
392
|
-
|
|
393
|
-
|
|
382
|
+
outputStream.close();
|
|
383
|
+
inputStream.close();
|
|
394
384
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
385
|
+
// Rename the temp file with the final name (dest)
|
|
386
|
+
tempFile.renameTo(new File(documentsDir, dest));
|
|
387
|
+
infoFile.delete();
|
|
388
|
+
publishResults(dest, id, version, checksum, sessionKey, "", false);
|
|
389
|
+
}
|
|
390
|
+
} else {
|
|
391
|
+
infoFile.delete();
|
|
392
|
+
}
|
|
393
|
+
} finally {
|
|
394
|
+
if (httpConn != null) {
|
|
395
|
+
httpConn.disconnect();
|
|
396
|
+
}
|
|
401
397
|
}
|
|
402
|
-
httpConn.disconnect();
|
|
403
398
|
} catch (OutOfMemoryError e) {
|
|
404
399
|
e.printStackTrace();
|
|
405
400
|
publishResults(
|
|
@@ -423,7 +418,6 @@ public class DownloadService extends IntentService {
|
|
|
423
418
|
false
|
|
424
419
|
);
|
|
425
420
|
}
|
|
426
|
-
stopForegroundIfNeeded();
|
|
427
421
|
}
|
|
428
422
|
|
|
429
423
|
private void clearDownloadData(String docDir) {
|
|
@@ -581,15 +575,4 @@ public class DownloadService extends IntentService {
|
|
|
581
575
|
}
|
|
582
576
|
return sb.toString();
|
|
583
577
|
}
|
|
584
|
-
|
|
585
|
-
private void stopForegroundIfNeeded() {
|
|
586
|
-
handler.removeCallbacks(notificationRunnable);
|
|
587
|
-
if (isNotificationShown) {
|
|
588
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
589
|
-
stopForeground(STOP_FOREGROUND_REMOVE);
|
|
590
|
-
} else {
|
|
591
|
-
stopForeground(true);
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
578
|
}
|
|
@@ -44,7 +44,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
44
44
|
CAPPluginMethod(name: "isAutoUpdateAvailable", returnType: CAPPluginReturnPromise)
|
|
45
45
|
]
|
|
46
46
|
public var implementation = CapacitorUpdater()
|
|
47
|
-
private let PLUGIN_VERSION: String = "6.7.
|
|
47
|
+
private let PLUGIN_VERSION: String = "6.7.7-alpha.1"
|
|
48
48
|
static let updateUrlDefault = "https://plugin.capgo.app/updates"
|
|
49
49
|
static let statsUrlDefault = "https://plugin.capgo.app/stats"
|
|
50
50
|
static let channelUrlDefault = "https://plugin.capgo.app/channel_self"
|