@capgo/capacitor-updater 4.13.8 → 4.14.2

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,3 +1,6 @@
1
1
  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
2
  package="ee.forgr.capacitor_updater">
3
+ <application>
4
+ <service android:name="ee.forgr.capacitor_updater.DownloadService" />
5
+ </application>
3
6
  </manifest>
@@ -1,14 +1,22 @@
1
1
  package ee.forgr.capacitor_updater;
2
2
 
3
+ import android.app.Activity;
4
+ import android.content.BroadcastReceiver;
5
+ import android.content.Context;
6
+ import android.content.Intent;
7
+ import android.content.IntentFilter;
3
8
  import android.content.SharedPreferences;
4
9
  import android.os.Build;
10
+ import android.os.Bundle;
5
11
  import android.util.Base64;
6
12
  import android.util.Log;
7
13
  import com.android.volley.BuildConfig;
14
+ import com.android.volley.NetworkResponse;
8
15
  import com.android.volley.Request;
9
16
  import com.android.volley.RequestQueue;
10
17
  import com.android.volley.Response;
11
18
  import com.android.volley.VolleyError;
19
+ import com.android.volley.toolbox.HttpHeaderParser;
12
20
  import com.android.volley.toolbox.JsonObjectRequest;
13
21
  import com.getcapacitor.JSObject;
14
22
  import com.getcapacitor.plugin.WebView;
@@ -21,6 +29,7 @@ import java.io.FileOutputStream;
21
29
  import java.io.FilenameFilter;
22
30
  import java.io.IOException;
23
31
  import java.io.InputStream;
32
+ import java.io.UnsupportedEncodingException;
24
33
  import java.net.URL;
25
34
  import java.net.URLConnection;
26
35
  import java.security.GeneralSecurityException;
