@capgo/capacitor-updater 8.46.1 → 8.46.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.
@@ -0,0 +1,92 @@
1
+ /*
2
+ * This Source Code Form is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
5
+ */
6
+
7
+ package ee.forgr.capacitor_updater;
8
+
9
+ import android.annotation.TargetApi;
10
+ import android.app.ActivityManager;
11
+ import android.app.ApplicationExitInfo;
12
+ import android.content.Context;
13
+ import android.content.SharedPreferences;
14
+ import android.os.Build;
15
+ import java.util.HashMap;
16
+ import java.util.List;
17
+ import java.util.Map;
18
+
19
+ @TargetApi(Build.VERSION_CODES.R)
20
+ final class AndroidAppExitReporter {
21
+
22
+ private AndroidAppExitReporter() {}
23
+
24
+ static void reportPreviousAppExitReasons(
25
+ final Context context,
26
+ final SharedPreferences prefs,
27
+ final CapgoUpdater implementation,
28
+ final Logger logger,
29
+ final String lastReportedAppExitTimestampPrefKey
30
+ ) {
31
+ try {
32
+ final ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
33
+ if (activityManager == null) {
34
+ return;
35
+ }
36
+
37
+ final List<ApplicationExitInfo> exitReasons = activityManager.getHistoricalProcessExitReasons(context.getPackageName(), 0, 8);
38
+ if (exitReasons == null || exitReasons.isEmpty()) {
39
+ return;
40
+ }
41
+
42
+ final long lastReportedTimestamp = prefs.getLong(lastReportedAppExitTimestampPrefKey, 0L);
43
+ long newestReportedTimestamp = lastReportedTimestamp;
44
+ final BundleInfo current = implementation.getCurrentBundle();
45
+ final String versionName = current == null ? "" : current.getVersionName();
46
+
47
+ for (final ApplicationExitInfo exitInfo : exitReasons) {
48
+ if (exitInfo == null || exitInfo.getTimestamp() <= lastReportedTimestamp) {
49
+ continue;
50
+ }
51
+
52
+ final String action = CapacitorUpdaterPlugin.statsActionForApplicationExitReason(exitInfo.getReason());
53
+ if (action == null) {
54
+ continue;
55
+ }
56
+
57
+ implementation.sendStats(action, versionName, "", buildApplicationExitMetadata(exitInfo));
58
+ newestReportedTimestamp = Math.max(newestReportedTimestamp, exitInfo.getTimestamp());
59
+ }
60
+
61
+ if (newestReportedTimestamp > lastReportedTimestamp) {
62
+ prefs.edit().putLong(lastReportedAppExitTimestampPrefKey, newestReportedTimestamp).apply();
63
+ }
64
+ } catch (final Exception e) {
65
+ logger.warn("Unable to report previous app exit reason: " + e.getMessage());
66
+ }
67
+ }
68
+
69
+ private static Map<String, String> buildApplicationExitMetadata(final ApplicationExitInfo exitInfo) {
70
+ final Map<String, String> metadata = new HashMap<>();
71
+ metadata.put("exit_reason", CapacitorUpdaterPlugin.applicationExitReasonName(exitInfo.getReason()));
72
+ metadata.put("exit_reason_code", Integer.toString(exitInfo.getReason()));
73
+ metadata.put("exit_status", Integer.toString(exitInfo.getStatus()));
74
+ metadata.put("exit_importance", Integer.toString(exitInfo.getImportance()));
75
+ metadata.put("exit_timestamp", Long.toString(exitInfo.getTimestamp()));
76
+ metadata.put("pid", Integer.toString(exitInfo.getPid()));
77
+ metadata.put("pss_kb", Long.toString(exitInfo.getPss()));
78
+ metadata.put("rss_kb", Long.toString(exitInfo.getRss()));
79
+
80
+ final String processName = exitInfo.getProcessName();
81
+ if (processName != null && !processName.isEmpty()) {
82
+ metadata.put("process_name", CapacitorUpdaterPlugin.truncateStatsMetadataValue(processName, 128));
83
+ }
84
+
85
+ final String description = exitInfo.getDescription();
86
+ if (description != null && !description.isEmpty()) {
87
+ metadata.put("exit_description", CapacitorUpdaterPlugin.truncateStatsMetadataValue(description, 512));
88
+ }
89
+
90
+ return metadata;
91
+ }
92
+ }
@@ -7,8 +7,6 @@
7
7
  package ee.forgr.capacitor_updater;
8
8
 
9
9
  import android.app.Activity;
10
- import android.app.ActivityManager;
11
- import android.app.ApplicationExitInfo;
12
10
  import android.content.Context;
13
11
  import android.content.Intent;
14
12
  import android.content.SharedPreferences;
