@capgo/capacitor-updater 8.46.0 → 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
|
-
|
|
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
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
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
|
|
879
|
+
case APPLICATION_EXIT_REASON_CRASH:
|
|
903
880
|
return "app_crash";
|
|
904
|
-
case
|
|
881
|
+
case APPLICATION_EXIT_REASON_CRASH_NATIVE:
|
|
905
882
|
return "app_crash_native";
|
|
906
|
-
case
|
|
883
|
+
case APPLICATION_EXIT_REASON_ANR:
|
|
907
884
|
return "app_anr";
|
|
908
|
-
case
|
|
885
|
+
case APPLICATION_EXIT_REASON_LOW_MEMORY:
|
|
909
886
|
return "app_killed_low_memory";
|
|
910
|
-
case
|
|
887
|
+
case APPLICATION_EXIT_REASON_EXCESSIVE_RESOURCE_USAGE:
|
|
911
888
|
return "app_killed_excessive_resource_usage";
|
|
912
|
-
case
|
|
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
|
|
898
|
+
case APPLICATION_EXIT_REASON_EXIT_SELF:
|
|
922
899
|
return "exit_self";
|
|
923
|
-
case
|
|
900
|
+
case APPLICATION_EXIT_REASON_SIGNALED:
|
|
924
901
|
return "signaled";
|
|
925
|
-
case
|
|
902
|
+
case APPLICATION_EXIT_REASON_LOW_MEMORY:
|
|
926
903
|
return "low_memory";
|
|
927
|
-
case
|
|
904
|
+
case APPLICATION_EXIT_REASON_CRASH:
|
|
928
905
|
return "crash";
|
|
929
|
-
case
|
|
906
|
+
case APPLICATION_EXIT_REASON_CRASH_NATIVE:
|
|
930
907
|
return "crash_native";
|
|
931
|
-
case
|
|
908
|
+
case APPLICATION_EXIT_REASON_ANR:
|
|
932
909
|
return "anr";
|
|
933
|
-
case
|
|
910
|
+
case APPLICATION_EXIT_REASON_INITIALIZATION_FAILURE:
|
|
934
911
|
return "initialization_failure";
|
|
935
|
-
case
|
|
912
|
+
case APPLICATION_EXIT_REASON_PERMISSION_CHANGE:
|
|
936
913
|
return "permission_change";
|
|
937
|
-
case
|
|
914
|
+
case APPLICATION_EXIT_REASON_EXCESSIVE_RESOURCE_USAGE:
|
|
938
915
|
return "excessive_resource_usage";
|
|
939
|
-
case
|
|
916
|
+
case APPLICATION_EXIT_REASON_USER_REQUESTED:
|
|
940
917
|
return "user_requested";
|
|
941
|
-
case
|
|
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
|
-
|
|
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.
|
|
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:
|
|
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)")
|