@capgo/capacitor-updater 7.3.3 → 7.5.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.
@@ -955,19 +955,17 @@ import UIKit
955
955
  request.validate().responseDecodable(of: SetChannelDec.self) { response in
956
956
  switch response.result {
957
957
  case .success:
958
- if let status = response.value?.status {
959
- setChannel.status = status
960
- }
961
- if let error = response.value?.error {
962
- setChannel.error = error
963
- }
964
- if let message = response.value?.message {
965
- setChannel.message = message
958
+ if let responseValue = response.value {
959
+ if let error = responseValue.error {
960
+ setChannel.error = error
961
+ } else {
962
+ setChannel.status = responseValue.status ?? ""
963
+ setChannel.message = responseValue.message ?? ""
964
+ }
966
965
  }
967
966
  case let .failure(error):
968
- self.logger.error("Error unset Channel \(response.value.debugDescription) \(error)")
969
- setChannel.message = "Error unset Channel \(String(describing: response.value))"
970
- setChannel.error = "response_error"
967
+ self.logger.error("Error unset Channel \(error)")
968
+ setChannel.error = "Request failed: \(error.localizedDescription)"
971
969
  }
972
970
  semaphore.signal()
973
971
  }
@@ -992,19 +990,17 @@ import UIKit
992
990
  request.validate().responseDecodable(of: SetChannelDec.self) { response in
993
991
  switch response.result {
994
992
  case .success:
995
- if let status = response.value?.status {
996
- setChannel.status = status
997
- }
998
- if let error = response.value?.error {
999
- setChannel.error = error
1000
- }
1001
- if let message = response.value?.message {
1002
- setChannel.message = message
993
+ if let responseValue = response.value {
994
+ if let error = responseValue.error {
995
+ setChannel.error = error
996
+ } else {
997
+ setChannel.status = responseValue.status ?? ""
998
+ setChannel.message = responseValue.message ?? ""
999
+ }
1003
1000
  }
1004
1001
  case let .failure(error):
1005
- self.logger.error("Error set Channel \(response.value.debugDescription) \(error)")
1006
- setChannel.message = "Error set Channel \(String(describing: response.value))"
1007
- setChannel.error = "response_error"
1002
+ self.logger.error("Error set Channel \(error)")
1003
+ setChannel.error = "Request failed: \(error.localizedDescription)"
1008
1004
  }
1009
1005
  semaphore.signal()
1010
1006
  }
@@ -1030,20 +1026,15 @@ import UIKit
1030
1026
  }
1031
1027
  switch response.result {
1032
1028
  case .success:
1033
- if let status = response.value?.status {
1034
- getChannel.status = status
1035
- }
1036
- if let error = response.value?.error {
1037
- getChannel.error = error
1038
- }
1039
- if let message = response.value?.message {
1040
- getChannel.message = message
1041
- }
1042
- if let channel = response.value?.channel {
1043
- getChannel.channel = channel
1044
- }
1045
- if let allowSet = response.value?.allowSet {
1046
- getChannel.allowSet = allowSet
1029
+ if let responseValue = response.value {
1030
+ if let error = responseValue.error {
1031
+ getChannel.error = error
1032
+ } else {
1033
+ getChannel.status = responseValue.status ?? ""
1034
+ getChannel.message = responseValue.message ?? ""
1035
+ getChannel.channel = responseValue.channel ?? ""
1036
+ getChannel.allowSet = responseValue.allowSet ?? true
1037
+ }
1047
1038
  }
1048
1039
  case let .failure(error):
1049
1040
  if let data = response.data, let bodyString = String(data: data, encoding: .utf8) {
@@ -1054,15 +1045,81 @@ import UIKit
1054
1045
  }
1055
1046
  }
1056
1047
 
1057
- self.logger.error("Error get Channel \(response.value.debugDescription) \(error)")
1058
- getChannel.message = "Error get Channel \(String(describing: response.value)))"
1059
- getChannel.error = "response_error"
1048
+ self.logger.error("Error get Channel \(error)")
1049
+ getChannel.error = "Request failed: \(error.localizedDescription)"
1060
1050
  }
1061
1051
  }
1062
1052
  semaphore.wait()
1063
1053
  return getChannel
1064
1054
  }
1065
1055
 
