Using Unlock With Tap
This feature enables your app to perform unlock operations using mobile credentials.
Unlocking with SeamSDK uses proximity to communicate credentials to door readers. When a user initiates an unlock, the SDK performs scanning, error handling, and unlock events using Seam.shared.unlock(using:)
.
Using this process involves the following steps:
Retrieve available mobile credentials.
Monitor for permission or credential errors. Unhandled errors are thrown as
credentialErrors([SeamCredentialError])
.Perform the unlock operation.
Handle unlock status events.
Cancel the unlock operation if needed.
1. Retrieve Mobile Credentials
Access the current credentials through the published credentials
array on Seam.shared
:
import SeamSDK
import Combine
// Access credentials
let credentials = Seam.shared.credentials
// Observe updates with Combine
let credentialsSubscription = Seam.shared.$credentials
.sink { creds in
// Update UI with new credentials array.
}
2. Monitor Credential Errors
Permission or setup issues appear in each credential’s errors
property. Observe like this:
import SeamSDK
import Combine
let errorSubscription = Seam.shared.$credentials
.flatMap { creds in creds.publisher }
.map { $0.errors }
.sink { errors in
// Handle errors, for example, `.userInteractionRequired`, `.expired`, etc.
}
Note: The
.errors
array on credentials represents per-credential issues, though some issues may be repeated across several credentials (for example, bluetooth requirements). SDK- or credential-level errors (such as invalid token or expired credential) are thrown directly by methods likeunlock(using:)
becauseSeamError
orSeamCredentialError
and must be handled throughdo/catch
.
3. Perform Unlock Operation
The call to Seam.shared.unlock(using:)
may throw:
SeamError
: For SDK-level issues (for example, invalid token, uninitialized SDK).SeamCredentialError
: For credential-specific issues (for example, expired credential, device not eligible). Ensure that you wrap the call indo/catch
blocks to handle these errors.
Use Async/Await or Combine to initiate an unlock with a selected credential:
import SeamSDK
import Combine
let credentialId = credentials.first!.id
// Async/Await example
Task {
do {
for try await event in try Seam.shared.unlock(using: credentialId).values {
switch event {
case .grantedAccess:
// The lock granted access. Show a success indicator.
default:
print("Unlock event: \(event)")
// Access wasn't granted. Inform the user and offer retry.
}
}
} catch {
// Handle unlock error, for example, invalid credential or SDK error
print("Unlock error: \(error)")
}
}
// Combine example
do {
let unlockPublisher = try Seam.shared.unlock(using: credentialId)
let unlockSubscription = unlockPublisher.sink(
receiveCompletion: { _ in
// Unlock completed.
},
receiveValue: { event in
switch event {
case .grantedAccess:
// The lock granted access—show a success indicator.
default:
// Access wasn't granted, inform the user and offer retry.
print("Unlock event: \(event)")
}
}
)
// Retain `unlockSubscription`; discarding it will cancel the unlock attempt.
} catch {
// Handle unlock initialization error.
print("Unlock error: \(error)")
}
4. Handle Unlock Events
Handle each SeamUnlockEvent
to update your UI and logic. Available events:
launched Unlock operation has started.
grantedAccess Access was granted by the lock.
timedOut Unlock operation timed out without success.
connectionFailed(debugDescription:) Unlock operation failed to connect;
debugDescription
may contain additional details.
Async/Await example:
Task {
do {
for try await event in Seam.shared.unlock(using: credentialID) {
switch event {
case .launched:
// Show scanning indicator.
case .grantedAccess:
// Show access granted.
case .timedOut:
// Show timeout and offer retry.
case .connectionFailed(let debugDescription):
// Show error with debugDescription.
}
}
} catch {
// Handle thrown errors.
}
}
Combine example:
do {
let unlockPublisher = try Seam.shared.unlock(using: credentialID)
let unlockSubscription = unlockPublisher
.receive(on: RunLoop.main)
.sink(
receiveCompletion: { _ in
// unlock completed.
},
receiveValue: { event in
switch event {
case .launched:
// Show scanning indicator.
case .grantedAccess:
// Show success indicator.
case .timedOut:
// Operation timed out—offer retry.
case .connectionFailed(let debugDescription):
// Show debugDescription details.
}
}
)
// Retain `unlockSubscription` as a property and cancel when appropriate (for example, in deinit or viewWillDisappear).
} catch {
// Handle unlock initialization error.
print("Unlock initialization error: \(error)")
}
5. Cancel the Unlock Operation
Stop scanning by cancelling your subscription or task:
// For Combine
unlockSubscription.cancel()
// For Async/Await, cancel the Task as needed.
Last updated
Was this helpful?