SlideShare a Scribd company logo
1 of 15
Download to read offline
Native Payment - Part I
As I built this app I took the code I used within it and created a cn1lib that implements the native interface described here. So a better way to implement braintree
support would be to use the official braintree cn1lib. However, this is still useful as an educational tool explaining both braintree and how to map a native interface
Braintree
© Codename One 2017 all rights reserved
Braintree is a pretty simple API on the client side as most of the charging process is handled on the server side of the API. The reason for this is that the client side if far
more hackable even in a native app. 

In order to work with the API we start with a token which we can get from server code and then perform the charge process which is handled mostly seamlessly by the
library API.
What do we Need to Do?
✦Get a nonce using a token, heres the API snippet for
Android:
© Codename One 2017 all rights reserved
public void onBraintreeSubmit(View v) {
DropInRequest dropInRequest = new DropInRequest()
.clientToken(token);
startActivityForResult(dropInRequest.getIntent(this), REQUEST_CODE);
}
If you go to the braintree online docs and look at the integration instructions for native Android code you will find this code. This is native Android code for making a
request, the token is something we need to get from the server although conveniently the braintree site provides a helpful debugging token we can work with. This can fit
right into our native interface but first I want to review the native API to decide what sort of native calls we would need… Notice that even though a view object is passed,
it isn’t really used and that a token value is needed even though it isn’t passed.
And iOS
✦This is what we need to do in iOS:
© Codename One 2017 all rights reserved
- (void)showDropIn:(NSString *)clientTokenOrTokenizationKey {
BTDropInRequest *request = [[BTDropInRequest alloc] init];
BTDropInController *dropIn = [[BTDropInController alloc]
initWithAuthorization:clientTokenOrTokenizationKey request:request handler:^(BTDropInController *
_Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) {
if (error != nil) {
NSLog(@"ERROR");
} else if (result.cancelled) {
NSLog(@"CANCELLED");
} else {
// Use the BTDropInResult properties to update your UI
}
}];
[self presentViewController:dropIn animated:YES completion:nil];
}
Moving to the iOS side the Objective-C code isn’t as readable for Java developers so let’s review this in pieces
And iOS
✦This is what we need to do in iOS:
© Codename One 2017 all rights reserved
- (void)showDropIn:(NSString *)clientTokenOrTokenizationKey {
BTDropInRequest *request = [[BTDropInRequest alloc] init];
BTDropInController *dropIn = [[BTDropInController alloc]
initWithAuthorization:clientTokenOrTokenizationKey request:request handler:^(BTDropInController *
_Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) {
if (error != nil) {
NSLog(@"ERROR");
} else if (result.cancelled) {
NSLog(@"CANCELLED");
} else {
// Use the BTDropInResult properties to update your UI
}
}];
[self presentViewController:dropIn animated:YES completion:nil];
}
This is a method declaration that accepts one string argument. Technically in objective-c these are messages not methods but I won’t go into subtle language differences
And iOS
✦This is what we need to do in iOS:
© Codename One 2017 all rights reserved
- (void)showDropIn:(NSString *)clientTokenOrTokenizationKey {
BTDropInRequest *request = [[BTDropInRequest alloc] init];
BTDropInController *dropIn = [[BTDropInController alloc]
initWithAuthorization:clientTokenOrTokenizationKey request:request handler:^(BTDropInController *
_Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) {
if (error != nil) {
NSLog(@"ERROR");
} else if (result.cancelled) {
NSLog(@"CANCELLED");
} else {
// Use the BTDropInResult properties to update your UI
}
}];
[self presentViewController:dropIn animated:YES completion:nil];
}
Here we allocate a request, notice that this is the equivalent of a “new” call in Java. The init entry is a method invocation of init. Methods are invoked using a square
bracket syntax. 