@@ -95,8 +93,20 @@ public class CapacitorUpdaterPlugin extends Plugin {
95
93
  private static final int SPLASH_SCREEN_RETRY_DELAY_MS = 100;
96
94
  private static final int SPLASH_SCREEN_MAX_RETRIES = 20;
97
95
  private static final long PENDING_BUNDLE_APP_READY_MIN_TIMEOUT_MS = 30000L;
98
-
99
- private final String pluginVersion = "8.46.1";
96
+ static final int APPLICATION_EXIT_REASON_UNKNOWN = 0;
97
+ static final int APPLICATION_EXIT_REASON_EXIT_SELF = 1;
98
+ static final int APPLICATION_EXIT_REASON_SIGNALED = 2;
99
+ static final int APPLICATION_EXIT_REASON_LOW_MEMORY = 3;
100
+ static final int APPLICATION_EXIT_REASON_CRASH = 4;
101
+ static final int APPLICATION_EXIT_REASON_CRASH_NATIVE = 5;
102
+ static final int APPLICATION_EXIT_REASON_ANR = 6;
103
+ static final int APPLICATION_EXIT_REASON_INITIALIZATION_FAILURE = 7;
104
+ static final int APPLICATION_EXIT_REASON_PERMISSION_CHANGE = 8;
105
+ static final int APPLICATION_EXIT_REASON_EXCESSIVE_RESOURCE_USAGE = 9;
106
+ static final int APPLICATION_EXIT_REASON_USER_REQUESTED = 10;
107
+ static final int APPLICATION_EXIT_REASON_DEPENDENCY_DIED = 12;
108
+
109
+ private final String pluginVersion = "8.46.3";
100
110
  private static final String DELAY_CONDITION_PREFERENCES = "";
101
111
 
102
112
  private SharedPreferences.Editor editor;
@@ -855,61 +865,28 @@ public class CapacitorUpdaterPlugin extends Plugin {
855
865
  return;
856
866
  }
857
867
 
858
- try {
859
- final ActivityManager activityManager = (ActivityManager) this.getContext().getSystemService(Context.ACTIVITY_SERVICE);
860
- if (activityManager == null) {
861
- return;
862
- }
863
-
864
- final List<ApplicationExitInfo> exitReasons = activityManager.getHistoricalProcessExitReasons(
865
- this.getContext().getPackageName(),
866
- 0,
867
- 8
868
- );
869
- if (exitReasons == null || exitReasons.isEmpty()) {
870
- return;
871
- }
872
-
873
- final long lastReportedTimestamp = this.prefs.getLong(LAST_REPORTED_APP_EXIT_TIMESTAMP_PREF_KEY, 0L);
874
- long newestReportedTimestamp = lastReportedTimestamp;
875
- final BundleInfo current = this.implementation.getCurrentBundle();
876
- final String versionName = current == null ? "" : current.getVersionName();
877
-
878
- for (final ApplicationExitInfo exitInfo : exitReasons) {
879
- if (exitInfo == null || exitInfo.getTimestamp() <= lastReportedTimestamp) {
880
- continue;
881
- }
882
-
883
- final String action = statsActionForApplicationExitReason(exitInfo.getReason());
884
- if (action == null) {
885
- continue;
886
- }
887
-
888
- this.implementation.sendStats(action, versionName, "", buildApplicationExitMetadata(exitInfo));
889
- newestReportedTimestamp = Math.max(newestReportedTimestamp, exitInfo.getTimestamp());
890
- }
891
-
892
- if (newestReportedTimestamp > lastReportedTimestamp) {
893
- this.prefs.edit().putLong(LAST_REPORTED_APP_EXIT_TIMESTAMP_PREF_KEY, newestReportedTimestamp).apply();
894
- }
895
- } catch (final Exception e) {
896
- logger.warn("Unable to report previous app exit reason: " + e.getMessage());
897
- }
868
+ AndroidAppExitReporter.reportPreviousAppExitReasons(
869
+ this.getContext(),
870
+ this.prefs,
871
+ this.implementation,
872
+ this.logger,
873
+ LAST_REPORTED_APP_EXIT_TIMESTAMP_PREF_KEY
874
+ );
898
875
  }
899
876
 
