SwiftUI iOS中如何在扫码函数中获取URL Scheme传递的jobcode参数
问题
我开发了一个通过URL Scheme从网站启动的简易扫码程序,可扫描条形码并携带扫码数据返回浏览器,功能运行正常。但现在需要向APP传递jobcode参数,让扫码成功后打开网站对应的特定Job页面。
网站启动链接格式:MyNewApp://open-job?jobcode=1234
目前已在ContentView中成功获取到jobcode参数,但需要在扫码成功的回调函数中使用它,拼接到返回网站的URL里。尝试过在View中存储jobcode并从那里启动浏览器,但出现无法启动浏览器的错误。已经编写了handleIncomingURL函数,但还没找到让扫码函数读取传入URL Scheme参数的方法,试过修改Scheme、添加启动参数,也见过AppDelegate的实现方案,但因为用的是SwiftUI,现在有些困惑。
扫码回调函数代码:
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { // Check if the metadataObjects array is not nil and it contains at least one object. if metadataObjects.count == 0 { scanResult = "No bar code detected" return } // Get the metadata object. let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject if metadataObj.type == AVMetadataObject.ObjectType.code39, let result = metadataObj.stringValue { scanResult = result print(scanResult) let theurl = String("https://backtomywebsite.com/jobdetails.php?source=app&vin=" + scanResult) if let link = URL(string: theurl) { UIApplication.shared.open(link) } } }
handleIncomingURL函数代码:
private func handleIncomingURL(_ url: URL) { guard url.scheme == "MyNewApp" else { return } guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else { print("Invalid URL") return } guard let action = components.host, action == "open-job" else { print("Unknown URL, we can't handle this one!") return } guard let myjobcode = components.queryItems?.first(where: { $0.name == "jobcode" })?.value else { print("Job not found") return } openJobcode = myjobcode }
请问如何在扫码成功的回调函数中获取jobcode参数并拼接到返回的URL中?
解决方案
1. 用ObservableObject共享jobcode状态
SwiftUI中View和扫码回调类需要共享数据,用ObservableObject做全局状态管理器是最稳妥的方式:
import Foundation import SwiftUI class AppState: ObservableObject { @Published var jobcode: String? }
在App入口注入这个状态,并处理URL Scheme跳转:
@main struct MyNewApp: App { @StateObject private var appState = AppState() var body: some Scene { WindowGroup { ContentView() .environmentObject(appState) } .onOpenURL { url in handleIncomingURL(url) } } private func handleIncomingURL(_ url: URL) { guard url.scheme == "MyNewApp", let components = URLComponents(url: url, resolvingAgainstBaseURL: true), components.host == "open-job", let jobcode = components.queryItems?.first(where: { $0.name == "jobcode" })?.value else { print("Invalid URL or missing jobcode") return } appState.jobcode = jobcode } }
2. 在扫码类中持有AppState引用
假设扫码逻辑封装在ScannerManager类中,初始化时传入AppState,这样回调就能直接访问jobcode:
class ScannerManager: NSObject, AVCaptureMetadataOutputObjectsDelegate { @Published var scanResult: String = "" private let appState: AppState init(appState: AppState) { self.appState = appState super.init() // 这里初始化你的AVCaptureSession等扫码逻辑 } func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { guard !metadataObjects.isEmpty, let metadataObj = metadataObjects[0] as? AVMetadataMachineReadableCodeObject, metadataObj.type == .code39, let result = metadataObj.stringValue else { scanResult = "No bar code detected" return } scanResult = result print(scanResult) // 拼接jobcode到目标URL var urlComponents = URLComponents(string: "https://backtomywebsite.com/jobdetails.php")! urlComponents.queryItems = [ URLQueryItem(name: "source", value: "app"), URLQueryItem(name: "vin", value: result), URLQueryItem(name: "jobcode", value: appState.jobcode) ] // 必须在主线程调用open方法 if let link = urlComponents.url { DispatchQueue.main.async { UIApplication.shared.open(link) } } } }
3. 在ContentView中关联状态和扫码管理器
struct ContentView: View { @EnvironmentObject private var appState: AppState @StateObject private var scannerManager: ScannerManager init() { _scannerManager = StateObject(wrappedValue: ScannerManager(appState: AppState())) } var body: some View { // 你的扫码UI布局,比如预览画面、结果文本 Text("扫描结果:\(scannerManager.scanResult)") } }
关键注意事项
- 扫码回调会在后台线程触发,必须用
DispatchQueue.main.async包裹UIApplication.shared.open,否则会报错无法启动浏览器。 - 确保
AppState是全局唯一实例,通过@StateObject和environmentObject注入,避免多实例导致数据不一致。 - 把URL Scheme的处理逻辑移到App的
onOpenURL回调中,更符合SwiftUI的生命周期管理。
内容的提问来源于stack exchange,提问作者Mike Crane
相关产品推荐
相关产品推荐