init is a special case method in Objective-C and is usually used as a constructor.
And iOS
✦This is what we need to do in iOS:
© Codename One 2017 all rights reserved
- (void)showDropIn:(NSString *)clientTokenOrTokenizationKey {
BTDropInRequest *request = [[BTDropInRequest alloc] init];
BTDropInController *dropIn = [[BTDropInController alloc]
initWithAuthorization:clientTokenOrTokenizationKey request:request handler:^(BTDropInController *
_Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) {
if (error != nil) {
NSLog(@"ERROR");
} else if (result.cancelled) {
NSLog(@"CANCELLED");
} else {
// Use the BTDropInResult properties to update your UI
}
}];
[self presentViewController:dropIn animated:YES completion:nil];
}
This is a really interesting block so I’ll split the block itself into several pieces
And iOS
✦This is what we need to do in iOS:
© Codename One 2017 all rights reserved
- (void)showDropIn:(NSString *)clientTokenOrTokenizationKey {
BTDropInRequest *request = [[BTDropInRequest alloc] init];
BTDropInController *dropIn = [[BTDropInController alloc]
initWithAuthorization:clientTokenOrTokenizationKey request:request handler:^(BTDropInController *
_Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) {
if (error != nil) {
NSLog(@"ERROR");
} else if (result.cancelled) {
NSLog(@"CANCELLED");
} else {
// Use the BTDropInResult properties to update your UI
}
}];
[self presentViewController:dropIn animated:YES completion:nil];
}
That’s simple, it’s just code that allocates the drop in controller. Not much to it, this is like Java’s new. However, you will notice that the brackets aren’t closed because
the init method or the constructor should be invoked…
And iOS
✦This is what we need to do in iOS:
© Codename One 2017 all rights reserved
- (void)showDropIn:(NSString *)clientTokenOrTokenizationKey {
BTDropInRequest *request = [[BTDropInRequest alloc] init];
BTDropInController *dropIn = [[BTDropInController alloc]
initWithAuthorization:clientTokenOrTokenizationKey request:request handler:^(BTDropInController *
_Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) {
if (error != nil) {
NSLog(@"ERROR");
} else if (result.cancelled) {
NSLog(@"CANCELLED");
} else {
// Use the BTDropInResult properties to update your UI
}
}];
[self presentViewController:dropIn animated:YES completion:nil];
}
The init method here is special… It accepts the token as an argument as well as the request. Notice two interesting things. The client token is just passed but request is
written twice! 

In Objective-C arguments are named, that means that you need to type the name of every argument to a method and you can have two methods with the same name but
different argument names. To make matters more confusing the first argument is a special case that doesn’t need a name so we have one argument followed by the other
arguments each containging the name of the argument and then the value. So the request argument name and value make sense but the last argument might seem odd.
Handler is an argument that accepts a lambda expression with a callback. That callback accepts several argument types and will be invoked asynchronously when a
purchase produces a result
And iOS
✦This is what we need to do in iOS:
© Codename One 2017 all rights reserved
- (void)showDropIn:(NSString *)clientTokenOrTokenizationKey {
BTDropInRequest *request = [[BTDropInRequest alloc] init];
BTDropInController *dropIn = [[BTDropInController alloc]
initWithAuthorization:clientTokenOrTokenizationKey request:request handler:^(BTDropInController *
_Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) {
if (error != nil) {
NSLog(@"ERROR");
} else if (result.cancelled) {
NSLog(@"CANCELLED");
} else {
// Use the BTDropInResult properties to update your UI
}
}];
[self presentViewController:dropIn animated:YES completion:nil];
}
The lambda expression itself checks if the arguments represent an error, cancellation or success, this code should be pretty familiar to Java programmers. The one
“weird” things is that Objective-C strings start with the @ character which I won’t go into here
And iOS
✦This is what we need to do in iOS:
© Codename One 2017 all rights reserved
- (void)showDropIn:(NSString *)clientTokenOrTokenizationKey {
BTDropInRequest *request = [[BTDropInRequest alloc] init];
BTDropInController *dropIn = [[BTDropInController alloc]
initWithAuthorization:clientTokenOrTokenizationKey request:request handler:^(BTDropInController *
_Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) {
if (error != nil) {
NSLog(@"ERROR");
} else if (result.cancelled) {
NSLog(@"CANCELLED");
} else {
// Use the BTDropInResult properties to update your UI
}
}];
[self presentViewController:dropIn animated:YES completion:nil];
}
The final piece of code is the present view controller which shows the UI, notice it happens before the lambda expression is invoked as that is a callback. Also notice we
used the Objective-C keyword self which is the Objective-C equivalent of Java’s this keyword. In this particular case self is assumed to be a view controller.