1056
+ func listChannels() -> ListChannels {
1057
+ let listChannels: ListChannels = ListChannels()
1058
+ if (self.channelUrl).isEmpty {
1059
+ logger.error("Channel URL is not set")
1060
+ listChannels.error = "Channel URL is not set"
1061
+ return listChannels
1062
+ }
1063
+
1064
+ let semaphore: DispatchSemaphore = DispatchSemaphore(value: 0)
1065
+
1066
+ // Auto-detect values
1067
+ let appId = self.appId
1068
+ let platform = "ios"
1069
+ let isEmulator = self.isEmulator()
1070
+ let isProd = self.isProd()
1071
+
1072
+ // Create query parameters
1073
+ var urlComponents = URLComponents(string: self.channelUrl)
1074
+ urlComponents?.queryItems = [
1075
+ URLQueryItem(name: "app_id", value: appId),
1076
+ URLQueryItem(name: "platform", value: platform),
1077
+ URLQueryItem(name: "is_emulator", value: String(isEmulator)),
1078
+ URLQueryItem(name: "is_prod", value: String(isProd))
1079
+ ]
1080
+
1081
+ guard let url = urlComponents?.url else {
1082
+ logger.error("Invalid channel URL")
1083
+ listChannels.error = "Invalid channel URL"
1084
+ return listChannels
1085
+ }
1086
+
1087
+ let request = AF.request(url, method: .get, requestModifier: { $0.timeoutInterval = self.timeout })
1088
+
1089
+ request.validate().responseDecodable(of: ListChannelsDec.self) { response in
1090
+ defer {
1091
+ semaphore.signal()
1092
+ }
1093
+ switch response.result {
1094
+ case .success:
1095
+ if let responseValue = response.value {
1096
+ // Check for server-side errors
1097
+ if let error = responseValue.error {
1098
+ listChannels.error = error
1099
+ return
1100
+ }
1101
+
1102
+ // Backend returns direct array, so channels should be populated by our custom decoder
1103
+ if let channels = responseValue.channels {
1104
+ listChannels.channels = channels.map { channel in
1105
+ var channelDict: [String: Any] = [:]
1106
+ channelDict["id"] = channel.id ?? ""
1107
+ channelDict["name"] = channel.name ?? ""
1108
+ channelDict["public"] = channel.public ?? false
1109
+ channelDict["allow_self_set"] = channel.allow_self_set ?? false
1110
+ return channelDict
1111
+ }
1112
+ }
1113
+ }
1114
+ case let .failure(error):
1115
+ self.logger.error("Error list channels \(error)")
1116
+ listChannels.error = "Request failed: \(error.localizedDescription)"
1117
+ }
1118
+ }
1119
+ semaphore.wait()
1120
+ return listChannels
1121
+ }
1122
+
1066
1123
  private let operationQueue = OperationQueue()
1067
1124
 
1068
1125
  func sendStats(action: String, versionName: String? = nil, oldVersionName: String? = "") {
@@ -67,6 +67,51 @@ extension GetChannel {
67
67
  return dict
68
68
  }
69
69
  }
