The structure for verifying an mDL is very similar to implementing the . To verify an mDL over BLE you will need to manage the BLEReaderSessionState and provide a UI for every state during the presentation process.
1. Scanning Documents
Rather than generating a QR-code, for a verifier, you will have to implement a scanning ability. For mdoc verification, you can directly use the QRCodeScanner. If you want to implement a generic scanner that can handle PDF417 VC Barcodes and Machine Readable Zones, check out this example of a .
Verify mdocs
Here, we give an example of what your VerifyMdocView could look like. You can also directly reference our implementation.
import SpruceIDMobileSdk
// An Example View for Verification of Mdocs
public struct VerifyMDocView: View {
@Binding var path: NavigationPath
@State private var scanned: String?
public var body: some View {
if scanned == nil {
QRCodeScanner(
title: "Scan QR Code",
subtitle: "Looking...",
onRead: { code in
self.scanned = code
},
onCancel: onCancel,
titleFont: .customFont(font: .inter, style: .bold, size: .h0),
subtitleFont: .customFont(font: .inter, style: .bold, size: .h4),
cancelButtonFont: .customFont(font: .inter, style: .medium, size: .h3),
readerColor: .white
)
} else {
// Define an MdocReaderView and initiate it when the code is scanned
MDocReaderView(
// Set the scanned value
uri: scanned!,
// Define the items you want to query by namespace, attribute_name
// and intent to retain:
requestedItems: ["org.iso.18013.5.1": ["given_name": true]],
// Enter an array of issuer certificates that you accept (e.g. a list of US states).
// These issuer certificates should follow the IACA profile as defined in ISO/IEC 18013-5 Annex B.
trustAnchorRegistry: [<issuer_cert>],
onCancel: onCancel,
path: $path
)
}
}
func onCancel() {
// Define what to do when a user cancels the scan
self.scanned = nil
path.removeLast()
}
}
MdocReaderView
Build the Delegate that holds the BLEReaderSessionState and the mDocReader sessionManager.
// Build out your Reader Delegate
class MDocReaderDelegate: ObservableObject {
@Published var state: BLEReaderSessionState = .advertizing
private var mdocReader: MDocReader?
init(
uri: String,
requestedItems: [String: [String: Bool]],
trustAnchorRegistry: [String]?
) {
// MdocReader is a core SpruceKit Component.
self.mdocReader = MDocReader(
callback: self,
uri: uri,
requestedItems: requestedItems,
trustAnchorRegistry: trustAnchorRegistry
)
}
func cancel() {
self.mdocReader?.cancel()
}
}
// Make sure to extend the BLEReaderSessionStateDelegate to MdocReaderDelegate
extension MDocReaderDelegate: BLEReaderSessionStateDelegate {
public func update(state: BLEReaderSessionState) {
self.state = state
}
}
Once you have your Delegate implemented, you can add it to your MdocReaderView, which manages the UI based on the SessionState.
// Build your MdocReaderView
public struct MDocReaderView: View {
@StateObject var delegate: MDocScanViewDelegate
@Binding var path: NavigationPath
var onCancel: () -> Void
init(
uri: String,
requestedItems: [String: [String: Bool]],
trustAnchorRegistry: [String]?,
onCancel: @escaping () -> Void,
path: Binding<NavigationPath>
) {
self._delegate = StateObject(
wrappedValue: MDocReaderDelegate(
uri: uri,
requestedItems: requestedItems,
trustAnchorRegistry: trustAnchorRegistry
)
)
self.onCancel = onCancel
self._path = path
}
@ViewBuilder
var cancelButton: some View {
Button("Cancel") {
self.cancel()
}
.padding(10)
.buttonStyle(.bordered)
.tint(.red)
public var body: some View {
VStack {
switch self.delegate.state {
// Manage the BLE ReaderSessionStates here
}
}
.padding(.all, 30)
.navigationBarBackButtonHidden(true)
}
func cancel() {
self.delegate.cancel()
self.onCancel()
}
}
There you have it, you now have everything you need for an mDL verification flow. You can:
Initiate a QR Code Scanner
Manage the states of the BleReaderSession with appropriate UI of your design