So now that we reviewed everything in the method its pretty clear that the big thing that’s needed from the Java side of the API is the token and not much else.
So all we need…
✦Is one method:
© Codename One 2017 all rights reserved
import com.codename1.system.NativeInterface;
public interface BraintreeNative extends NativeInterface {
public void showChargeUI(String clientToken);
}
Tip
We generate stubs by right
clicking the native interface
and selecting Generate
Native Stubs
This is something we can represent with this simple method. Once we implement that in the Java side we can use generate native stubs to generate stub code for the
various native platforms and fill up that stub code
But we also need…
✦Callbacks for results… Left them as stubs for now
© Codename One 2017 all rights reserved
public class BraintreePaymentCallback {
public static void onPurchaseSuccess(String nonce) {
}
public static void onPurchaseFail(String errorMessage) {
}
public static void onPurchaseCancel() {
}
}
One important piece that’s missing from the native interface is the callback code. We need to monitor callback events so we can know if a purchase succeeded or failed.
A more common approach would be to pass the callback object instance to the call but here I use static callback code. The reason for this is simple, native interfaces
have a lot of restrictions on them and one of those is that we can’t pass arbitrary object types. The reason for those restrictions is simplicity and portability. How would
you represent an object instance in the Objective-C mapping?

To implement callbacks we use static methods and some platform specific code.
Purchase Class
✦ Invoking native interfaces directly is bad practice
✦ They are an implementation detail and should be
abstracted
✦ Enter the Purchase class which hides the
implementation and also provides a generic
implementation based on the JavaScript port of
Braintree
© Codename One 2017 all rights reserved
Calling the native interface directly is often a “bad practice”

Native interfaces are often fragile and should be wrapped in an abstraction that hides potential platform issues. For instance if the iOS & Android native interfaces have
different features we might be able to hide/abstract it in the Java side which is normally much easier to do than implementing native code.

In this code we even have an attempt at fallback code based on the JavaScript port of braintree. It doesn’t work all that well but that’s mostly because I didn’t pay that
much attention to it.
public class Purchase {
boolean flag;
public void startOrder() {
BraintreeNative bn = NativeLookup.create(BraintreeNative.class);
String token = "token-snipped";
if(bn != null && bn.isSupported()) {
bn.showChargeUI(token);
} else {
Form buy = new Form(new BorderLayout());
buy.getToolbar().setUIID("DarkToolbar");
Form previous = Display.getInstance().getCurrent();
buy.getToolbar().addMaterialCommandToLeftBar("", FontImage.MATERIAL_CANCEL, e ->
previous.showBack());
BrowserComponent cmp = new BrowserComponent();
buy.add(BorderLayout.CENTER, cmp);
cmp.setPage("html-snipped", null);
buy.show();
}
if(flag) {
BraintreePaymentCallback.onPurchaseCancel();
BraintreePaymentCallback.onPurchaseFail(null);
BraintreePaymentCallback.onPurchaseSuccess(null);
}
}
}
Purchase
Compiler Issue
iOS VM strips unused code and could
remove these without that flag…
This class is mostly trivial since the native interface is trivial too.

Notice the code at the bottom that invokes the static callbacks. This is a special case for iOS where the VM strips away unused code. By writing this the compiler can’t
tell that the code will never be invoked and will keep it in place. Notice that even making a seemingly small change like making “flag” into a private variable might break
this…

More Related Content

Similar to Native Payment - Part 1 - Transcript.pdf

303 TANSTAAFL: Using Open Source iPhone UI Code
303 TANSTAAFL: Using Open Source iPhone UI Code303 TANSTAAFL: Using Open Source iPhone UI Code
303 TANSTAAFL: Using Open Source iPhone UI Codejonmarimba
 
XebiConFr 15 - Brace yourselves Angular 2 is coming
XebiConFr 15 - Brace yourselves Angular 2 is comingXebiConFr 15 - Brace yourselves Angular 2 is coming
XebiConFr 15 - Brace yourselves Angular 2 is comingPublicis Sapient Engineering
 
WWDC 2016 Personal Recollection
WWDC 2016 Personal RecollectionWWDC 2016 Personal Recollection
WWDC 2016 Personal RecollectionMasayuki Iwai
 
Quick Start to iOS Development
Quick Start to iOS DevelopmentQuick Start to iOS Development
Quick Start to iOS DevelopmentJussi Pohjolainen
 
Native Payment - Part 3.pdf
Native Payment - Part 3.pdfNative Payment - Part 3.pdf
Native Payment - Part 3.pdfShaiAlmog1
 
iOS Unit Testing
iOS Unit TestingiOS Unit Testing
iOS Unit Testingsgleadow
 
