Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SwiftUI support #202

Closed
morizmartiner opened this issue Dec 5, 2019 · 7 comments · Fixed by #226
Closed

SwiftUI support #202

morizmartiner opened this issue Dec 5, 2019 · 7 comments · Fixed by #226

Comments

@morizmartiner
Copy link

General information

  • SDK/Library version: 7.5.0
  • Environment: Production
  • iOS Version and Device: 11.2.1
  • Integration type and version: Cocoapods

Issue description

I am trying to set up payment with Braintree, but Braintree does not yet support SwiftUI so I have to integrate it with UIKit. I created a wrapper using UIViewControllerRepresentable and I am presenting it as a modal using the sheet function; however, it does not work as expected, it seems it is opening two modals.

The screen when I open the modal:enter image description here

Here's my wrapper:

import SwiftUI
import BraintreeDropIn

struct BTDropInRepresentable: UIViewControllerRepresentable {
    var authorization: String
    var handler: BTDropInControllerHandler
    
    init(authorization: String, handler: @escaping BTDropInControllerHandler) {
        self.authorization = authorization
        self.handler = handler
    }
    
    func makeUIViewController(context: Context) -> BTDropInController {
        let bTDropInController = BTDropInController(authorization: authorization, request: BTDropInRequest(), handler: handler)!
        return bTDropInController
    }
    
    func updateUIViewController(_ uiViewController: BTDropInController, context: UIViewControllerRepresentableContext<BTDropInRepresentable>) {
    }
}

Here is where I am trying to open the modal:

Button(action: {
    self.checkout = true
}) {
    HStack {
        Spacer()
        Text("Checkout")
            .fontWeight(.bold)
            .font(.body)
        Spacer()
    }
    .padding(.vertical, 12)
    .foregroundColor(.white)
    .background(Color.blue)
}.sheet(isPresented: self.$checkout) {
    BTDropInRepresentable(authorization: self.token!, handler:  { (controller, result, error) in
                       if (error != nil) {
                           print("ERROR")
                       } else if (result?.isCancelled == true) {
                           print("CANCELLED")
                       } else if result != nil {
                        print("SUCCESS")
                           // Use the BTDropInResult properties to update your UI
                           // result.paymentOptionType
                           // result.paymentMethod
                           // result.paymentIcon
                           // result.paymentDescription
            }
        controller.dismiss(animated: true, completion: nil)
    })
}

Does anyone have experience with Braintree in SwiftUI or with a similar situation? Am I doing something wrong or forgetting something?
I know writing my own views for Braintree checkout is an option, but I'd like to avoid that.

Thanks!

@demerino
Copy link
Member

demerino commented Dec 5, 2019

@morizmartiner We'll have to investigate more but we currently don't have plans to support SwiftUI. Based on the screenshot, it looks like the background of the Drop-in view is showing but not the subviews.

@sestevens
Copy link
Contributor

@morizmartiner It might make sense to use a ZStack instead of the .sheet modifier. The "second modal" you're seeing is indeed the blur background that we display over the merchant app when Drop-in is presented.

You could try something like this:

struct ContentView: View {
    let token = "tokenization-key"
    
    @State var showDropIn = false
    
    var body: some View {
        ZStack {
            Button(action: {
                self.showDropIn = true
            }) {
                // configure button with text, etc.
            }
            if self.showDropIn {
                BTDropInRepresentable(authorization: token, handler: { controller, result, error in
                    // check for error or result
                    // send tokenized payment method to your server
                    self.showDropIn = false
                }).edgesIgnoringSafeArea(.vertical)
            }
        }
    }
}

While I was trying this out, I noticed that this condition in BTDropInController doesn't evaluate to true when the view controller is shown from SwiftUI. Commenting out that line allowed the modal to display properly. We'll need to do some testing to figure out if we can safely remove this condition from our code.

@morizmartiner
Copy link
Author

Thanks you so much, it worked!

@hevelius
Copy link

General information

  • SDK/Library Braintree (4.33.0), BraintreeDropIn (8.1.0)
  • Environment: Staging
  • iOS Version and Simulator Device: 13.5
  • Integration type and version: Cocoapods

Hi all,

in my app DropIn UI not show subviews. I used as reference the braintree-ios-drop-in-swiftui-demo. As you can see in image below the BTDropInController is showed but without subviews.

Simulator Screen Shot - iPhone SE (2nd generation) - 2020-05-27 at 10 42 12

DropInRepresentable

import SwiftUI
import BraintreeDropIn

struct DropInRepresentable: UIViewControllerRepresentable {
    var authorization: String
    var handler: BTDropInControllerHandler
    
    init(authorization: String, handler: @escaping BTDropInControllerHandler) {
        self.authorization = authorization
        self.handler = handler
    }
    
    func makeUIViewController(context: Context) -> BTDropInController {
        
        let request = BTDropInRequest()
        //request.payPalRequest = payPalRequest
        //request.applePayDisabled = true
        
        let dropInController = BTDropInController(authorization: authorization, request: request, handler: handler)!
        return dropInController
    }
    
    func updateUIViewController(_ uiViewController: BTDropInController, context: UIViewControllerRepresentableContext<DropInRepresentable>) {
        
    }
}

ContentView

VStack {
//.........
Group {
                HStack {
                    Button(action: {
                        self.showDropIn = true
                    }) {
                        HStack {
                            Spacer()
                            Text("Checkout")
                                .fontWeight(.bold)
                                .font(.body)
                            Spacer()
                        }
                        .padding(.vertical, 12)
                        .foregroundColor(.white)
                        .background(Color.blue)
                    }
                }
            }.disabled(self.clientToken.client_token.isEmpty)
            
            if self.showDropIn {
                DropInRepresentable(authorization: self.clientToken.client_token, handler: { controller, result, error in
                    if let error = error {
                        print("Error: \(error.localizedDescription)")
                    } else if let result = result, result.isCancelled {
                        print("Cancelled🎲")
                    } else {
                        print("Ready for checkout...")
                    }
                    self.showDropIn = false
                }).edgesIgnoringSafeArea(.vertical)
            }
}

Any ideas on that? Surely the mistake is under my nose... 😟

@scannillo
Copy link
Contributor

scannillo commented May 27, 2020

Hello @hevelius. In Susan's comment above - she points out a bug in our SDK that was causing the modal to be empty. We have a PR out for this fix that we will include in our next release of the SDK.

I will close this issue once that fix is released.

@15joeybloom
Copy link

Can someone release a new version of the library that includes the swiftui support? I would love to start using it.

@billwerges
Copy link
Contributor

Fixed in 8.1.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants