ruvector/examples/app-clip/Sources/AppClip/AppClipApp.swift
Claude 701c93f45a feat(app-clip): add Swift App Clip skeleton for RVQS QR seed decoding
Minimal iOS App Clip template that bridges into the RVF C FFI to
decode QR cognitive seeds. Includes SPM package config linking
librvf_runtime.a, a C header mirroring ffi.rs exports (rvqs_parse_header,
rvqs_verify_signature, rvqs_verify_content_hash, rvqs_decompress_microkernel,
rvqs_get_primary_host_url), a Swift SeedDecoder wrapper with proper memory
management, and a SwiftUI view with QR scanner placeholder and decoded
seed info display.

https://claude.ai/code/session_01RnwD4x5cbpB7FPvoyYQz8G
2026-02-15 18:34:13 +00:00

73 lines
2.4 KiB
Swift

// AppClipApp.swift Entry point for the RVF App Clip.
//
// This is a minimal SwiftUI App Clip that scans QR cognitive seeds
// and decodes them using the RVF C FFI. Designed to stay under the
// 15 MB App Clip size limit per Apple guidelines.
//
// App Clip invocation URL scheme:
// https://rvf.example.com/seed?id=<file_id>
//
// The App Clip can be invoked by:
// 1. Scanning an RVQS QR code directly (camera flow)
// 2. Tapping an App Clip Code / NFC tag
// 3. Opening a Smart App Banner link
import SwiftUI
@main
struct AppClipApp: App {
@StateObject private var appState = AppClipState()
var body: some Scene {
WindowGroup {
AppClipView()
.onContinueUserActivity(
NSUserActivityTypeBrowsingWeb,
perform: handleUserActivity
)
.environmentObject(appState)
}
}
/// Handle App Clip invocation via URL.
///
/// When the App Clip is launched from a Smart App Banner or App Clip Code,
/// iOS delivers the invocation URL as a user activity. We extract the
/// seed identifier and trigger a download + decode flow.
private func handleUserActivity(_ activity: NSUserActivity) {
guard let url = activity.webpageURL else { return }
appState.handleInvocationURL(url)
}
}
// MARK: - AppClipState
/// Shared state for App Clip lifecycle and invocation handling.
@MainActor
final class AppClipState: ObservableObject {
/// The invocation URL that launched this App Clip (if any).
@Published var invocationURL: URL?
/// Handle an App Clip invocation URL.
///
/// Extracts the seed ID from the URL query parameters and could
/// trigger a network fetch for the seed payload.
func handleInvocationURL(_ url: URL) {
invocationURL = url
// Extract seed ID from query parameters.
// Example: https://rvf.example.com/seed?id=0102030405060708
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
let seedIDParam = components.queryItems?.first(where: { $0.name == "id" }),
let _ = seedIDParam.value
else {
return
}
// In production:
// 1. Fetch the seed payload from the CDN using the seed ID.
// 2. Pass the raw bytes to SeedDecoder.decode(data:).
// 3. Begin progressive download of the full RVF file.
}
}