You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 20:58:19