900
877
  static String statsActionForApplicationExitReason(final int reason) {
901
878
  switch (reason) {
902
- case ApplicationExitInfo.REASON_CRASH:
879
+ case APPLICATION_EXIT_REASON_CRASH:
903
880
  return "app_crash";
904
- case ApplicationExitInfo.REASON_CRASH_NATIVE:
881
+ case APPLICATION_EXIT_REASON_CRASH_NATIVE:
905
882
  return "app_crash_native";
906
- case ApplicationExitInfo.REASON_ANR:
883
+ case APPLICATION_EXIT_REASON_ANR:
907
884
  return "app_anr";
908
- case ApplicationExitInfo.REASON_LOW_MEMORY:
885
+ case APPLICATION_EXIT_REASON_LOW_MEMORY:
909
886
  return "app_killed_low_memory";
910
- case ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE:
887
+ case APPLICATION_EXIT_REASON_EXCESSIVE_RESOURCE_USAGE:
911
888
  return "app_killed_excessive_resource_usage";
912
- case ApplicationExitInfo.REASON_INITIALIZATION_FAILURE:
889
+ case APPLICATION_EXIT_REASON_INITIALIZATION_FAILURE:
913
890
  return "app_initialization_failure";
914
891
  default:
915
892
  return null;
@@ -918,58 +895,34 @@ public class CapacitorUpdaterPlugin extends Plugin {
918
895
 
919
896
  static String applicationExitReasonName(final int reason) {
920
897
  switch (reason) {
921
- case ApplicationExitInfo.REASON_EXIT_SELF:
898
+ case APPLICATION_EXIT_REASON_EXIT_SELF:
922
899
  return "exit_self";
923
- case ApplicationExitInfo.REASON_SIGNALED:
900
+ case APPLICATION_EXIT_REASON_SIGNALED:
924
901
  return "signaled";
925
- case ApplicationExitInfo.REASON_LOW_MEMORY:
902
+ case APPLICATION_EXIT_REASON_LOW_MEMORY:
926
903
  return "low_memory";
927
- case ApplicationExitInfo.REASON_CRASH:
904
+ case APPLICATION_EXIT_REASON_CRASH:
928
905
  return "crash";
929
- case ApplicationExitInfo.REASON_CRASH_NATIVE:
906
+ case APPLICATION_EXIT_REASON_CRASH_NATIVE:
930
907
  return "crash_native";
931
- case ApplicationExitInfo.REASON_ANR:
908
+ case APPLICATION_EXIT_REASON_ANR:
932
909
  return "anr";
933
- case ApplicationExitInfo.REASON_INITIALIZATION_FAILURE:
910
+ case APPLICATION_EXIT_REASON_INITIALIZATION_FAILURE:
934
911
  return "initialization_failure";
935
- case ApplicationExitInfo.REASON_PERMISSION_CHANGE:
912
+ case APPLICATION_EXIT_REASON_PERMISSION_CHANGE:
936
913
  return "permission_change";
937
- case ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE:
914
+ case APPLICATION_EXIT_REASON_EXCESSIVE_RESOURCE_USAGE:
938
915
  return "excessive_resource_usage";
939
- case ApplicationExitInfo.REASON_USER_REQUESTED:
916
+ case APPLICATION_EXIT_REASON_USER_REQUESTED:
940
917
  return "user_requested";
941
- case ApplicationExitInfo.REASON_DEPENDENCY_DIED:
918
+ case APPLICATION_EXIT_REASON_DEPENDENCY_DIED:
942
919
  return "dependency_died";
943
920
  default:
944
921
  return "unknown";
945
922
  }
946
923
  }
947
924
 
948
- private static Map<String, String> buildApplicationExitMetadata(final ApplicationExitInfo exitInfo) {
949
- final Map<String, String> metadata = new HashMap<>();
950
- metadata.put("exit_reason", applicationExitReasonName(exitInfo.getReason()));
951
- metadata.put("exit_reason_code", Integer.toString(exitInfo.getReason()));
952
- metadata.put("exit_status", Integer.toString(exitInfo.getStatus()));
953
- metadata.put("exit_importance", Integer.toString(exitInfo.getImportance()));
954
- metadata.put("exit_timestamp", Long.toString(exitInfo.getTimestamp()));
955
- metadata.put("pid", Integer.toString(exitInfo.getPid()));
956
- metadata.put("pss_kb", Long.toString(exitInfo.getPss()));
957
- metadata.put("rss_kb", Long.toString(exitInfo.getRss()));
958
-
959
- final String processName = exitInfo.getProcessName();
960
- if (processName != null && !processName.isEmpty()) {
961
- metadata.put("process_name", truncateStatsMetadataValue(processName, 128));
962
- }
963
-
964
- final String description = exitInfo.getDescription();
965
- if (description != null && !description.isEmpty()) {
966
- metadata.put("exit_description", truncateStatsMetadataValue(description, 512));
967
- }
968
-
969
- return metadata;
970
- }
971
-
972
- private static String truncateStatsMetadataValue(final String value, final int maxLength) {
925
+ static String truncateStatsMetadataValue(final String value, final int maxLength) {
973
926
  return value.length() <= maxLength ? value : value.substring(0, maxLength);
974
927
  }
975
928
 
@@ -76,7 +76,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
76
76
  CAPPluginMethod(name: "completeFlexibleUpdate", returnType: CAPPluginReturnPromise)
77
77
  ]
78
78
  public var implementation = CapgoUpdater()
79
- private let pluginVersion: String = "8.46.1"
79
+ private let pluginVersion: String = "8.46.3"
80
80
  static let updateUrlDefault = "https://plugin.capgo.app/updates"
81
81
  static let statsUrlDefault = "https://plugin.capgo.app/stats"
82
82
  static let channelUrlDefault = "https://plugin.capgo.app/channel_self"
@@ -1025,6 +1025,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
1025
1025
  if let error = res.error, !error.isEmpty {
1026
1026
  let responseKind = self.updateResponseKind(kind: res.kind)
1027
1027
  res.kind = responseKind
1028
+ self.notifyBreakingEventsIfNeeded(response: res, version: res.version)
1028
1029
  if responseKind == "failed" {
1029
1030
  self.rejectCall(call, message: error)
1030
1031
  } else {
@@ -1036,6 +1037,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
1036
1037
  } else if let kind = res.kind, !kind.isEmpty {
1037
1038
  let responseKind = self.updateResponseKind(kind: kind)
1038
1039
  res.kind = responseKind
1040
+ self.notifyBreakingEventsIfNeeded(response: res, version: res.version)
1039
1041
  if responseKind != "failed" {
1040
1042
  if res.version.isEmpty {
1041
1043
  res.version = self.implementation.getCurrentBundle().getVersionName()
@@ -1045,6 +1047,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
1045
1047
  self.rejectCall(call, message: res.message ?? "server did not provide a message")
1046
1048
  }
1047
1049
  } else if let message = res.message, !message.isEmpty {
1050
+ self.notifyBreakingEventsIfNeeded(response: res, version: res.version)
1048
1051
  self.rejectCall(call, message: message)
1049
1052
  } else {
1050
1053
  self.resolveCall(call, data: res.toDict())
@@ -1821,6 +1824,21 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
1821
1824
  self.notifyListeners("majorAvailable", data: payload)
1822
1825
  }
1823
1826
 
1827
+ private func shouldNotifyBreakingEvents(response: AppVersion) -> Bool {
1828
+ if response.breaking == true {
1829
+ return true
1830
+ }
1831
+
1832
+ return response.error == "disable_auto_update_to_major" || response.message == "store_update_required"
1833
+ }
1834
+
1835
+ private func notifyBreakingEventsIfNeeded(response: AppVersion, version: String) {
1836
+ if self.shouldNotifyBreakingEvents(response: response) {
1837
+ let eventVersion = version.isEmpty ? self.implementation.getCurrentBundle().getVersionName() : version
1838
+ self.notifyBreakingEvents(version: eventVersion)
1839
+ }
1840
+ }
1841
+
1824
1842
  static func normalizedUpdateResponseKind(kind: String?) -> String {
1825
1843
  if let kind, ["up_to_date", "blocked", "failed"].contains(kind) {
1826
1844
  return kind
@@ -1851,6 +1869,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
1851
1869
  "version": latestVersionName,
1852
1870
  "bundle": current.toJSON()
1853
1871
  ])
1872
+ self.notifyBreakingEventsIfNeeded(response: res, version: res.version)
1854
1873
 
1855
1874
  if responseKind == "up_to_date" {
1856
1875
  self.logger.info("No new version available")
@@ -2017,17 +2036,18 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
2017
2036
  return
2018
2037
  }
2019
2038
  let sessionKey = res.sessionKey ?? ""
2039
+ let latestVersionName = res.version
2020
2040
  guard let downloadUrl = URL(string: res.url) else {
2041
+ self.notifyBreakingEventsIfNeeded(response: res, version: latestVersionName)
2021
2042
  self.logger.error("Error no url or wrong format")
2022
2043
  self.endBackGroundTaskWithNotif(
2023
2044
  msg: "Error no url or wrong format",
2024
- latestVersionName: res.version,
2045
+ latestVersionName: latestVersionName,
2025
2046
  current: current,
2026
2047
  plannedDirectUpdate: plannedDirectUpdate
2027
2048
  )
2028
2049
  return
2029
2050
  }
2030
- let latestVersionName = res.version
2031
2051
  if latestVersionName != "" && current.getVersionName() != latestVersionName {
2032
2052
  do {
2033
2053
  self.logger.info("New bundle: \(latestVersionName) found. Current is: \(current.getVersionName()). \(messageUpdate)")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-updater",
3
- "version": "8.46.1",
3
+ "version": "8.46.3",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Live update for capacitor apps",
6
6
  "main": "dist/plugin.cjs.js",