How to build mDocs proximity presentation capabilities into my iOS application
This guide offers step-by-step instructions for using the iOS mDocs holder SDK to build the capability to present an mDoc for verification via a proximity presentation workflow as per ISO/IEC 18013-5.
If you are unfamiliar with this presentation workflow, the corresponding tutorial might be a better starting point as it offers more context and a high level overview of the user experience.
Prerequisites
- Access to the SDK’s GitHub distribution repository. Refer to the getting started guide for more information.
Access requires an SSH key associated with the GitHub user who has access to the distribution repo. Please contact us if you are having trouble with setting this up.
Overview
This guide comprises the following steps:
- Setup your project.
- Create a QR code.
- Receive and handle a presentation request.
- Send matching mDocs to the verifier.
Setup your project
- Install the SDK.
- Add Bluetooth and Biometric permissions to your application.
Initialize the SDK
- Create a new variable:
var mobileCredentialHolder: MobileCredentialHolder
- Initialize the SDK by creating a new instance of the
MobileCredentialHolder
class and calling itsinitialize
function:
mobileCredentialHolder = MobileCredentialHolder.shared
try mobileCredentialHolder.initialize()
Create a QR code
- Create a new UI element to enable the user to request creating a QR code.
- Call the
ProximityPresentationSession
function when the user requests creating a QR code.
func createQRCode() {
Task { @MainActor in
do {
presentationSession = try await mobileCredentialHolder.createProximityPresentationSession(
onRequestReceived: onRequestReceived(_:error:)
)
qrCode = presentationSession?.deviceEngagement
} catch {
print(error)
}
}
}
The function returns a
ProximityPresentationSession
which includes a deviceEngagement
string:
"mdoc:owBjMS4wAYIB2BhYS6QBAiABIVgghaBYJe7KSqcEolhmnIJaYJ2AIevkKbEy5xP7tkwlqAwiWCAMGCGe6uFI2hKeghb59h_K4hPV-Ldq6vnaxsRiySMH9gKBgwIBowD0AfULUKRoj0ZH60Qco-m0k97qRSQ"
- Convert the
deviceEngagement
string into a QR code and create a new view to display it:
var qrCodeView: some View {
ZStack {
if let imageData = generateQRCode(data: viewModel.qrCode?.data(using: .utf8) ?? Data()),
let image = UIImage(data: imageData) {
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fit)
}
}
}
func generateQRCode(data: Data) -> Data? {
guard let filter = CIFilter(name: "CIQRCodeGenerator") else { return nil }
filter.setValue(data, forKey: "inputMessage")
guard let ciimage = filter.outputImage else { return nil }
let transform = CGAffineTransform(scaleX: 10, y: 10)
let scaledCIImage = ciimage.transformed(by: transform)
let uiimage = UIImage(ciImage: scaledCIImage)
return uiimage.pngData()
}
Once the SDK receives a presentation request from the verifier, it looks for any matching mDocs stored in the wallet.
Respond to a presentation request
- Handle the
onRequestReceived
event of thecreateProximityPresentationSession
function by presenting matching credentials to the user, and add a UI element for providing consent to sharing them with the verifier:
@State var selectedCredential: String?
...
@Published var requestedDocuments: [(request: MobileCredentialRequest,
matchedMobileCredentials: [MobileCredentialMetadata])]? = nil
...
if viewModel.requestedDocuments != nil {
let matchedCredentials = viewModel.requestedDocuments![0].matchedMobileCredentials
List(selection: $selectedCredential) {
Section(header: Text("Requested Document")) {
Text("\(viewModel.requestedDocuments![0].request.docType)")
}
Section(header: Text("Please select matching document to present")) {
ForEach(matchedCredentials, id: \.id) { credential in
Text(credential.docType)
}
}
}
if let selectedCredential {
Button {
viewModel.sendResponse(selectedCredential)
} label: {
Text("Send Response")
}
}
}
...
func sendResponse(_ id: String) {
Task { @MainActor in
do {
try await presentationSession?.sendResponse(credentialIds: [id], terminateSession: true)
} catch {
print(error)
}
}
}