@@ -54,7 +63,7 @@ public class CapacitorUpdater {
54
63
  private static final String bundleDirectory = "versions";
55
64
 
56
65
  public static final String TAG = "Capacitor-updater";
57
- public static final String pluginVersion = "4.13.8";
66
+ public static final String pluginVersion = "4.14.2";
58
67
 
59
68
  public SharedPreferences.Editor editor;
60
69
  public SharedPreferences prefs;
@@ -62,6 +71,7 @@ public class CapacitorUpdater {
62
71
  public RequestQueue requestQueue;
63
72
 
64
73
  public File documentsDir;
74
+ public Activity activity;
65
75
  public String versionBuild = "";
66
76
  public String versionCode = "";
67
77
  public String versionOs = "";
@@ -125,6 +135,10 @@ public class CapacitorUpdater {
125
135
  return;
126
136
  }
127
137
 
138
+ void notifyListeners(final String id, final JSObject res) {
139
+ return;
140
+ }
141
+
128
142
  private String randomString(final int len) {
129
143
  final StringBuilder sb = new StringBuilder(len);
130
144
  for (int i = 0; i < len; i++) sb.append(
@@ -224,6 +238,135 @@ public class CapacitorUpdater {
224
238
  sourceFile.delete();
225
239
  }
226
240
 
241
+ public void onResume() {
242
+ this.activity.registerReceiver(
243
+ receiver,
244
+ new IntentFilter(DownloadService.NOTIFICATION)
245
+ );
246
+ }
247
+
248
+ public void onPause() {
249
+ this.activity.unregisterReceiver(receiver);
250
+ }
251
+
252
+ private BroadcastReceiver receiver = new BroadcastReceiver() {
253
+ @Override
254
+ public void onReceive(Context context, Intent intent) {
255
+ String action = intent.getAction();
256
+ Bundle bundle = intent.getExtras();
257
+ if (bundle != null) {
258
+ if (action == DownloadService.PERCENTDOWNLOAD) {
259
+ String id = bundle.getString(DownloadService.ID);
260
+ int percent = bundle.getInt(DownloadService.PERCENT);
261
+ CapacitorUpdater.this.notifyDownload(id, percent);
262
+ } else if (action == DownloadService.NOTIFICATION) {
263
+ String id = bundle.getString(DownloadService.ID);
264
+ String dest = bundle.getString(DownloadService.FILEDEST);
265
+ String version = bundle.getString(DownloadService.VERSION);
266
+ String sessionKey = bundle.getString(DownloadService.SESSIONKEY);
267
+ String checksum = bundle.getString(DownloadService.CHECKSUM);
268
+ Log.i(
269
+ CapacitorUpdater.TAG,
270
+ "res " +
271
+ id +
272
+ " " +
273
+ dest +
274
+ " " +
275
+ version +
276
+ " " +
277
+ sessionKey +
278
+ " " +
279
+ checksum
280
+ );
281
+ CapacitorUpdater.this.finishBackground(
282
+ id,
283
+ dest,
284
+ version,
285
+ sessionKey,
286
+ checksum
287
+ );
288
+ } else {
289
+ Log.i(TAG, "Unknown action " + action);
290
+ }
291
+ }
292
+ }
293
+ };
294
+
295
+ public void finishBackground(
296
+ String id,
297
+ String dest,
298
+ String version,
299
+ String sessionKey,
300
+ String checksumRes
301
+ ) {
302
+ try {
303
+ final File downloaded = new File(this.documentsDir, dest);
304
+ this.decryptFile(downloaded, sessionKey);
305
+ final String checksum;
306
+ checksum = this.getChecksum(downloaded);
307
+
308
+ this.notifyDownload(id, 71);
309
+ final File unzipped = this.unzip(id, downloaded, this.randomString(10));
310
+ downloaded.delete();
311
+ this.notifyDownload(id, 91);
312
+ final String idName = bundleDirectory + "/" + id;
313
+ this.flattenAssets(unzipped, idName);
314
+ this.notifyDownload(id, 100);
315
+ this.saveBundleInfo(id, null);
316
+ BundleInfo info = new BundleInfo(
317
+ id,
318
+ version,
319
+ BundleStatus.PENDING,
320
+ new Date(System.currentTimeMillis()),
321
+ checksum
322
+ );
323
+ this.saveBundleInfo(id, info);
324
+ if (!checksumRes.equals("") && !checksumRes.equals(checksum)) {
325
+ Log.e(
326
+ CapacitorUpdater.TAG,
327
+ "Error checksum " + info.getChecksum() + " " + checksum
328
+ );
329
+ this.sendStats("checksum_fail", getCurrentBundle().getVersionName());
330
+ final Boolean res = this.delete(info.getId());
331
+ if (res) {
332
+ Log.i(
333
+ CapacitorUpdater.TAG,
334
+ "Failed bundle deleted: " + info.getVersionName()
335
+ );
336
+ }
337
+ return;
338
+ }
339
+ final JSObject ret = new JSObject();
340
+ ret.put("bundle", info.toJSON());
341
+ CapacitorUpdater.this.notifyListeners("updateAvailable", ret);
342
+ this.setNextBundle(info.getId());
343
+ } catch (IOException e) {
344
+ e.printStackTrace();
345
+ }
346
+ }
347
+
348
+ private void downloadFileBackground(
349
+ final String id,
350
+ final String url,
351
+ final String version,
352
+ final String sessionKey,
353
+ final String checksum,
354
+ final String dest
355
+ ) {
356
+ Intent intent = new Intent(this.activity, DownloadService.class);
357
+ intent.putExtra(DownloadService.URL, url);
358
+ intent.putExtra(DownloadService.FILEDEST, dest);
359
+ intent.putExtra(
360
+ DownloadService.DOCDIR,
361
+ this.documentsDir.getAbsolutePath()
362
+ );
363
+ intent.putExtra(DownloadService.ID, id);
364
+ intent.putExtra(DownloadService.VERSION, version);
365
+ intent.putExtra(DownloadService.SESSIONKEY, sessionKey);
366
+ intent.putExtra(DownloadService.CHECKSUM, checksum);
367
+ this.activity.startService(intent);
368
+ }
369
+
227
370
  private File downloadFile(
228
371
  final String id,
229
372
  final String url,
@@ -325,6 +468,35 @@ public class CapacitorUpdater {
325
468
  }
326
469
  }
327
470
 
471
+ public void downloadBackground(
472
+ final String url,
473
+ final String version,
474
+ final String sessionKey,
475
+ final String checksum
476
+ ) {
477
+ final String id = this.randomString(10);
478
+ this.saveBundleInfo(
479
+ id,
480
+ new BundleInfo(
481
+ id,
482
+ version,
483
+ BundleStatus.DOWNLOADING,
484
+ new Date(System.currentTimeMillis()),
485
+ ""
486
+ )
487
+ );
488
+ this.notifyDownload(id, 0);
489
+ this.notifyDownload(id, 5);
490
+ this.downloadFileBackground(
491
+ id,
492
+ url,
493
+ version,
494
+ sessionKey,
495
+ checksum,
496
+ this.randomString(10)
497
+ );
498
+ }
499
+
328
500
  public BundleInfo download(
329
501
  final String url,
330
502
  final String version,
@@ -503,6 +675,29 @@ public class CapacitorUpdater {
503
675
  return json;
504
676
  }
505
677
 
678
+ private JSObject createError(String message, VolleyError error) {
679
+ NetworkResponse response = error.networkResponse;
680
+ final JSObject retError = new JSObject();
681
+ retError.put("error", "response_error");
682
+ if (response != null) {
683
+ try {
684
+ String json = new String(
685
+ response.data,
686
+ HttpHeaderParser.parseCharset(response.headers)
687
+ );
688
+ Log.e(TAG, message + ": " + json);
689
+ retError.put("message", message + ": " + json);
690
+ } catch (UnsupportedEncodingException e) {
691
+ Log.e(TAG, message + ": " + e.toString());
692
+ retError.put("message", message + ": " + e.toString());
693
+ }
694
+ } else {
695
+ Log.e(TAG, message + ": " + error.toString());
696
+ retError.put("message", message + ": " + error.toString());
697
+ }
698
+ return retError;
699
+ }
700
+
506
701
  public void getLatest(final String updateUrl, final Callback callback) {
507
702
  JSONObject json = null;
508
703
  try {
@@ -548,11 +743,9 @@ public class CapacitorUpdater {
548
743
  new Response.ErrorListener() {
549
744
  @Override
550
745
  public void onErrorResponse(VolleyError error) {
551
- Log.e(TAG, "Error getting Latest" + error.toString());
552
- final JSObject retError = new JSObject();
553
- retError.put("message", "Cannot set info: " + error.toString());
554
- retError.put("error", "response_error");
555
- callback.callback(retError);
746
+ callback.callback(
747
+ CapacitorUpdater.this.createError("Error get latest", error)
748
+ );
556
749
  }
557
750
  }
558
751
  );
@@ -615,11 +808,9 @@ public class CapacitorUpdater {
615
808
  new Response.ErrorListener() {
616
809
  @Override
617
810
  public void onErrorResponse(VolleyError error) {
618
- Log.e(TAG, "Error set channel: " + error.toString());
619
- final JSObject retError = new JSObject();
620
- retError.put("message", "Cannot set channel: " + error.toString());
621
- retError.put("error", "response_error");
622
- callback.callback(retError);
811
+ callback.callback(
812
+ CapacitorUpdater.this.createError("Error set channel", error)
813
+ );
623
814
  }
624
815
  }
625
816
  );
@@ -677,11 +868,9 @@ public class CapacitorUpdater {
677
868
  new Response.ErrorListener() {
678
869
  @Override
679
870
  public void onErrorResponse(VolleyError error) {
680
- Log.e(TAG, "Error get channel: " + error.toString());
681
- final JSObject retError = new JSObject();
682
- retError.put("message", "Error get channel: " + error.toString());
683
- retError.put("error", "response_error");
684
- callback.callback(retError);
871
+ callback.callback(
872
+ CapacitorUpdater.this.createError("Error get channel", error)
873
+ );
685
874
  }
686
875
  }
687
876
  );
@@ -719,7 +908,7 @@ public class CapacitorUpdater {
719
908
  new Response.ErrorListener() {
720
909
  @Override
721
910
  public void onErrorResponse(VolleyError error) {
722
- Log.e(TAG, "Error sending stats: " + error.toString());
911
+ CapacitorUpdater.this.createError("Error send stats", error);
723
912
  }
724
913
  }
725
914
  );
@@ -81,11 +81,17 @@ public class CapacitorUpdaterPlugin
81
81
  public void notifyDownload(final String id, final int percent) {
82
82
  CapacitorUpdaterPlugin.this.notifyDownload(id, percent);
83
83
  }
84
+
85
+ @Override
86
+ public void notifyListeners(final String id, final JSObject res) {
87
+ CapacitorUpdaterPlugin.this.notifyListeners(id, res);
88
+ }
84
89
  };
85
90
  final PackageInfo pInfo =
86
91
  this.getContext()
87
92
  .getPackageManager()
88
93
  .getPackageInfo(this.getContext().getPackageName(), 0);
94
+ this.implementation.activity = this.getActivity();
89
95
  this.implementation.versionBuild = pInfo.versionName;
90
96
  this.implementation.versionCode = Integer.toString(pInfo.versionCode);
91
97
  this.implementation.requestQueue =
@@ -946,51 +952,11 @@ public class CapacitorUpdaterPlugin
946
952
  final String session_key = res.has("session_key")
947
953
  ? res.getString("session_key")
948
954
  : "";
949
- final BundleInfo next =
950
- CapacitorUpdaterPlugin.this.implementation.download(
951
- url,
952
- latestVersionName,
953
- session_key
954
- );
955
- final String checksum = res.has("checksum")
956
- ? res.getString("checksum")
957
- : "";
958
- if (
959
- !checksum.equals("") &&
960
- !next.getChecksum().equals(checksum)
961
- ) {
962
- Log.e(
963
- CapacitorUpdater.TAG,
964
- "Error checksum " +
965
- next.getChecksum() +
966
- " " +
967
- checksum
968
- );
969
- CapacitorUpdaterPlugin.this.implementation.sendStats(
970
- "checksum_fail",
971
- current.getVersionName()
972
- );
973
- final Boolean res =
974
- CapacitorUpdaterPlugin.this.implementation.delete(
975
- next.getId()
976
- );
977
- if (res) {
978
- Log.i(
979
- CapacitorUpdater.TAG,
980
- "Failed bundle deleted: " +
981
- next.getVersionName()
982
- );
983
- }
984
- return;
985
- }
986
- final JSObject ret = new JSObject();
987
- ret.put("bundle", next.toJSON());
988
- CapacitorUpdaterPlugin.this.notifyListeners(
989
- "updateAvailable",
990
- ret
991
- );
992
- CapacitorUpdaterPlugin.this.implementation.setNextBundle(
993
- next.getId()
955
+ CapacitorUpdaterPlugin.this.implementation.downloadBackground(
956
+ url,
957
+ latestVersionName,
958
+ session_key,
959
+ res.getString("checksum")
994
960
  );
995
961
  } catch (final Exception e) {
996
962
  Log.e(
@@ -1246,23 +1212,34 @@ public class CapacitorUpdaterPlugin
1246
1212
  if (backgroundTask != null && taskRunning) {
1247
1213
  backgroundTask.interrupt();
1248
1214
  }
1215
+ this.implementation.activity = activity;
1216
+ this.implementation.onResume();
1249
1217
  }
1250
1218
 
1251
1219
  @Override
1252
- public void onActivityPaused(@NonNull final Activity activity) {}
1220
+ public void onActivityPaused(@NonNull final Activity activity) {
1221
+ this.implementation.activity = activity;
1222
+ this.implementation.onPause();
1223
+ }
1253
1224
 
1254
1225
  @Override
1255
1226
  public void onActivityCreated(
1256
1227
  @NonNull final Activity activity,
1257
1228
  @Nullable final Bundle savedInstanceState
1258
- ) {}
1229
+ ) {
1230
+ this.implementation.activity = activity;
1231
+ }
1259
1232
 
1260
1233
  @Override
1261
1234
  public void onActivitySaveInstanceState(
1262
1235
  @NonNull final Activity activity,
1263
1236
  @NonNull final Bundle outState
1264
- ) {}
1237
+ ) {
1238
+ this.implementation.activity = activity;
1239
+ }
1265
1240
 
1266
1241
  @Override
1267
- public void onActivityDestroyed(@NonNull final Activity activity) {}
1242
+ public void onActivityDestroyed(@NonNull final Activity activity) {
1243
+ this.implementation.activity = activity;
1244
+ }
1268
1245
  }
@@ -0,0 +1,120 @@
1
+ package ee.forgr.capacitor_updater;
2
+
3
+ import android.app.IntentService;
4
+ import android.content.Intent;
5
+ import java.io.DataInputStream;
6
+ import java.io.File;
7
+ import java.io.FileOutputStream;
8
+ import java.io.InputStream;
9
+ import java.net.URL;
10
+ import java.net.URLConnection;
11
+
12
+ public class DownloadService extends IntentService {
13
+
14
+ public static final String URL = "URL";
15
+ public static final String ID = "id";
16
+ public static final String PERCENT = "percent";
17
+ public static final String FILEDEST = "filendest";
18
+ public static final String DOCDIR = "docdir";
19
+ public static final String ERROR = "error";
20
+ public static final String VERSION = "version";
21
+ public static final String SESSIONKEY = "sessionkey";
22
+ public static final String CHECKSUM = "checksum";
23
+ public static final String NOTIFICATION = "service receiver";
24
+ public static final String PERCENTDOWNLOAD = "percent receiver";
25
+
26
+ public DownloadService() {
27
+ super("Background DownloadService");
28
+ }
29
+
30
+ private int calcTotalPercent(
31
+ final int percent,
32
+ final int min,
33
+ final int max
34
+ ) {
35
+ return (percent * (max - min)) / 100 + min;
36
+ }
37
+
38
+ // Will be called asynchronously by OS.
39
+ @Override
40
+ protected void onHandleIntent(Intent intent) {
41
+ String url = intent.getStringExtra(URL);
42
+ String id = intent.getStringExtra(ID);
43
+ String documentsDir = intent.getStringExtra(DOCDIR);
44
+ String dest = intent.getStringExtra(FILEDEST);
45
+ String version = intent.getStringExtra(VERSION);
46
+ String sessionKey = intent.getStringExtra(SESSIONKEY);
47
+ String checksum = intent.getStringExtra(CHECKSUM);
48
+
49
+ try {
50
+ final URL u = new URL(url);
51
+ final URLConnection connection = u.openConnection();
52
+ final InputStream is = u.openStream();
53
+ final DataInputStream dis = new DataInputStream(is);
54
+
55
+ final File target = new File(documentsDir, dest);
56
+ target.getParentFile().mkdirs();
57
+ target.createNewFile();
58
+ final FileOutputStream fos = new FileOutputStream(target);
59
+
60
+ final long totalLength = connection.getContentLength();
61
+ final int bufferSize = 1024;
62
+ final byte[] buffer = new byte[bufferSize];
63
+ int length;
64
+
65
+ int bytesRead = bufferSize;
66
+ int percent = 0;
67
+ this.notifyDownload(id, 10);
68
+ while ((length = dis.read(buffer)) > 0) {
69
+ fos.write(buffer, 0, length);
70
+ final int newPercent = (int) ((bytesRead * 100) / totalLength);
71
+ if (totalLength > 1 && newPercent != percent) {
72
+ percent = newPercent;
73
+ this.notifyDownload(id, this.calcTotalPercent(percent, 10, 70));
74
+ }
75
+ bytesRead += length;
76
+ }
77
+ publishResults(dest, id, version, checksum, sessionKey, "");
78
+ } catch (Exception e) {
79
+ e.printStackTrace();
80
+ publishResults(
81
+ "",
82
+ id,
83
+ version,
84
+ checksum,
85
+ sessionKey,
86
+ e.getLocalizedMessage()
87
+ );
88
+ }
89
+ }
90
+
91
+ private void notifyDownload(String id, int percent) {
92
+ Intent intent = new Intent(PERCENTDOWNLOAD);
93
+ intent.putExtra(ID, id);
94
+ intent.putExtra(PERCENT, percent);
95
+ sendBroadcast(intent);
96
+ }
97
+
98
+ private void publishResults(
99
+ String dest,
100
+ String id,
101
+ String version,
102
+ String checksum,
103
+ String sessionKey,
104
+ String error
105
+ ) {
106
+ Intent intent = new Intent(NOTIFICATION);
107
+ if (!dest.equals("")) {
108
+ intent.putExtra(FILEDEST, dest);
109
+ }
110
+ if (!error.equals("")) {
111
+ intent.putExtra(ERROR, error);
112
+ }
113
+ intent.putExtra(ID, id);
114
+ intent.putExtra(VERSION, version);
115
+ intent.putExtra(SESSIONKEY, sessionKey);
116
+ intent.putExtra(CHECKSUM, checksum);
117
+ intent.putExtra(ERROR, error);
118
+ sendBroadcast(intent);
119
+ }
120
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-updater",
3
- "version": "4.13.8",
3
+ "version": "4.14.2",
4
4
  "license": "LGPL-3.0-only",
5
5
  "description": "OTA update for capacitor apps",
6
6
  "main": "dist/plugin.cjs.js",