Projet d'accès aux résultats des étudiant via client mobile
Projet d'accès aux résultats des étudiant via client mobile Projet d'accès aux résultats des étudiant via client mobile
Projet d'accès aux résultats des étudiant via client mobile Patrick Bashizi
 
10 tips for a reusable architecture
10 tips for a reusable architecture10 tips for a reusable architecture
10 tips for a reusable architectureJorge Ortiz
 
Performance measurement and tuning
Performance measurement and tuningPerformance measurement and tuning
Performance measurement and tuningAOE
 
Modify the bouncing ball example demonstrated/tutorialoutlet
Modify the bouncing ball example demonstrated/tutorialoutletModify the bouncing ball example demonstrated/tutorialoutlet
Modify the bouncing ball example demonstrated/tutorialoutletCleasbyz
 
AngularJS Architecture
AngularJS ArchitectureAngularJS Architecture
AngularJS ArchitectureEyal Vardi
 
AngularJS Internal
AngularJS InternalAngularJS Internal
AngularJS InternalEyal Vardi
 
Time for intersection observer
Time for intersection observerTime for intersection observer
Time for intersection observerJonas Ohlsson Aden
 

Similar to Native Payment - Part 1 - Transcript.pdf (20)

303 TANSTAAFL: Using Open Source iPhone UI Code
303 TANSTAAFL: Using Open Source iPhone UI Code303 TANSTAAFL: Using Open Source iPhone UI Code
303 TANSTAAFL: Using Open Source iPhone UI Code
 
XebiConFr 15 - Brace yourselves Angular 2 is coming
XebiConFr 15 - Brace yourselves Angular 2 is comingXebiConFr 15 - Brace yourselves Angular 2 is coming
XebiConFr 15 - Brace yourselves Angular 2 is coming
 
mean stack
mean stackmean stack
mean stack
 
WWDC 2016 Personal Recollection
WWDC 2016 Personal RecollectionWWDC 2016 Personal Recollection
WWDC 2016 Personal Recollection
 
Day 1
Day 1Day 1
Day 1
 
Angular 2 in-1
Angular 2 in-1 Angular 2 in-1
Angular 2 in-1
 
Quick Start to iOS Development
Quick Start to iOS DevelopmentQuick Start to iOS Development
Quick Start to iOS Development
 
Native Payment - Part 3.pdf
Native Payment - Part 3.pdfNative Payment - Part 3.pdf
Native Payment - Part 3.pdf
 
iOS Unit Testing
iOS Unit TestingiOS Unit Testing
iOS Unit Testing
 
從零開始學 Android
從零開始學 Android從零開始學 Android
從零開始學 Android
 
Projet d'accès aux résultats des étudiant via client mobile
Projet d'accès aux résultats des étudiant via client mobile Projet d'accès aux résultats des étudiant via client mobile
Projet d'accès aux résultats des étudiant via client mobile
 
10 tips for a reusable architecture
10 tips for a reusable architecture10 tips for a reusable architecture
10 tips for a reusable architecture
 
Hybrid Tips & Tricks
Hybrid Tips & TricksHybrid Tips & Tricks
Hybrid Tips & Tricks
 
Performance measurement and tuning
Performance measurement and tuningPerformance measurement and tuning
Performance measurement and tuning
 
Modify the bouncing ball example demonstrated/tutorialoutlet
Modify the bouncing ball example demonstrated/tutorialoutletModify the bouncing ball example demonstrated/tutorialoutlet
Modify the bouncing ball example demonstrated/tutorialoutlet
 
AngularJS Architecture
AngularJS ArchitectureAngularJS Architecture
AngularJS Architecture
 
AngularJS Internal
AngularJS InternalAngularJS Internal
AngularJS Internal
 
Oops presentation
Oops presentationOops presentation
Oops presentation
 
Time for intersection observer
Time for intersection observerTime for intersection observer
Time for intersection observer
 
NInject - DI Container
NInject - DI ContainerNInject - DI Container
NInject - DI Container
 

More from ShaiAlmog1

The Duck Teaches Learn to debug from the masters. Local to production- kill ...
The Duck Teaches  Learn to debug from the masters. Local to production- kill ...The Duck Teaches  Learn to debug from the masters. Local to production- kill ...
The Duck Teaches Learn to debug from the masters. Local to production- kill ...ShaiAlmog1
 
create-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfcreate-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfShaiAlmog1
 
