ios – Plaid OAuth deep hyperlink integration in SwiftUI

[ad_1]

Is there a tutorial on the best way to implement OAuth in iOS utilizing pure SwiftUI?

I learn all of the docs right here (https://plaid.com/docs/hyperlink/oauth/) and studied the code right here (https://github.com/plaid/plaid-link-ios).

The issue with the Plaid instance above is that it reveals a SwiftUI implementation of OAuth based mostly a UIKit ViewController. My app is 100% SwiftUI and we do not use a ViewControllers.

After I take a look at the Plaid OAuth in sandbox (utilizing the platypus account), I can redirect to my app from their take a look at web site, however I am unable to learn the arguments handed within the parameters of the deep hyperlink (oauth_state_id=21a91b98-06ac-4c2c-9e5f-83c5fe9cbba5). Right here is how I at the moment do it:

1/ Under is a simplified model of our bankAccountView, the place the Plaid modal is launched inside our app. Just a few notes about this file:

a. As you’ll be able to see, I open the Plaid modal inside a .fullScreenCover() modifier.

b. The LinkController object is a duplicate/paste of this: https://github.com/plaid/plaid-link-ios/blob/grasp/LinkDemo-Swift/LinkDemo-Swift/LinkKitSwiftUISupport.swift

import SwiftUI
import LinkKit
import FirebaseFunctions

protocol LinkOAuthHandling {
    var linkHandler: Handler? { get }
    var oauthRedirectUri: URL? { get }
}

struct BankAccountsView: View, LinkOAuthHandling {
            
    @State var configurationForCreate: LinkTokenConfiguration?
    @State var configurationForUpdate: LinkTokenConfiguration?
    @State var plaidModal: LinkController?
    
    @State var linkHandler: Handler?
    var oauthRedirectUri: URL? = { URL(string: "https://cruisedevelopment.web page.hyperlink") }()
    
    var physique: some View {
        VStack {
            
            // BUTTON TO OPEN PLAID MODAL
            Button("Hyperlink checking account") {
                configurationForCreate = createLinkTokenConfigurationForCreate(with: plaid.tokenForCreate)
                plaidModal = LinkController(configuration: .linkToken(configurationForCreate!), openOptions: [:]) { (error) in
                    print("Deal with error: (error)!")
                }
            }
            
            // OPEN PLAID MODAL
            if plaidModal != nil { Rectangle().body(width: 0, top: 0).onAppear { isPlaidModalOpen = true } }
            
            // ... MORE CONTENT
        
        }
        .onAppear {
            plaid.getLinkTokenForCreate()
        }
        // PLAID MODAL
        .fullScreenCover(isPresented: $isPlaidModalOpen, onDismiss: {
            isPlaidModalOpen = false
        }, content material: {
            plaidModal
        })
    }
    
    personal func createLinkTokenConfigurationForCreate(with linkToken: String) -> LinkTokenConfiguration {
        var linkConfiguration = LinkTokenConfiguration(token: linkToken) { success in
            print("public-token: (success.publicToken) metadata: (success.metadata)")
            self.handleSuccessForCreate(success.publicToken, metadata: success.metadata)
        }
        linkConfiguration.onExit = { exit in
            if let error = exit.error {
                print("LinkTokenConfigurationForCreate exit with (error)n(exit.metadata)")
            } else {
                print("LinkTokenConfigurationForCreate exit with (exit.metadata)")
            }
            hidePlaidModal()
        }
        return linkConfiguration
    }
    
    personal func handleSuccessForCreate(_ publicToken: String, metadata: SuccessMetadata) {
        let bankId = metadata.establishment.id
        let bankName = metadata.establishment.identify
        var accountsIds = [String]()
        for account in metadata.accounts { accountsIds.append(account.id) }
        let payload: [String: Any] = [
            "publicToken": publicToken,
            "bankId": bankId,
            "bankName": bankName,
            "accountsIds": accountsIds
        ]
        isFinishingPlaidSetup = true
        Capabilities.features().httpsCallable(finishPlaidSetupPath).name(payload) { (outcome, error) in
            if let error = error {
                print("Error ending Plaid setup: (error.localizedDescription)")
            } else {
                print("Success ending Plaid setup: (outcome!)")
            }
            isFinishingPlaidSetup = false
            hidePlaidModal()
        }
    }
}

2/ After the App2App OAuth circulate finishes and the person is redirected to my app (whereas the Plaid fullScreenCover continues to be open), I deal with the deep hyperlink utilizing the .onOpenUrl() modifier (that is the brand new method of doing it with SwiftUI – see right here: https://www.donnywals.com/handling-deeplinks-in-ios-14-with-onopenurl/). I am attaching a screenshot that reveals the code we use.

Notes about this file:

a. My objective right here is to copy this: https://github.com/plaid/plaid-link-ios/blob/grasp/LinkDemo-Swift/LinkDemo-Swift/AppDelegatepercent2BOAuthSupport.swift

b. The code at the moment executes as anticipated till the “Fail 1” line. That’s, I obtain what appears to be like like the correct deep hyperlink URL from the platypus financial institution web site and I can seize the keyWindow, however I’m unable to create a link0AuthHandler of kind “Link0AuthHandling” utilizing that keyWindow (although the app nonetheless has the Plaid fullScreenCover open on the correct display).

import SwiftUI
import LinkKit

@major
struct CruiseApp: App {
    
    @UIApplicationDelegateAdaptor var delegate: AppDelegate
        
    var physique: some Scene {
        WindowGroup {
            ContentView()
                .onOpenURL { url in
                    let window = UIApplication.shared.connectedScenes.flatMap {($0 as? UIWindowScene)?.home windows ?? [] }.first { $0.isKeyWindow }
                    guard let linkOAuthHandler = window?.rootViewController as? LinkOAuthHandling else { let _ = print(">> FAIL 1"); return }
                    guard let handler = linkOAuthHandler.linkHandler else { let _ = print(">> FAIL 2"); return }
                    handler.proceed(from: url)                    
                }
        }
    }
}

I believe the difficulty has to do with the method described above.

[ad_2]

Leave a Reply