craft-native 0.0.220 → 0.0.221

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.
package/dist/cli.js CHANGED
@@ -3424,7 +3424,7 @@ function pinCraftNativeDependency(packagePath, craftVersion) {
3424
3424
  `);
3425
3425
  }
3426
3426
  // package.json
3427
- var version = "0.0.220";
3427
+ var version = "0.0.221";
3428
3428
 
3429
3429
  // bin/cli.ts
3430
3430
  var spawnedFrom = process6.env[CRAFT_CLI_SPAWN_MARKER];
package/dist/index.cjs CHANGED
@@ -309,7 +309,7 @@ function craftBinaryNotFoundMessage(triedPath) {
309
309
  `);
310
310
  }
311
311
  // package.json
312
- var version = "0.0.220";
312
+ var version = "0.0.221";
313
313
 
314
314
  // src/sdk-version.ts
315
315
  var SDK_VERSION = version;
package/dist/index.js CHANGED
@@ -57,7 +57,7 @@ function craftBinaryNotFoundMessage(triedPath) {
57
57
  `);
58
58
  }
59
59
  // package.json
60
- var version = "0.0.220";
60
+ var version = "0.0.221";
61
61
 
62
62
  // src/sdk-version.ts
63
63
  var SDK_VERSION = version;
@@ -1105,23 +1105,58 @@ struct CraftSplashView: View {
1105
1105
  }
1106
1106
 
1107
1107
  // MARK: - Deep Link Manager
1108
+ /// Launch intent settles when UIKit delivers its URL or completes activation,
1109
+ /// independently of when a page or native screen registers its listeners.
1110
+ final class CraftInitialLinkState {
1111
+ private(set) var url: URL?
1112
+ private(set) var settled = false
1113
+ private var readers: [(URL?) -> Void] = []
1114
+
1115
+ func receive(_ url: URL) {
1116
+ guard !settled else { return }
1117
+ self.url = url
1118
+ settle()
1119
+ }
1120
+
1121
+ func settle() {
1122
+ guard !settled else { return }
1123
+ settled = true
1124
+ let waiting = readers
1125
+ readers.removeAll()
1126
+ for reader in waiting { reader(url) }
1127
+ }
1128
+
1129
+ func resolve(_ completion: @escaping (URL?) -> Void) {
1130
+ if settled { completion(url) }
1131
+ else { readers.append(completion) }
1132
+ }
1133
+ }
1134
+
1108
1135
  class DeepLinkManager {
1109
1136
  static let shared = DeepLinkManager()
1110
1137
 
1111
- private var initialURL: URL?
1138
+ private let launch = CraftInitialLinkState()
1139
+ private var initialURL: URL? { launch.url }
1140
+ private var activationObservers: [NSObjectProtocol] = []
1112
1141
  // Every link that arrived while no page could receive it, in order. This
1113
1142
  // was a single slot, so a second link before the bridge was ready replaced
1114
1143
  // the first; on a cold start, that could be the link that launched the app.
1115
1144
  private var pendingURLs: [URL] = []
1116
1145
  private weak var webView: WKWebView?
1117
1146
  private var isReady = false
1118
- // Whether a page has ever become ready. A link that arrives before that is
1119
- // the one the app was opened with; a link that arrives later is not, and
1120
- // is no answer to getInitialURL.
1147
+ // Replay bookkeeping only. A native screen can become ready before UIKit
1148
+ // delivers the launch URL; listener readiness cannot classify that URL.
1121
1149
  private var hasBeenReady = false
1122
1150
  private var nativeListeners: [UUID: (URL, Bool) -> Void] = [:]
1123
1151
 
1124
- private init() {}
1152
+ private init() {
1153
+ for name in [UIApplication.didBecomeActiveNotification, UIApplication.didEnterBackgroundNotification] {
1154
+ activationObservers.append(NotificationCenter.default.addObserver(forName: name, object: nil, queue: .main) { [weak self] _ in
1155
+ self?.launch.settle()
1156
+ })
1157
+ }
1158
+ if UIApplication.shared.applicationState == .active { launch.settle() }
1159
+ }
1125
1160
 
1126
1161
  func setWebView(_ webView: WKWebView) {
1127
1162
  self.webView = webView
@@ -1146,9 +1181,7 @@ class DeepLinkManager {
1146
1181
  }
1147
1182
 
1148
1183
  func handleURL(_ url: URL) {
1149
- if initialURL == nil && !hasBeenReady {
1150
- initialURL = url
1151
- }
1184
+ launch.receive(url)
1152
1185
 
1153
1186
  // A hybrid app opens a native path's screen itself, and tells the
1154
1187
  // native screens that listen; every other link is the page's. An
@@ -1179,6 +1212,17 @@ class DeepLinkManager {
1179
1212
  return initialURL
1180
1213
  }
1181
1214
 
1215
+ /// A foreground scene can draw before SwiftUI delivers its launch activity.
1216
+ /// A headless background launch has no scene or foreground URL to await.
1217
+ func resolveInitialURL(_ completion: @escaping (URL?) -> Void) {
1218
+ let application = UIApplication.shared
1219
+ if application.applicationState == .active ||
1220
+ (application.applicationState == .background && application.connectedScenes.isEmpty) {
1221
+ launch.settle()
1222
+ }
1223
+ launch.resolve(completion)
1224
+ }
1225
+
1182
1226
  @discardableResult
1183
1227
  func addNativeListener(_ listener: @escaping (URL, Bool) -> Void) -> UUID {
1184
1228
  let token = UUID()
@@ -258,7 +258,10 @@ enum CraftNativeActions {
258
258
  sync = .success(currentAppState())
259
259
  case ("DeepLinks", "getInitialURL"):
260
260
  if config.enableDeepLinks {
261
- sync = .success(claimInitialDeepLink().map(deepLinkData) ?? NSNull())
261
+ DeepLinkManager.shared.resolveInitialURL { url in
262
+ complete(requestToken, .success(claimInitialDeepLink(url).map(deepLinkData) ?? NSNull()), completion)
263
+ }
264
+ return
262
265
  } else {
263
266
  sync = failure("CAPABILITY_DISABLED", "Deep links are disabled")
264
267
  }
@@ -809,12 +812,12 @@ enum CraftNativeActions {
809
812
  else { task.resume() }
810
813
  }
811
814
 
812
- private static func claimInitialDeepLink() -> URL? {
815
+ private static func claimInitialDeepLink(_ url: URL?) -> URL? {
813
816
  cancellationLock.lock()
814
817
  defer { cancellationLock.unlock() }
815
818
  guard !initialDeepLinkClaimed else { return nil }
816
819
  initialDeepLinkClaimed = true
817
- return DeepLinkManager.shared.getInitialURL()
820
+ return url
818
821
  }
819
822
 
820
823
  private static func complete(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "craft-native",
3
- "version": "0.0.220",
3
+ "version": "0.0.221",
4
4
  "type": "module",
5
5
  "description": "Build desktop apps with web languages - TypeScript SDK for Craft",
6
6
  "author": "Chris Breuer <chris@stacksjs.org>",