create-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfcreate-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfShaiAlmog1
 
create-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfcreate-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfShaiAlmog1
 
create-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfcreate-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfShaiAlmog1
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfShaiAlmog1
 
create-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfcreate-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfShaiAlmog1
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfShaiAlmog1
 
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfShaiAlmog1
 
create-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfcreate-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfShaiAlmog1
 
create-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfcreate-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfShaiAlmog1
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfShaiAlmog1
 
create-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfcreate-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfCreating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfCreating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfCreating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfCreating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfCreating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfCreating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfCreating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfShaiAlmog1
 

More from ShaiAlmog1 (20)

The Duck Teaches Learn to debug from the masters. Local to production- kill ...
The Duck Teaches  Learn to debug from the masters. Local to production- kill ...The Duck Teaches  Learn to debug from the masters. Local to production- kill ...
The Duck Teaches Learn to debug from the masters. Local to production- kill ...
 
create-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfcreate-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdf
 
create-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfcreate-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdf
 
create-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfcreate-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdf
 
create-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfcreate-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdf
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdf
 
create-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfcreate-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdf
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdf
 
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdf
 
create-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfcreate-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdf
 
create-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfcreate-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdf
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdf
 
create-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfcreate-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdf
 
Creating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfCreating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdf
 
Creating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfCreating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdf
 
Creating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfCreating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdf
 
Creating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfCreating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfCreating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfCreating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdf
 
Creating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfCreating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdf
 

Recently uploaded

CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...HostedbyConfluent
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksSoftradix Technologies
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphNeo4j
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 

Recently uploaded (20)

CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping Elbows
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food Manufacturing
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other Frameworks
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 

