@craft-native/ios 0.0.214 → 0.0.215

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/README.md CHANGED
@@ -192,6 +192,14 @@ wrong screen. `systemtap` targets the system button around a Live Activity rathe
192
192
  than its remotely hosted text. The [Live Activity layout fixture](./fixtures/live-activity)
193
193
  exercises long names and timer alignment using the production widget.
194
194
 
195
+ Use `universallink https://example.com/profile` to test an associated HTTPS
196
+ link after a fresh install. The driver host uses Apple's public
197
+ `universalLinksOnly` option and waits up to 60 seconds for iOS to accept the
198
+ association downloaded from Apple's CDN. A rejected association fails the
199
+ journey; it cannot fall back to Safari. This operation does not launch the app
200
+ under test directly, so a preceding `terminate` still tests a cold handoff.
201
+ Use `openurl` for browser fallback checks and custom URL schemes.
202
+
195
203
  The iOS host uses the shared tree-layout ABI for eligible definite-size,
196
204
  non-grid, non-wrapped containers and retains a local fallback for older
197
205
  runtimes or unsupported styles. Both paths implement wrapped-line and grid
package/dist/index.js CHANGED
@@ -156,8 +156,11 @@ function serializeSimulatorSteps(steps) {
156
156
  }
157
157
  } else if ("name" in step)
158
158
  arg = token(step.name);
159
- else if ("url" in step)
159
+ else if ("url" in step) {
160
+ if (step.command === "universallink" && new URL(step.url).protocol !== "https:")
161
+ throw new Error("Universal Links require an HTTPS URL");
160
162
  arg = step.url;
163
+ }
161
164
  if (/[\r\n]/.test(arg))
162
165
  throw new Error("Simulator arguments cannot contain newlines");
163
166
  return `${step.command}${arg ? ` ${arg}` : ""}`;
package/dist/testing.d.ts CHANGED
@@ -60,6 +60,11 @@ export type SimulatorStep = {
60
60
  command: 'openurl';
61
61
  url: string;
62
62
  }
63
+ /** Use Apple's universalLinksOnly API, allowing association downloads up to 60 seconds. */
64
+ | {
65
+ command: 'universallink';
66
+ url: string;
67
+ }
63
68
  /** Runs `step` only when the element with this identifier is there (a screen shown the first time). */
64
69
  | {
65
70
  command: 'ifid';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@craft-native/ios",
3
- "version": "0.0.214",
3
+ "version": "0.0.215",
4
4
  "homepage": "https://github.com/craft-native/craft/tree/main/packages/ios#readme",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,6 +14,7 @@ import XCTest
14
14
  /// delay <ms> every proxied request waits this long (0 = off)
15
15
  /// exec <hook> runs the switch's HOOKS/<hook>.sh on the Mac (restart the API, …)
16
16
  /// openurl <url> opens a link through the system, answering "Open in the app?"
17
+ /// universallink <https-url> waits up to 60s for an OS-verified link; never opens a browser
17
18
  /// shot <name> screenshot → shots/<name>.png
18
19
  /// tree <name> accessibility tree → shots/<name>.txt
19
20
  /// tap <text> first hittable element whose label contains text
@@ -253,6 +254,21 @@ final class DriverTests: XCTestCase {
253
254
  answerOpenPrompt()
254
255
  note("openurl \(arg)")
255
256
  }
257
+ case "universallink":
258
+ guard let url = URL(string: arg), url.scheme == "https" else {
259
+ check(false, "universallink requires an HTTPS URL")
260
+ return
261
+ }
262
+ let host = XCUIApplication(bundleIdentifier: "{{BUNDLE_PREFIX}}.host")
263
+ host.launchArguments = ["--craft-universal-link", url.absoluteString]
264
+ host.launch()
265
+ let opened = app.wait(for: .runningForeground, timeout: 75)
266
+ if !opened {
267
+ post("/save?name=universal-link-host.txt", Data(host.debugDescription.utf8))
268
+ post("/save?name=universal-link-app.txt", Data(app.debugDescription.utf8))
269
+ }
270
+ check(opened, "universallink \(arg) opened the target app")
271
+ host.terminate()
256
272
  case "shot":
257
273
  let shot = XCUIScreen.main.screenshot()
258
274
  post("/save?name=\(arg).png", shot.pngRepresentation)
@@ -1,6 +1,36 @@
1
1
  import SwiftUI
2
+ import UIKit
2
3
 
3
4
  @main
4
5
  struct HostApp: App {
5
- var body: some Scene { WindowGroup { Text("Craft simulator driver") } }
6
+ @State private var status = "Craft simulator driver"
7
+
8
+ var body: some Scene {
9
+ WindowGroup {
10
+ Text(status).accessibilityIdentifier("craft-driver-status")
11
+ .task { await openUniversalLinkIfRequested() }
12
+ }
13
+ }
14
+
15
+ @MainActor
16
+ private func openUniversalLinkIfRequested() async {
17
+ let arguments = ProcessInfo.processInfo.arguments
18
+ guard let index = arguments.firstIndex(of: "--craft-universal-link"),
19
+ arguments.indices.contains(index + 1),
20
+ let url = URL(string: arguments[index + 1]), url.scheme == "https" else { return }
21
+ // Installation returns before iOS finishes downloading the AASA from
22
+ // Apple's CDN. Ask the public API until the OS accepts the association;
23
+ // universalLinksOnly prevents a failed attempt from opening Safari.
24
+ let deadline = Date().addingTimeInterval(60)
25
+ while Date() < deadline && !Task.isCancelled {
26
+ let opened = await UIApplication.shared.open(url, options: [.universalLinksOnly: true])
27
+ if opened {
28
+ status = "Universal Link accepted"
29
+ return
30
+ }
31
+ status = "Waiting for Universal Link association"
32
+ try? await Task.sleep(nanoseconds: 1_000_000_000)
33
+ }
34
+ status = "Universal Link was not accepted within 60 seconds"
35
+ }
6
36
  }