70
+ struct ChannelInfo: Codable {
71
+ let id: String?
72
+ let name: String?
73
+ let `public`: Bool?
74
+ let allow_self_set: Bool?
75
+ }
76
+ struct ListChannelsDec: Decodable {
77
+ let channels: [ChannelInfo]?
78
+ let error: String?
79
+
80
+ init(from decoder: Decoder) throws {
81
+ let container = try decoder.singleValueContainer()
82
+
83
+ if let channelsArray = try? container.decode([ChannelInfo].self) {
84
+ // Backend returns direct array
85
+ self.channels = channelsArray
86
+ self.error = nil
87
+ } else {
88
+ // Handle error response
89
+ let errorContainer = try decoder.container(keyedBy: CodingKeys.self)
90
+ self.channels = nil
91
+ self.error = try? errorContainer.decode(String.self, forKey: .error)
92
+ }
93
+ }
94
+
95
+ private enum CodingKeys: String, CodingKey {
96
+ case error
97
+ }
98
+ }
99
+ public class ListChannels: NSObject {
100
+ var channels: [[String: Any]] = []
101
+ var error: String = ""
102
+ }
103
+ extension ListChannels {
104
+ func toDict() -> [String: Any] {
105
+ var dict: [String: Any] = [String: Any]()
106
+ let otherSelf: Mirror = Mirror(reflecting: self)
107
+ for child: Mirror.Child in otherSelf.children {
108
+ if let key: String = child.label {
109
+ dict[key] = child.value
110
+ }
111
+ }
112
+ return dict
113
+ }
114
+ }
70
115
  struct InfoObject: Codable {
71
116
  let platform: String?
72
117
  let device_id: String?
@@ -134,7 +134,7 @@ public class Logger {
134
134
  withTag tag: String,
135
135
  config: InstanceConfiguration? = nil,
136
136
  options: Options? = nil
137
- ) {
137
+ ) {
138
138
  self.tag = tag
139
139
  if let config = config {
140
140
  // The logger plugin's name is LoggerBridge, we want to look at the config
@@ -0,0 +1,112 @@
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
+ import UIKit
8
+ import Capacitor
9
+
10
+ extension UIApplication {
11
+ public class func topViewController(_ base: UIViewController? = UIApplication.shared.windows.first?.rootViewController) -> UIViewController? {
12
+ if let nav = base as? UINavigationController {
13
+ return topViewController(nav.visibleViewController)
14
+ }
15
+ if let tab = base as? UITabBarController, let selected = tab.selectedViewController {
16
+ return topViewController(selected)
17
+ }
18
+ if let presented = base?.presentedViewController {
19
+ return topViewController(presented)
20
+ }
21
+ return base
22
+ }
23
+ }
24
+
25
+ extension UIWindow {
26
+ override open func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
27
+ if motion == .motionShake {
28
+ // Find the CapacitorUpdaterPlugin instance
29
+ guard let bridge = (rootViewController as? CAPBridgeProtocol),
30
+ let plugin = bridge.plugin(withName: "CapacitorUpdaterPlugin") as? CapacitorUpdaterPlugin else {
31
+ return
32
+ }
33
+
34
+ // Check if shake menu is enabled
35
+ if !plugin.shakeMenuEnabled {
36
+ return
37
+ }
38
+
39
+ showShakeMenu(plugin: plugin, bridge: bridge)
40
+ }
41
+ }
42
+
43
+ private func showShakeMenu(plugin: CapacitorUpdaterPlugin, bridge: CAPBridgeProtocol) {
44
+ // Prevent multiple alerts from showing
45
+ if let topVC = UIApplication.topViewController(),
46
+ topVC.isKind(of: UIAlertController.self) {
47
+ plugin.logger.info("UIAlertController is already presented")
48
+ return
49
+ }
50
+
51
+ let appName = Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String ?? "App"
52
+ let title = "Preview \(appName) Menu"
53
+ let message = "What would you like to do?"
54
+ let okButtonTitle = "Go Home"
55
+ let reloadButtonTitle = "Reload app"
56
+ let cancelButtonTitle = "Close menu"
57
+
58
+ let updater = plugin.implementation
59
+
60
+ func resetBuiltin() {
61
+ updater.reset()
62
+ bridge.setServerBasePath("")
63
+ DispatchQueue.main.async {
64
+ if let vc = (self.rootViewController as? CAPBridgeViewController) {
65
+ vc.loadView()
66
+ vc.viewDidLoad()
67
+ }
68
+ _ = updater.delete(id: updater.getCurrentBundleId())
69
+ plugin.logger.info("Reset to builtin version")
70
+ }
71
+ }
72
+
73
+ let bundleId = updater.getCurrentBundleId()
74
+ if let vc = (self.rootViewController as? CAPBridgeViewController) {
75
+ plugin.logger.info("getServerBasePath: \(vc.getServerBasePath())")
76
+ }
77
+ plugin.logger.info("bundleId: \(bundleId)")
78
+
79
+ let alertShake = UIAlertController(title: title, message: message, preferredStyle: .alert)
80
+
81
+ alertShake.addAction(UIAlertAction(title: okButtonTitle, style: .default) { _ in
82
+ guard let next = updater.getNextBundle() else {
83
+ resetBuiltin()
84
+ return
85
+ }
86
+ if !next.isBuiltin() {
87
+ plugin.logger.info("Resetting to: \(next.toString())")
88
+ _ = updater.set(bundle: next)
89
+ let destHot = updater.getBundleDirectory(id: next.getId())
90
+ plugin.logger.info("Reloading \(next.toString())")
91
+ bridge.setServerBasePath(destHot.path)
92
+ } else {
93
+ resetBuiltin()
94
+ }
95
+ plugin.logger.info("Reload app done")
96
+ })
97
+
98
+ alertShake.addAction(UIAlertAction(title: cancelButtonTitle, style: .default))
99
+
100
+ alertShake.addAction(UIAlertAction(title: reloadButtonTitle, style: .default) { _ in
101
+ DispatchQueue.main.async {
102
+ bridge.webView?.reload()
103
+ }
104
+ })
105
+
106
+ DispatchQueue.main.async {
107
+ if let topVC = UIApplication.topViewController() {
108
+ topVC.present(alertShake, animated: true)
109
+ }
110
+ }
111
+ }
112
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-updater",
3
- "version": "7.3.3",
3
+ "version": "7.5.1",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Live update for capacitor apps",
6
6
  "main": "dist/plugin.cjs.js",