Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions ios/DocuSignManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,16 @@ internal final class DocuSignManager: NSObject {
}
_ = pendingResolved // silence unused-warning; kept for future telemetry

// DSMManager APIs (clearAllWebCookies, logout) must run on the main thread.
// Expo async functions are dispatched on AsyncFunctionQueue (non-main), so
// we must hop to main before touching any DSMManager API.
guard Thread.isMainThread else {
DispatchQueue.main.async { [weak self] in
self?.endSigningSession(completion: completion)
}
return
}

clearWebCookiesAsync { [weak self] in
guard let self = self else {
completion()
Expand Down Expand Up @@ -571,8 +581,10 @@ internal final class DocuSignManager: NSObject {
/// Safe to call when the SDK was never initialized: returns immediately
/// without touching DSMManager.
func reset(completion: @escaping () -> Void) {
var hadPending = false
stateQueue.sync {
if let pending = pendingCompletion {
hadPending = true
let outcome = SigningOutcome(
status: "cancelled",
envelopeId: currentEnvelopeId ?? "",
Expand All @@ -585,6 +597,23 @@ internal final class DocuSignManager: NSObject {
}
}

// Force-dismiss the captive signing modal if one is on screen. reset() is
// called on session teardown (e.g. END_CONSULTATION) which can arrive while
// the DocuSign WebView is still presented; the SDK only dismisses its own UI
// on user Finish/Cancel, so we dismiss the presented modal here. Gated on
// hadPending so an unrelated modal is never torn down.
if hadPending {
DispatchQueue.main.async {
let root = UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.flatMap { $0.windows }
.first(where: { $0.isKeyWindow })?.rootViewController
if root?.presentedViewController != nil {
root?.dismiss(animated: true)
}
}
}

let needsTeardown = stateQueue.sync { _isInitialized || _hasLoggedIn }
guard needsTeardown else {
completion()
Expand Down