Skip to content
This repository has been archived by the owner on Sep 5, 2020. It is now read-only.

Code for users using Xamarin.Forms #3

Open
kcrandall opened this issue May 3, 2019 · 1 comment
Open

Code for users using Xamarin.Forms #3

kcrandall opened this issue May 3, 2019 · 1 comment

Comments

@kcrandall
Copy link

kcrandall commented May 3, 2019

I made this using these bindings and thought it might save others time. So here is a Xamarin.Forms renderer for drop-in.

iOS Renderer

using System;
using System.ComponentModel;
using System.Reflection;
using CoreGraphics;
using UIKit;
using Xamarin.Forms.Platform.iOS;
using Xamarin.Forms;

using BraintreeCore;
using BraintreeDropIn;
using BraintreeUIKit;

using App;
using App.iOS.Renderers;

[assembly: ExportRenderer(typeof(BraintreeDropInUIButton), typeof(BraintreeDropInUIButtonRenderer))]
namespace App.iOS.Renderers
{
    public class BraintreeDropInUIButtonRenderer : ViewRenderer<BraintreeDropInUIButton, UIButton>
    {
        public UIButton Button { get; private set; }
        public BraintreeDropInUIButton FormsButton { get; private set; }

        protected override void OnElementChanged(ElementChangedEventArgs<BraintreeDropInUIButton> e)
        {
            base.OnElementChanged(e);
            BraintreeDropInUIButton formsButton = (Element as BraintreeDropInUIButton);
            this.FormsButton = formsButton;
            if (Control == null)
            {
                this.Button = new UIButton(new CGRect(0, 64, 320, 44)) { };
                this.Button.SetTitle(formsButton.Title, UIControlState.Normal);
                this.Button.SetTitleColor(UIColor.Purple, UIControlState.Normal);

                // Perform any additional setup after loading the view, typically from a nib.
                this.Button.AccessibilityIdentifier = "Payment";
                this.Button.TouchUpInside += delegate
                {
                    ShowBraintreeDropIn(formsButton.TokenizedKey);
                };
                SetNativeControl(this.Button);
            }
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
        }

        private void ShowBraintreeDropIn(string clientTokenOrTokenizationKey)
        {
            var request = new BTDropInRequest
            {
                ApplePayDisabled = true,
                ThreeDSecureVerification = true
            };
            BTDropInController dropIn = new BTDropInController(clientTokenOrTokenizationKey, request, HandleBTDropInControllerHandler);
            //https://forums.xamarin.com/discussion/41976/how-to-get-uiviewcontroller-associated-with-a-page
            IVisualElementRenderer renderer = Platform.GetRenderer(this.FormsButton.Page);
            if (renderer == null)
            {
                renderer = Platform.CreateRenderer(this.FormsButton.Page);
                Platform.SetRenderer(this.FormsButton.Page, renderer);
            }
            UIViewController viewController = renderer.ViewController;

            viewController.PresentViewController(dropIn, false, null);
        }

        void HandleBTDropInControllerHandler(BTDropInController controller, BTDropInResult result, Foundation.NSError error)
        {
            if (error != null)
            {
                System.Diagnostics.Debug.WriteLine("DROPIN ERROR");
                this.FormsButton.Callback.Invoke(new BraintreeDropInResponse()
                {
                    ExitCode = BraintreeDropInExitCode.Error,
                    ErorrMessage = error.ToString(),
                });
            }
            else if (result != null && result.Cancelled == true)
            {
                System.Diagnostics.Debug.WriteLine("DROPIN CANCELLED");
                this.FormsButton.Callback.Invoke(new BraintreeDropInResponse()
                {
                    ExitCode = BraintreeDropInExitCode.Canceled
                });
            }
            else
            {
                System.Diagnostics.Debug.WriteLine("DROPIN SUCCESS");
                
                BTUIKPaymentOptionType selectedPaymentOptionType = result.PaymentOptionType;

                BTPaymentMethodNonce selectedPaymentMethod = result.PaymentMethod;
                string nonce = selectedPaymentMethod.Nonce;
                string type = selectedPaymentMethod.Type;
                UIView selectedPaymentMethodIcon = result.PaymentIcon;
                string selectedPaymentMethodDescription = result.PaymentDescription;
                this.FormsButton.Callback.Invoke(new BraintreeDropInResponse()
                { 
                    Nonce = nonce,
                    Type = type,
                    PaymentDescription = selectedPaymentMethodDescription,
                    ExitCode = BraintreeDropInExitCode.Succes
                });
            }
            controller.DismissViewController(true, null);
        }
    }
}

Forms View

using System;
using Xamarin.Forms;
namespace App
{
    public enum BraintreeDropInExitCode { Error, Canceled, Succes }
    public class BraintreeDropInResponse
    {
        public BraintreeDropInExitCode ExitCode { get; set; }
        public string Nonce { get; set; }
        public string Type { get; set; }
        public string PaymentDescription { get; set; }
        public string ErorrMessage { get; set; }
    }
    public class BraintreeDropInUIButton : View
    {
        /// <summary>
        /// Required - the parent page this button is in
        /// </summary>
        /// <value>The page.</value>
        public Page Page { get; set; }

        /// <summary>
        /// Invoked after the drop in UI is dismised.
        /// </summary>
        /// <value>The callback.</value>
        public Action<BraintreeDropInResponse> Callback { get; set; }

        public string Title { get; set; }
        /// <summary>
        /// Braintree tokenized key generated on their website for the client SDK.
        /// </summary>
        public string TokenizedKey { get; set; } 
        public BraintreeDropInUIButton()
        {
            
        }
    }
}

Example XAML

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage 
    xmlns="http://xamarin.com/schemas/2014/forms" 
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    xmlns:local="clr-namespace:App" 
    x:Class="App.AddPaymentMethodPage"
    x:Name="page">
    <ContentPage.Content>
        <local:BraintreeDropInUIButton
            x:Name="DropInButton"/>
    </ContentPage.Content>
</ContentPage>

Example Xaml.cs

using System;
using System.Collections.Generic;

using Xamarin.Forms;

namespace App
{
    public partial class AddPaymentMethodPage : ContentPage
    {
        public AddPaymentMethodPage()
        {
            InitializeComponent();
            this.DropInButton.Page = this;
        }
    }
}
@gsemenov
Copy link

gsemenov commented Aug 26, 2019

Hello, great code, thanks. I just have one issue when use your example. When 3d verification and open in browser where user type code it do not redirect back to the app. On debug I see that BTAppSwitch.HandleOpenURL(url, options); executed, but it does not return back and does not execute HandleBTDropInControllerHandler. Did you have the same issue? or does it work for you?

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

No branches or pull requests

2 participants