Native Payment - Part 1 - Transcript.pdf

  • 1. Native Payment - Part I As I built this app I took the code I used within it and created a cn1lib that implements the native interface described here. So a better way to implement braintree support would be to use the official braintree cn1lib. However, this is still useful as an educational tool explaining both braintree and how to map a native interface
  • 2. Braintree © Codename One 2017 all rights reserved Braintree is a pretty simple API on the client side as most of the charging process is handled on the server side of the API. The reason for this is that the client side if far more hackable even in a native app. In order to work with the API we start with a token which we can get from server code and then perform the charge process which is handled mostly seamlessly by the library API.
  • 3. What do we Need to Do? ✦Get a nonce using a token, heres the API snippet for Android: © Codename One 2017 all rights reserved public void onBraintreeSubmit(View v) { DropInRequest dropInRequest = new DropInRequest() .clientToken(token); startActivityForResult(dropInRequest.getIntent(this), REQUEST_CODE); } If you go to the braintree online docs and look at the integration instructions for native Android code you will find this code. This is native Android code for making a request, the token is something we need to get from the server although conveniently the braintree site provides a helpful debugging token we can work with. This can fit right into our native interface but first I want to review the native API to decide what sort of native calls we would need… Notice that even though a view object is passed, it isn’t really used and that a token value is needed even though it isn’t passed.
  • 4. And iOS ✦This is what we need to do in iOS: © Codename One 2017 all rights reserved - (void)showDropIn:(NSString *)clientTokenOrTokenizationKey { BTDropInRequest *request = [[BTDropInRequest alloc] init]; BTDropInController *dropIn = [[BTDropInController alloc] initWithAuthorization:clientTokenOrTokenizationKey request:request handler:^(BTDropInController * _Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) { if (error != nil) { NSLog(@"ERROR"); } else if (result.cancelled) { NSLog(@"CANCELLED"); } else { // Use the BTDropInResult properties to update your UI } }]; [self presentViewController:dropIn animated:YES completion:nil]; } Moving to the iOS side the Objective-C code isn’t as readable for Java developers so let’s review this in pieces
  • 5. And iOS ✦This is what we need to do in iOS: © Codename One 2017 all rights reserved - (void)showDropIn:(NSString *)clientTokenOrTokenizationKey { BTDropInRequest *request = [[BTDropInRequest alloc] init]; BTDropInController *dropIn = [[BTDropInController alloc] initWithAuthorization:clientTokenOrTokenizationKey request:request handler:^(BTDropInController * _Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) { if (error != nil) { NSLog(@"ERROR"); } else if (result.cancelled) { NSLog(@"CANCELLED"); } else { // Use the BTDropInResult properties to update your UI } }]; [self presentViewController:dropIn animated:YES completion:nil]; } This is a method declaration that accepts one string argument. Technically in objective-c these are messages not methods but I won’t go into subtle language differences
  • 6. And iOS ✦This is what we need to do in iOS: © Codename One 2017 all rights reserved - (void)showDropIn:(NSString *)clientTokenOrTokenizationKey { BTDropInRequest *request = [[BTDropInRequest alloc] init]; BTDropInController *dropIn = [[BTDropInController alloc] initWithAuthorization:clientTokenOrTokenizationKey request:request handler:^(BTDropInController * _Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) { if (error != nil) { NSLog(@"ERROR"); } else if (result.cancelled) { NSLog(@"CANCELLED"); } else { // Use the BTDropInResult properties to update your UI } }]; [self presentViewController:dropIn animated:YES completion:nil]; } Here we allocate a request, notice that this is the equivalent of a “new” call in Java. The init entry is a method invocation of init. Methods are invoked using a square bracket syntax. 
 init is a special case method in Objective-C and is usually used as a constructor.
  • 7. And iOS ✦This is what we need to do in iOS: © Codename One 2017 all rights reserved - (void)showDropIn:(NSString *)clientTokenOrTokenizationKey { BTDropInRequest *request = [[BTDropInRequest alloc] init]; BTDropInController *dropIn = [[BTDropInController alloc] initWithAuthorization:clientTokenOrTokenizationKey request:request handler:^(BTDropInController * _Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) { if (error != nil) { NSLog(@"ERROR"); } else if (result.cancelled) { NSLog(@"CANCELLED"); } else { // Use the BTDropInResult properties to update your UI } }]; [self presentViewController:dropIn animated:YES completion:nil]; } This is a really interesting block so I’ll split the block itself into several pieces
  • 8. And iOS ✦This is what we need to do in iOS: © Codename One 2017 all rights reserved - (void)showDropIn:(NSString *)clientTokenOrTokenizationKey { BTDropInRequest *request = [[BTDropInRequest alloc] init]; BTDropInController *dropIn = [[BTDropInController alloc] initWithAuthorization:clientTokenOrTokenizationKey request:request handler:^(BTDropInController * _Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) { if (error != nil) { NSLog(@"ERROR"); } else if (result.cancelled) { NSLog(@"CANCELLED"); } else { // Use the BTDropInResult properties to update your UI } }]; [self presentViewController:dropIn animated:YES completion:nil]; } That’s simple, it’s just code that allocates the drop in controller. Not much to it, this is like Java’s new. However, you will notice that the brackets aren’t closed because the init method or the constructor should be invoked…
  • 9. And iOS ✦This is what we need to do in iOS: © Codename One 2017 all rights reserved - (void)showDropIn:(NSString *)clientTokenOrTokenizationKey { BTDropInRequest *request = [[BTDropInRequest alloc] init]; BTDropInController *dropIn = [[BTDropInController alloc] initWithAuthorization:clientTokenOrTokenizationKey request:request handler:^(BTDropInController * _Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) { if (error != nil) { NSLog(@"ERROR"); } else if (result.cancelled) { NSLog(@"CANCELLED"); } else { // Use the BTDropInResult properties to update your UI } }]; [self presentViewController:dropIn animated:YES completion:nil]; } The init method here is special… It accepts the token as an argument as well as the request. Notice two interesting things. The client token is just passed but request is written twice! 
 In Objective-C arguments are named, that means that you need to type the name of every argument to a method and you can have two methods with the same name but different argument names. To make matters more confusing the first argument is a special case that doesn’t need a name so we have one argument followed by the other arguments each containging the name of the argument and then the value. So the request argument name and value make sense but the last argument might seem odd. Handler is an argument that accepts a lambda expression with a callback. That callback accepts several argument types and will be invoked asynchronously when a purchase produces a result
  • 10. And iOS ✦This is what we need to do in iOS: © Codename One 2017 all rights reserved - (void)showDropIn:(NSString *)clientTokenOrTokenizationKey { BTDropInRequest *request = [[BTDropInRequest alloc] init]; BTDropInController *dropIn = [[BTDropInController alloc] initWithAuthorization:clientTokenOrTokenizationKey request:request handler:^(BTDropInController * _Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) { if (error != nil) { NSLog(@"ERROR"); } else if (result.cancelled) { NSLog(@"CANCELLED"); } else { // Use the BTDropInResult properties to update your UI } }]; [self presentViewController:dropIn animated:YES completion:nil]; } The lambda expression itself checks if the arguments represent an error, cancellation or success, this code should be pretty familiar to Java programmers. The one “weird” things is that Objective-C strings start with the @ character which I won’t go into here
  • 11. And iOS ✦This is what we need to do in iOS: © Codename One 2017 all rights reserved - (void)showDropIn:(NSString *)clientTokenOrTokenizationKey { BTDropInRequest *request = [[BTDropInRequest alloc] init]; BTDropInController *dropIn = [[BTDropInController alloc] initWithAuthorization:clientTokenOrTokenizationKey request:request handler:^(BTDropInController * _Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) { if (error != nil) { NSLog(@"ERROR"); } else if (result.cancelled) { NSLog(@"CANCELLED"); } else { // Use the BTDropInResult properties to update your UI } }]; [self presentViewController:dropIn animated:YES completion:nil]; } The final piece of code is the present view controller which shows the UI, notice it happens before the lambda expression is invoked as that is a callback. Also notice we used the Objective-C keyword self which is the Objective-C equivalent of Java’s this keyword. In this particular case self is assumed to be a view controller. So now that we reviewed everything in the method its pretty clear that the big thing that’s needed from the Java side of the API is the token and not much else.
  • 12. So all we need… ✦Is one method: © Codename One 2017 all rights reserved import com.codename1.system.NativeInterface; public interface BraintreeNative extends NativeInterface { public void showChargeUI(String clientToken); } Tip We generate stubs by right clicking the native interface and selecting Generate Native Stubs This is something we can represent with this simple method. Once we implement that in the Java side we can use generate native stubs to generate stub code for the various native platforms and fill up that stub code
  • 13. But we also need… ✦Callbacks for results… Left them as stubs for now © Codename One 2017 all rights reserved public class BraintreePaymentCallback { public static void onPurchaseSuccess(String nonce) { } public static void onPurchaseFail(String errorMessage) { } public static void onPurchaseCancel() { } } One important piece that’s missing from the native interface is the callback code. We need to monitor callback events so we can know if a purchase succeeded or failed. A more common approach would be to pass the callback object instance to the call but here I use static callback code. The reason for this is simple, native interfaces have a lot of restrictions on them and one of those is that we can’t pass arbitrary object types. The reason for those restrictions is simplicity and portability. How would you represent an object instance in the Objective-C mapping?
 To implement callbacks we use static methods and some platform specific code.
  • 14. Purchase Class ✦ Invoking native interfaces directly is bad practice ✦ They are an implementation detail and should be abstracted ✦ Enter the Purchase class which hides the implementation and also provides a generic implementation based on the JavaScript port of Braintree © Codename One 2017 all rights reserved Calling the native interface directly is often a “bad practice” Native interfaces are often fragile and should be wrapped in an abstraction that hides potential platform issues. For instance if the iOS & Android native interfaces have different features we might be able to hide/abstract it in the Java side which is normally much easier to do than implementing native code. In this code we even have an attempt at fallback code based on the JavaScript port of braintree. It doesn’t work all that well but that’s mostly because I didn’t pay that much attention to it.
  • 15. public class Purchase { boolean flag; public void startOrder() { BraintreeNative bn = NativeLookup.create(BraintreeNative.class); String token = "token-snipped"; if(bn != null && bn.isSupported()) { bn.showChargeUI(token); } else { Form buy = new Form(new BorderLayout()); buy.getToolbar().setUIID("DarkToolbar"); Form previous = Display.getInstance().getCurrent(); buy.getToolbar().addMaterialCommandToLeftBar("", FontImage.MATERIAL_CANCEL, e -> previous.showBack()); BrowserComponent cmp = new BrowserComponent(); buy.add(BorderLayout.CENTER, cmp); cmp.setPage("html-snipped", null); buy.show(); } if(flag) { BraintreePaymentCallback.onPurchaseCancel(); BraintreePaymentCallback.onPurchaseFail(null); BraintreePaymentCallback.onPurchaseSuccess(null); } } } Purchase Compiler Issue iOS VM strips unused code and could remove these without that flag… This class is mostly trivial since the native interface is trivial too. Notice the code at the bottom that invokes the static callbacks. This is a special case for iOS where the VM strips away unused code. By writing this the compiler can’t tell that the code will never be invoked and will keep it in place. Notice that even making a seemingly small change like making “flag” into a private variable might break this…