@capgo/capacitor-updater 6.7.6 → 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.
@@ -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 android:name="ee.forgr.capacitor_updater.DownloadService" />
5
+ <service
6
+ android:name="ee.forgr.capacitor_updater.DownloadService"
7
+ android:exported="false" />
4
8
  </application>
5
9
  </manifest>
@@ -482,22 +482,7 @@ public class CapacitorUpdater {
482
482
  intent.putExtra(DownloadService.IS_MANIFEST, true);
483
483
  }
484
484
 
485
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
486
- // Check if app is in foreground using activity lifecycle state
487
- boolean isAppForeground =
488
- this.activity != null &&
489
- !this.activity.isFinishing() &&
490
- this.activity.hasWindowFocus();
491
- if (!isAppForeground) {
492
- // If app is not in foreground, use regular startService instead of startForegroundService
493
- Log.d(TAG, "App is in background, aborting downloadFileBackground");
494
- return;
495
- }
496
- Log.d(TAG, "App is in foreground, using startForegroundService");
497
- this.activity.startForegroundService(intent);
498
- } else {
499
- this.activity.startService(intent);
500
- }
485
+ this.activity.startService(intent);
501
486
  }
502
487
 
503
488
  private void downloadFile(
@@ -513,28 +498,27 @@ public class CapacitorUpdater {
513
498
  target.createNewFile();
514
499
 
515
500
  final long totalLength = connection.getContentLength();
516
- final int bufferSize = 1024;
517
- final byte[] buffer = new byte[bufferSize];
518
- int length;
519
-
520
- int bytesRead = bufferSize;
501
+ int bytesRead = 0;
521
502
  int percent = 0;
522
503
  this.notifyDownload(id, 10);
504
+
523
505
  try (
524
- final InputStream is = connection.getInputStream();
525
- final DataInputStream dis = new DataInputStream(is);
526
- final FileOutputStream fos = new FileOutputStream(target)
506
+ InputStream is = connection.getInputStream();
507
+ DataInputStream dis = new DataInputStream(is);
508
+ FileOutputStream fos = new FileOutputStream(target)
527
509
  ) {
510
+ byte[] buffer = new byte[8192];
511
+ int length;
528
512
  while ((length = dis.read(buffer)) > 0) {
529
513
  fos.write(buffer, 0, length);
514
+ bytesRead += length;
530
515
  final int newPercent = (int) ((bytesRead / (float) totalLength) * 100);
531
516
  if (totalLength > 1 && newPercent != percent) {
532
517
  percent = newPercent;
533
518
  this.notifyDownload(id, this.calcTotalPercent(percent, 10, 70));
534
519
  }
535
- bytesRead += length;
536
520
  }
537
- if (bytesRead == bufferSize) {
521
+ if (bytesRead == 0) {
538
522
  throw new IOException("Failed to download: No data read from URL");
539
523
  }
540
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.6";
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,14 +6,7 @@
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.content.pm.ServiceInfo;
14
- import android.os.Build;
15
- import android.os.Handler;
16
- import android.os.Looper;
17
10
  import android.os.PowerManager;
18
11
  import android.util.Log;
19
12
  import java.io.*;
@@ -57,19 +50,10 @@ public class DownloadService extends IntentService {
57
50
  public static final String IS_MANIFEST = "is_manifest";
58
51
  public static final String MANIFEST = "manifest";
59
52
  private static final String UPDATE_FILE = "update.dat";
60
- private static final int NOTIFICATION_ID = 1;
61
- private static final long NOTIFICATION_DELAY_MS = 4000; // 4 seconds
62
- private static final String CHANNEL_ID = "CapacitorUpdaterChannel";
63
- private static final String CHANNEL_NAME = "Capacitor Updater";
64
- private static final String CHANNEL_DESCRIPTION =
65
- "Notifications for app updates";
66
53
 
67
54
  private final OkHttpClient client = new OkHttpClient.Builder()
68
55
  .protocols(Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1))
69
56
  .build();
70
- private Handler handler = new Handler(Looper.getMainLooper());
71
- private Runnable notificationRunnable;
72
- private boolean isNotificationShown = false;
73
57
  private PowerManager.WakeLock wakeLock;
74
58
 
75
59
  public DownloadService() {
@@ -79,54 +63,22 @@ public class DownloadService extends IntentService {
79
63
  @Override
80
64
  public void onCreate() {
81
65
  super.onCreate();
82
- this.startForegroundService();
66
+ PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
67
+ wakeLock = powerManager.newWakeLock(
68
+ PowerManager.PARTIAL_WAKE_LOCK,
69
+ "CapacitorUpdater::DownloadWakeLock"
70
+ );
83
71
  }
84
72
 
85
73
  @Override
86
74
  public void onDestroy() {
87
75
  super.onDestroy();
88
- handler.removeCallbacks(notificationRunnable);
89
76
  Log.w(TAG + " DownloadService", "DownloadService killed/destroyed");
90
- }
91
-
92
- private void startForegroundService() {
93
- isNotificationShown = true;
94
- String channelId = createNotificationChannelForDownload();
95
-
96
- Notification.Builder builder = new Notification.Builder(this, channelId)
97
- .setContentTitle("Downloading Update")
98
- .setContentText("Download in progress")
99
- .setSmallIcon(android.R.drawable.stat_sys_download)
100
- .setOngoing(true)
101
- .setPriority(Notification.PRIORITY_MIN)
102
- .setCategory(Notification.CATEGORY_SERVICE)
103
- .setAutoCancel(false);
104
-
105
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
106
- startForeground(
107
- NOTIFICATION_ID,
108
- builder.build(),
109
- ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
110
- );
111
- } else {
112
- startForeground(NOTIFICATION_ID, builder.build());
77
+ if (wakeLock != null && wakeLock.isHeld()) {
78
+ wakeLock.release();
113
79
  }
114
80
  }
115
81
 
116
- private String createNotificationChannelForDownload() {
117
- String channelId = "capacitor_updater_channel";
118
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
119
- NotificationChannel channel = new NotificationChannel(
120
- channelId,
121
- "Capacitor Updater Downloads",
122
- NotificationManager.IMPORTANCE_MIN // // High importance to keep service alive
123
- );
124
- NotificationManager manager = getSystemService(NotificationManager.class);
125
- manager.createNotificationChannel(channel);
126
- }
127
- return channelId;
128
- }
129
-
130
82
  private int calcTotalPercent(long downloadedBytes, long contentLength) {
131
83
  if (contentLength <= 0) {
132
84
  return 0;
@@ -139,50 +91,58 @@ public class DownloadService extends IntentService {
139
91
 
140
92
  @Override
141
93
  protected void onHandleIntent(Intent intent) {
142
- assert intent != null;
143
- String url = intent.getStringExtra(URL);
144
- String id = intent.getStringExtra(ID);
145
- String documentsDir = intent.getStringExtra(DOCDIR);
146
- String dest = intent.getStringExtra(FILEDEST);
147
- String version = intent.getStringExtra(VERSION);
148
- String sessionKey = intent.getStringExtra(SESSIONKEY);
149
- String checksum = intent.getStringExtra(CHECKSUM);
150
- boolean isManifest = intent.getBooleanExtra(IS_MANIFEST, false);
151
-
152
- Log.d(TAG + " DownloadService", "onHandleIntent isManifest: " + isManifest);
153
- if (isManifest) {
154
- JSONArray manifest = DataManager.getInstance().getAndClearManifest();
155
- if (manifest != null) {
156
- handleManifestDownload(
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,
157
136
  id,
158
137
  documentsDir,
159
138
  dest,
160
139
  version,
161
140
  sessionKey,
162
- manifest.toString()
163
- );
164
- } else {
165
- Log.e(TAG + " DownloadService", "Manifest is null");
166
- publishResults(
167
- "",
168
- id,
169
- version,
170
- checksum,
171
- sessionKey,
172
- "Manifest is null",
173
- false
141
+ checksum
174
142
  );
175
143
  }
176
- } else {
177
- handleSingleFileDownload(
178
- url,
179
- id,
180
- documentsDir,
181
- dest,
182
- version,
183
- sessionKey,
184
- checksum
185
- );
144
+ } finally {
145
+ wakeLock.release();
186
146
  }
187
147
  }
188
148
 
@@ -317,7 +277,6 @@ public class DownloadService extends IntentService {
317
277
  Log.e(TAG + " DownloadService", "Error in handleManifestDownload", e);
318
278
  publishResults("", id, version, "", sessionKey, e.getMessage(), true);
319
279
  }
320
- stopForegroundIfNeeded();
321
280
  }
322
281
 
323
282
  private void handleSingleFileDownload(
@@ -335,91 +294,107 @@ public class DownloadService extends IntentService {
335
294
  File tempFile = new File(documentsDir, "temp" + ".tmp"); // Temp file, where the downloaded data is stored
336
295
  try {
337
296
  URL u = new URL(url);
338
- HttpURLConnection httpConn = (HttpURLConnection) u.openConnection();
297
+ HttpURLConnection httpConn = null;
298
+ try {
299
+ httpConn = (HttpURLConnection) u.openConnection();
339
300
 
340
- // Reading progress file (if exist)
341
- long downloadedBytes = 0;
301
+ // Reading progress file (if exist)
302
+ long downloadedBytes = 0;
342
303
 
343
- if (infoFile.exists() && tempFile.exists()) {
344
- try (
345
- BufferedReader reader = new BufferedReader(new FileReader(infoFile))
346
- ) {
347
- String updateVersion = reader.readLine();
348
- if (!updateVersion.equals(version)) {
349
- clearDownloadData(documentsDir);
350
- downloadedBytes = 0;
351
- } else {
352
- downloadedBytes = tempFile.length();
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
+ }
353
315
  }
316
+ } else {
317
+ clearDownloadData(documentsDir);
318
+ downloadedBytes = 0;
354
319
  }
355
- } else {
356
- clearDownloadData(documentsDir);
357
- downloadedBytes = 0;
358
- }
359
320
 
360
- if (downloadedBytes > 0) {
361
- httpConn.setRequestProperty("Range", "bytes=" + downloadedBytes + "-");
362
- }
321
+ if (downloadedBytes > 0) {
322
+ httpConn.setRequestProperty(
323
+ "Range",
324
+ "bytes=" + downloadedBytes + "-"
325
+ );
326
+ }
363
327
 
364
- int responseCode = httpConn.getResponseCode();
328
+ int responseCode = httpConn.getResponseCode();
365
329
 
366
- if (
367
- responseCode == HttpURLConnection.HTTP_OK ||
368
- responseCode == HttpURLConnection.HTTP_PARTIAL
369
- ) {
370
- String contentType = httpConn.getContentType();
371
- long contentLength = httpConn.getContentLength() + downloadedBytes;
330
+ if (
331
+ responseCode == HttpURLConnection.HTTP_OK ||
332
+ responseCode == HttpURLConnection.HTTP_PARTIAL
333
+ ) {
334
+ String contentType = httpConn.getContentType();
335
+ long contentLength = httpConn.getContentLength() + downloadedBytes;
372
336
 
373
- InputStream inputStream = httpConn.getInputStream();
374
- FileOutputStream outputStream = new FileOutputStream(
375
- tempFile,
376
- downloadedBytes > 0
377
- );
378
- if (downloadedBytes == 0) {
379
337
  try (
380
- BufferedWriter writer = new BufferedWriter(new FileWriter(infoFile))
338
+ InputStream inputStream = httpConn.getInputStream();
339
+ FileOutputStream outputStream = new FileOutputStream(
340
+ tempFile,
341
+ downloadedBytes > 0
342
+ )
381
343
  ) {
382
- writer.write(String.valueOf(version));
383
- }
384
- }
385
- // Updating the info file
386
- try (
387
- BufferedWriter writer = new BufferedWriter(new FileWriter(infoFile))
388
- ) {
389
- writer.write(String.valueOf(version));
390
- }
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
+ }
391
361
 
392
- int bytesRead = -1;
393
- byte[] buffer = new byte[4096];
394
- int lastNotifiedPercent = 0;
395
- while ((bytesRead = inputStream.read(buffer)) != -1) {
396
- outputStream.write(buffer, 0, bytesRead);
397
- downloadedBytes += bytesRead;
398
- // Saving progress (flushing every 100 Ko)
399
- if (downloadedBytes % 102400 == 0) {
400
- outputStream.flush();
401
- }
402
- // Computing percentage
403
- int percent = calcTotalPercent(downloadedBytes, contentLength);
404
- while (lastNotifiedPercent + 10 <= percent) {
405
- lastNotifiedPercent += 10;
406
- // Artificial delay using CPU-bound calculation to take ~5 seconds
407
- double result = 0;
408
- notifyDownload(id, lastNotifiedPercent);
409
- }
410
- }
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
+ }
411
381
 
412
- outputStream.close();
413
- inputStream.close();
382
+ outputStream.close();
383
+ inputStream.close();
414
384
 
415
- // Rename the temp file with the final name (dest)
416
- tempFile.renameTo(new File(documentsDir, dest));
417
- infoFile.delete();
418
- publishResults(dest, id, version, checksum, sessionKey, "", false);
419
- } else {
420
- infoFile.delete();
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
+ }
421
397
  }
422
- httpConn.disconnect();
423
398
  } catch (OutOfMemoryError e) {
424
399
  e.printStackTrace();
425
400
  publishResults(
@@ -443,7 +418,6 @@ public class DownloadService extends IntentService {
443
418
  false
444
419
  );
445
420
  }
446
- stopForegroundIfNeeded();
447
421
  }
448
422
 
449
423
  private void clearDownloadData(String docDir) {
@@ -601,56 +575,4 @@ public class DownloadService extends IntentService {
601
575
  }
602
576
  return sb.toString();
603
577
  }
604
-
605
- private void stopForegroundIfNeeded() {
606
- handler.removeCallbacks(notificationRunnable);
607
- if (isNotificationShown) {
608
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
609
- stopForeground(STOP_FOREGROUND_REMOVE);
610
- } else {
611
- stopForeground(true);
612
- }
613
- }
614
- }
615
-
616
- private void createNotificationChannel() {
617
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
618
- NotificationChannel channel = new NotificationChannel(
619
- CHANNEL_ID,
620
- CHANNEL_NAME,
621
- NotificationManager.IMPORTANCE_MAX
622
- );
623
- channel.setDescription(CHANNEL_DESCRIPTION);
624
- NotificationManager notificationManager = getSystemService(
625
- NotificationManager.class
626
- );
627
- notificationManager.createNotificationChannel(channel);
628
- }
629
- }
630
-
631
- private void showNotification(String text, int progress) {
632
- Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID)
633
- .setSmallIcon(android.R.drawable.stat_sys_download)
634
- .setContentTitle("App Update")
635
- .setContentText(text)
636
- // .setPriority(Notification.PRIORITY_LOW)
637
- .setOngoing(true);
638
-
639
- if (progress > 0) {
640
- builder.setProgress(100, progress, false);
641
- }
642
-
643
- startForeground(NOTIFICATION_ID, builder.build());
644
- }
645
-
646
- // Update the notification progress
647
- private void updateNotificationProgress(int progress) {
648
- showNotification("Downloading OTA update... " + progress + "%", progress);
649
- }
650
-
651
- // When download completes or fails
652
- private void stopForegroundService() {
653
- stopForeground(true);
654
- stopSelf();
655
- }
656
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.6"
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"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-updater",
3
- "version": "6.7.6",
3
+ "version": "6.7.7-alpha.1",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Live update for capacitor apps",
6
6
  "main": "dist/plugin.cjs.js",