I am working on passkey authentication and trying to get a return values from my ViewController native code to my JS code using Capacitor. How can I get the value from ViewController and return it to my JS after dispatch bridge?
SamplePlugin.swift - to be called from JS
import Foundation
import Capacitor
@objc(SamplePlugin)
public class SamplePlugin: CAPPlugin {
@objc func someFunction(_ call: CAPPluginCall) {
let value = call.getString("value") ?? ""
let value2 = call.getString("value2") ?? ""
let challenge: Data? = call.getString("challenge")!.data(using: .utf8)
DispatchQueue.main.async {
let signInViewController = SignInViewController(challenge: challenge!)
self.bridge?.viewController?.present(signInViewController, animated: true, completion: nil)
}
// I want to return some value from SignInViewController to JS Code
call.resolve(["value": value, "testval": value2, "platform": "ios"])
}
}
SignInViewController - Open modal pop up for passkey authorization
class SignInViewController: UIViewController {
var challenge: Data!
private var signInObserver: NSObjectProtocol?
private var signInErrorObserver: NSObjectProtocol?
init(challenge: Data) {
self.challenge = challenge
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
signInObserver = NotificationCenter.default.addObserver(forName: .UserSignedIn, object: nil, queue: nil) {_ in
self.didFinishSignIn()
}
signInErrorObserver = NotificationCenter.default.addObserver(forName: .ModalSignInSheetCanceled, object: nil, queue: nil) { _ in
self.showSignInForm()
}
guard let window = self.view.window else { fatalError("The view was not in the app's view hierarchy!") }
// Open modal for passkey authorization and authenticate user
let userName = "Name"
(UIApplication.shared.delegate as? AppDelegate)?.accountManager.signUpWith(userName: userName, challenge: self.challenge, anchor: window)
}
func didFinishSignIn() {
// I want to return data to JS after authorization success
}
}
AccountManager.swift - Controller to authorize user
import AuthenticationServices
import Foundation
import os
extension NSNotification.Name {
static let UserSignedIn = Notification.Name("UserSignedInNotification")
static let ModalSignInSheetCanceled = Notification.Name("ModalSignInSheetCanceledNotification")
}
class AccountManager: NSObject, ASAuthorizationControllerPresentationContextProviding, ASAuthorizationControllerDelegate {
let domain = "com.domain.app"
var authenticationAnchor: ASPresentationAnchor?
var isPerformingModalReqest = false
func signUpWith(userName: String, challenge: Data, anchor: ASPresentationAnchor) {
self.authenticationAnchor = anchor
if #available(iOS 15.0, *) {
let publicKeyCredentialProvider = ASAuthorizationPlatformPublicKeyCredentialProvider(relyingPartyIdentifier: domain)
let userID = "d0a4bc91-2def-4567-8983-9188a4ca2048".data(using: .utf8)!
let registrationRequest = publicKeyCredentialProvider.createCredentialRegistrationRequest(challenge: challenge,
name: "User Fullname", userID: userID)
let authController = ASAuthorizationController(authorizationRequests: [ registrationRequest ] )
authController.delegate = self
authController.presentationContextProvider = self
authController.performRequests()
isPerformingModalReqest = true
} else {
// Fallback on earlier versions
}
}
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
// Authorization complete
if #available(iOS 14.0, *) {
let logger = Logger()
if #available(iOS 15.0, *) {
switch authorization.credential {
case let credentialRegistration as ASAuthorizationPlatformPublicKeyCredentialRegistration:
logger.log("A new passkey was registered: \(credentialRegistration)")
// I have managed to get the credential key success registration but couldn't get to pass it back to JS
didFinishSignIn()
case let credentialAssertion as ASAuthorizationPlatformPublicKeyCredentialAssertion:
logger.log("A passkey was used to sign in: \(credentialAssertion)")
didFinishSignIn()
case let passwordCredential as ASPasswordCredential:
logger.log("A password was provided: \(passwordCredential)")
didFinishSignIn()
default:
fatalError("Received unknown authorization type.")
}
} else {
// Fallback on earlier versions
}
} else {
// Fallback on earlier versions
}
isPerformingModalReqest = false
}
func didFinishSignIn() {
print("didFinish")
NotificationCenter.default.post(name: .UserSignedIn, object: nil)
}
}
I have managed to get the credential key success registration but couldn't get to pass it back to JS, how can I return the value back? Thank you in advance.
In Swift you can use a Completion Handler.
Here you can find an example in a Capacitor plugin: https://github.com/capawesome-team/capacitor-plugins/blob/main/packages/badge/ios/Plugin/BadgePlugin.swift#L27:L33
BadgePlugin.swift
:Badge.swift
: