CRAIG LABENZ: Hello, everybody. Welcome back to the fourth
episode of Observable Flutter I am your host, Craig
Labenz, and today we're going to have a continuation
of our last episode before the new year,
where if you tuned in, you saw me flounder around with
uninstalled Android emulators and overall have a bit
of a yak shaving episode before we could actually
get to the good stuff. But Jose, who kind of
suffered through that with me, has been kind enough
to return today. So Jose is once again
my guest and he's waiting backstage right now. Let's see. I'll switch over to-- Jose, are you ready? JOSE UGIA: Probably. Hello, hello. CRAIG LABENZ: Welcome. Welcome. JOSE UGIA: Hey. CRAIG LABENZ: So you
were just talking about how you wanted to recap
again Google Pay and everything that the package
can do in Flutter. So the stage is yours. Why don't you summarize
for folks what all we can get done with this? JOSE UGIA: Absolutely. Before that, thank you
for having me again. I may get used to
this if we keep on doing episodes together. Yeah, so for the Flutter
plugin for payment, what we were trying
to do last time is collect payments on
your Flutter application with the help of the
Play plugin for Flutter. Just one, maybe, thing
to get started with, one little comment, is that
there's two types of payments that you can collect
on mobile applications. Well, Flutter does
more than mobile, but let's say since
we are covering Android and iOS for this plugin,
let's concentrate on that. One of them is in-app
payments and the other one is physical payments. Without navigating too
much into each of those, we're going to concentrate
on physical payments. Those are payments for things
like clothes, gym memberships, maybe physical movies, things
that exist in the real world that you can order that you
typically pay with your credit card for. And those are the
payments that we are going to enable our
Flutter applications to collect in this episode, as well as
we tried in the previous one. But this time I have
a feeling that it's going to go a bit better. What do you think? CRAIG LABENZ: Yeah,
I think it is, too. So I did end up figuring
out what was-- well, we got to the end. We got to the finish
line in the last episode, but my emulator was going so
slowly that we just couldn't suffer through it anymore. But when I looked at it
later, it just worked. So we actually did troubleshoot
everything correctly. But this time all the same,
you're going to be driving. So you're the Google Pay expert. So I'm pretty confident. JOSE UGIA: Cool. And I'm going to surely need
some support from the Flatiron. So it's good to have
you in the back. So why don't we get going? CRAIG LABENZ: All right. Let's do it. JOSE UGIA: All right so let's
start from the very beginning. We have an empty
folder where we're going to create our project. We're going to start with
a new project altogether so that you get a sense on
how to integrate the plugin right from the beginning. So let's create a
new Flutter project. We're going to call
it Easy Pay Flutter. I think I have to
use underscore here. And while this--well,
that's very quick. So I can just simply go in
there, see what's in here. The typical Flutter
project structure. So let's open it in code. There we go. That looks more familiar to me. And so as we were
commenting a second ago, we want to enable payments
in this application. We're going to sell,
let's say, t-shirts, and we're going to
give our users a way to capture payments. Now one thing to note
is that this plugin allows you to add payment
providers to your application. It doesn't process payments. What do I mean with that? I mean that we're
going to be using Google Pay on
Android applications and Apple Pay on
iOS applications. For those services,
you still need to have a payment processor
in the back like Stripe, Braintree, Worldpay. There's many of them, and I'm
sure you're using one of them already if you're here. What we're going to do is
add this additional layer of payment services that will
make collecting payments easier for your users. It's just one thing
to keep in mind. Great. So we have this
structure of our project. I don't think we need to
launch the app right away. We trust that the projects
that Flutter Create creates are actually looking good. So if you go to the main page of
the plugin pop-up [INAUDIBLE],, which is the one that we are
going to integrate, the pay plugin, you can see a good
amount of relevant information. I think the two areas
that I'll concentrate on is the ReadMe, where you
have a really quick tutorial to learn how to use the package. And then you have the
repository in GitHub because this is an
open source project. But we can talk more about
that in just a second. So first things first. You have a good number
of prerequisites that I recommend you
taking a look into, especially if you're
going to integrate this plugin for
production usage, then you will need
some of those steps. For testing purposes, we
are not going to need those, so we're going to
skip them for now. It's just for you
to know that they are important if you want to
integrate for a production integration of the pay plugin. So let's start by adding
the dependency, which is going to be Version
1.0.11 of the pay package. So let's go. And this is a great refresher
of my Flutter skills. It's been a year since
I've touched Flutter, so we'll see how it goes. All dependents are in need. I already have them. CRAIG LABENZ: We're having
a redundant line there. There you go. Nice. JOSE UGIA: A great
start already. Good. As I say, Flutter
pop executing get. So I have my
dependency available. Let's go ahead and see how the
app looks like in the meantime. So we have a really
basic material app with a little counter. Actually, let me just show it. It's just nicer if I show it. So I'll start Pixel 4 simulator. Now talking about simulators,
there's a couple of things that we learned during
the last episode. One of them is that
you need to make sure that you start a simulator
that has Google Play services because Google Pay works on
top of Google Play services. So if you start a simulator
that only has the Google APIs, then you're not going to
be able to see the button. Now we just took away 20
minutes from the previous video. So we're good. CRAIG LABENZ: More
than that, I fear. Oh boy. JOSE UGIA: I think we
can just run this and see how it looks like. And while this runs, I
see that I have a Buddy. So that's a buddy of my
app with a column view that can have multiple children. I have a text and another text. And then I have a
button at the bottom. So I'll just simply
add a button here. Should we start with the
Google Pay or the Apple Pay integration, Craig? What do you feel like today? CRAIG LABENZ: Well, so we're
on an Android emulator, so I think Apple Pay is probably
the wrong tree to bark up. What do you think? JOSE UGIA: That's an obvious
answer and a good idea. So why don't we go
with Google Pay? We already saw an error, and
that is because the Google Pay plugin-- sorry, the pay plugin-- needs the minimum SDK
version of Android 19 so we need to fix that. To do that, that's a general
user recommendation for doing Android things on your
Flutter applications, is opening Android Studio,
which is, as you know, the most used widely used
ID for Android applications. So if we open Android Studio,
we can simply open the Android folder in your Flutter project. And if you do that, you're going
to have a nice view that you're familiar with about the
Android project in a Flutter application. And what you want to
go is the build gradle in your application folder. Let's switch to the project view
so that we can access the files before the content loads. And then we can open
the app gradle, where we have basic configuration. I'm sure you're familiar
with this file already. And we have a section
in here that it's called mean SDK version. And we saw in the logs
that we need 19 there. And again, this is
because the Google Pay library needs a minimum
version of 19 on the API. So we safe, we think. And now we should be able
to run the application. CRAIG LABENZ: While that
cooks, I have a question. Whenever I've needed
to edit that file, I always just stay in VS code. Are there niceties around
those Android-specific edits that draw you back
to Android Studio? JOSE UGIA: Yeah,
that's a good question. For me, it's probably
because I haven't done a lot of Android
development on VS Code, and maybe there's tools
for doing the things that I do in Android Studio. But I'm personally familiar
with Android Studio. And this things,
like the gradle thing that probably you
also have in VS code. But it's really easy to access. It's easy to find your SDK
directory and configuration under preferences. It's also easy to launch
and manage your simulators. You can see your simulators
in VS Code and launch them, but it's also the manager
for creating new ones or changing the configuration. For me it's
definitely much easier to find in Android Studio. CRAIG LABENZ: Yeah, indeed. I've certainly never configured
an Android emulator in VS code. All right. We're back. JOSE UGIA: How far
should we get to? OK, it looks like this works. CRAIG LABENZ: 12,000. JOSE UGIA: Maybe
this breaks up at 59. Oh, yeah, broke. Actually, no. It works. So that works fine. So we can go back. CRAIG LABENZ: Oh,
real quick, chat is asking to increase
the font size. Be good to go full screen
on your IDE window. And then yeah, full screen
up until the emulator. Yeah. And then a couple
command pluses, probably. At least could maybe
do another one. And yeah. And then you can get
rid of the left bar if you're comfortable with
that, which I think is-- nice. You got it. All right. JOSE UGIA: Sorry for that. Good. All right. CRAIG LABENZ: Good call, Damien. JOSE UGIA: Thank you, Damian. I would have some space here. What do you typically
recommend here in Flutter, size box or
margins or something else? CRAIG LABENZ: Oh. Size box is always fair because
you can const to that as well. Of course, if you have a
responsibly sized size box then you can no
longer use const. But-- oh yeah, there you go. I think that'll do it. JOSE UGIA: So there's
the Google Pay button, and there's a few
required prompts that we see right away here. One of them is called
payment configuration asset. So if that doesn't
make sense to you, there's a little note to
that in the tutorial right at the beginning, right
after you add the dependency. So this is basically
a json file now. It's going to be a configurable
string in the future, in the really short
term future, where you add information about how
you want your payment to be. And to make this a
bit easier, there's a couple examples in the GitHub
repo in the assets folder. So let's take a look at a
basic one for Google Pay, for example. As you can see, you have
things like the types of card that you want to accept, the
networks, the payment gateway that you use, and maybe some
information about the items that you are selling. Some of this information
can be dynamic as well. CRAIG LABENZ: Can you increase
the font size on GitHub as well? Yeah, nice. JOSE UGIA: Hopefully this
works for the others. Yeah, good. So yeah, it's just
basic information about how you want Google
Pay, in this case, to work. So we're going to take one
of those as an example. Let's take the default
payment profile for Google Pay so you can see
similar information. I'm going to copy that into my
assets folder on the Flutter project, switch to screen
and assets folder, and then a new file. That's going to be
Google Pay config.jason. Paste that information that
I'm personally happy with, let's say, maybe,
for the address. I don't want to have my
phone number required because then you're going
to see it on screen. And then everything else
looks good, I think. CRAIG LABENZ: You don't
want us hitting you up with the late night texts? JOSE UGIA: Yeah,
especially given that this is PSD friendly. So in six hours, that's
going to mean wake-up calls. CRAIG LABENZ: True. JOSE UGIA: All right. Oh, one thing that I have missed
already is that I have an asset now. I have a json file
in my assets folder. That means that
I need to specify that on my
pubspec.yaml, I think, and tell it that we're going to
have some files in the assets folder. I think that they
should suffice. Now all we need to do is
just pass in the name file. That will be enough for
the Google Pay button to figure out what
it needs to do. This has a callback for
whenever the payment throws-- returns a result. So now
you're going to print it so we can see it on the screen. And we have a list
of payment items. So this is going to be because
every time you sell something, it's going to be something
different with a different price and different text. That's something that you can
pass to the button dynamically. You can build it based on
the status or the things that the user is buying. And then you can pass
it onto the button. What we're going to do, just
for the purpose of this example, is add it as a const in here. That's going to be
called payment items. It could be an array of items. You can have multiple items. For example, let's
say that you have a final invoice or a
final checkout page that has two items, and then
maybe some VAT, and then a total price, and
you can have all those for different
items on this list. CRAIG LABENZ: So this is
essentially someone's cart when they're checking out, right? JOSE UGIA: Correct. This is what's going to
show on the payment sheet when Google Pay
or Apple Pay opens to give the user information
about what they are paying for. So you don't need
to have, maybe, the same level of detail,
but something that you think is enough for that
amount of real estate in the screen for the user
to recognize the payment. Let's just say that
label's going to be total. The amount is $100. And the type is going
to be payment item type. CRAIG LABENZ: Did that total? Is that we're looking for? JOSE UGIA: Status. So the status will
indicate what's the-- I'm trying to look for a
word different from status, but nothing's coming to mind. So basically, it's just
telling your customers about the status of the payment. That is whether the payment
will change or isn't known, or the price is final. So let's say, for
example, you are selling, or your users are buying a
ride on a bike sharing service, and you don't know what the
total amount is going to be. But you have a fixed amount. You have a fixed rate. So you can set that fixed rate
as your payment item amount, and then specify or set the
status as a known, or something that is pending that will
change after the ride happens to give the user, again, that
kind of visual indication that the price is not final. In our case, the price of the
share that we're going to sell is going to be a final price. So you can very well
say that it's final. CRAIG LABENZ: Is there
like an estimated status? I'm just thinking about someone
getting on a ride share. Oh, pending. Yeah, things like that
would probably be it. JOSE UGIA: Yeah, but
that's also the result of trying to make
both buttons work. I think, in fact, Google
Pay has an estimated flag. I believe so. But not Apple Pay, so I think
payment works for both of them. But this could be one
of those scenarios in which it makes sense to
split them in the future. CRAIG LABENZ: Yeah. Yeah. JOSE UGIA: All right. So let's pass the payment
items to our Google Pay button. And with that, we
seem to be ready with the basic integration. And already saving, shows
the Google Play button on the screen of
our application. So let's go ahead and try
to pay and see what happens. All right. So my test account is showing
there with a test card as well. So there's nothing
interesting about it. So you can see I have
all the information. I can change the account or
change the payment method. When I'm ready to go,
I can hit continue. But before that, you can
see a red text in there that is basically
telling us that we are operating in test mode. That is, no charge to your
card is going to take place until you go into production. So if I hit Continue,
nothing's going to happen. I'm going to receive
a test response. So let me do it. And you can see the
payment sheet disappeared. And then as I was printing
on the payment result, I'm getting that
information here, this kind of map or
dictionary-looking data. And as you can see here,
we have some information about the payment like
the billing address, like the card used to pay. This is all metadata for you to
use until the payment happens. The most important
bit of information here is the tokenization data. The information
behind this parameter is what you need to send to
your payment gateway or your PSP to actually process the payment. And since we are
operating in test, this just has some
dummy information. So on the token,
so you can see we have something that looks like
example payment method token, whereas in a
production environment, you will see something
that is not readable. It's basically an
encrypted payment payload that your PSP will
be able to process and issue the order. CRAIG LABENZ: And that token-- there's no other keys in this
nested dictionary, right? It's just the token actually
contains the goods outside of the test environment. JOSE UGIA: That's right. Yeah, that's internally a little
like another nested dictionary, but it's encrypted so far. It's just like an opaque
blurb of charts, really. CRAIG LABENZ: Nice. JOSE UGIA: OK. What are the things we
can do with this button? Well, I'll get to
that in a second, the different integration paths. But there are some other
fields that we can have in here just because this button
is managed, quote unquote. With that I mean
that the button is doing a lot of things for you. You can configure also
a number of parameters. For example, you may want the
button to be hidden if the user in question cannot
pay with Google Pay, and instead show a
different widget. You can do that with
the child under a param. You can, for
example, add a text. Let's actually try it. Text saying Google
Pay is not supported. This will be shown as a
replacement of the Google Pay button. So if we do this, and then we
mess with the configuration, let's say we break it
like that and reload, the baton shouldn't show. I think I've broken it so much
that the json is incorrect. So it's breaking before it's
saying your json is not valid. So let's say-- just make
it a bit easier for it. CRAIG LABENZ: So the
json will at least parse, but then it will be-- wow. JOSE UGIA: So you see-- let's say for your app, you're
supporting, like, 20 payment methods, and you
simply just want the ones that are not
supported to hide or show something different. You can use that child
[INAUDIBLE] for that purpose. I think it's handy. CRAIG LABENZ: Yeah,
that is quite handy. So Jose, we have a few
questions in the chat. We've already basically
gotten further than we got last episode
because your emulator works out of the gate. So I was thinking we
could maybe pause and chat about a few things, including
maybe this question to start. Oh, it went away. I don't know why it went away. Where is the first
part, Junveld asks. And the first part
is on YouTube, but you've already seen the
entirety of that episode in terms of Google Pay payments
collecting everything progress. Only watch that
episode at this point if you want to watch
me try to install Android emulators
on a computer that was overtaxed by streaming. But good question. And this is a similar
question that we had from last week, Jose. Can you speak to the
relationship with Stripe? You mentioned a little
bit about it a second ago, that there does still
need to be a payment processor in the background. But can you say
a little bit more about how Stripe
factors into all this, and the Stripe library? JOSE UGIA: Yeah. So Stripe is a payment gateway. That is a collection
of services that will help you collect
payments in your services, in your application,
your backend, in your mobile application. It's the responsible
entity of moving the funds. If you need to collect
$20 from your customer, then the actual transfer of
funds will be done by a PSP, by Stripe, for example. Google Pay, or a
payment facilitator like Google Pay or Apple
Pay, they are not actually doing the transfer funds. They're not doing the
processing itself. They're simply helping
your customers to pay. Why? Because in their Google accounts
or in their Apple accounts, they already have their
frequently used cards that they use for online payments. They already have them there. So they don't need to type
them every single time again. So when you use
Google Pay, you are giving that ease of checking
out to your customers. So they can just simply click. With a couple of taps,
they can simply check out. And then that information
of the payment method that they have selected,
that information is then being sent to your payment
gateway, for example, Stripe. There's multiple
payment gateways that connect to or can be
used with Google Pay, also with Apple Pay. You have them in the
Google Pay documentation site, which I can
write somewhere, maybe in the comments. Maybe it's not a good
idea in the live stream, but you can find them there. And many of them have
APIs, as the case in libraries, that you can use
in conjunction with Flutter. Concretely for Stripe, they
also have a Flutter plugin that it's very easy to
use with this plugin. So basically you will get what
we have in the payment result here, the payload that has
been returned from Google Pay. In this case. They have a method,
they have a little class with the method that
takes that and creates the order on the Stripe. And so there's other
pieces like that will make that integration very easy. And I hope that
addresses the question. Let me know otherwise. CRAIG LABENZ: Yeah. I think that was quite detailed. Thank you. There was another question. This is a little
Android-specific, and I kind of gather that
you have a bit more Android experience than I do. So I was curious what you
thought about this question. Out of curiosity,
why didn't you locate the flutter.minSdkVersion
property rather than directly inserting 19? I have guesses, but
they are just guesses. JOSE UGIA: OK. Yeah. Let's try with the combined
knowledge of everyone here and see if we can
find a solution because I was looking into this today. I wanted to know where
that property was set. And I was just looking
around on Android Studio and I couldn't find it. So if there's a way to do
this, that would be fantastic. Maybe if you know, Lodeki Brian,
or you know Craig as well. I was looking in gradle
local properties. You have some of them here. But there's not minSdkVersion. So if we could find where that
is being set, that'd be great. Do you know where those are set? CRAIG LABENZ: I don't. That's why I was saying
I have only guesses. I mean, so I would
start by just grepping for that string, minSdkVersion,
see if it shows up anywhere. But it might be a thing
that gets string replaced at build time, and it comes from
some kind of deep buried place. Yeah, I'm not sure. So OK. Yeah, here we have-- but 19, that's
what you set it to. So these are probably
built artifacts. JOSE UGIA: Yeah,
those are build times. The manifest has been-- yeah, this is build directory. CRAIG LABENZ: So is
there anything not in the build directory here? JOSE UGIA: This one, which
is what we set it to. CRAIG LABENZ: Yeah, OK. So my second thing that I
would do to figure that out is just ask someone
on the Flutter team who works specifically
on the Android bindings, and then they'll just tell me. But no, I don't know. That was a great
question, Brian. JOSE UGIA: Yeah, I was
looking for that one. And I think it would be elegant
if we could do it that way. Yeah. CRAIG LABENZ: All right. Two more I think that it
would be good to get to now, and then we'll carry on. So this question is kind
of a mix of information about mechanics
of the API itself, and then just, I
think, a little bit of maybe general
application development. Oh, I clicked the wrong one. I do want to get
to this question, but the list jumped on me. Shivam asks, but what if we try
to send the token information to our payment gateway
but the API call fails? JOSE UGIA: Yeah. So that's logic,
that's business logic that you have to handle
in your application similar to if
something else fails. Like if any part of the
process of the payment process fails, then at some
point, you would want to show some
error to your users, or maybe even retry before
you show some error. So that really depends on your
strategy towards resilience, how defensive you're
planning to do it. But that's something that
falls under your responsibility because we--well, we-- let's say Google Pay,
or any payment provider, will give you the
payment information that the user chose when they
opened the payment sheet. But then you will have to
send it to your gateway. So if that fails, then you
have control over that, and you can react to
it if you need to. CRAIG LABENZ: Yeah. So I'm going to try to restate
what I'm hearing you say here. The interaction with
the pay package, that's kind of all on device. And then once you start to
send that information to Stripe or whomever, you've now left
the universe of this package. And so an error
that you get there, that's just entirely outside
the scope of the pay package because you've moved on to
the next step in the process. Is that right? JOSE UGIA: Yeah. Correct. Maybe we can illustrate
it a bit more. So if instead of doing print,
we create a little method that takes the result.
We call it on Google Pay result. Void on
Google Pay result, and then payment results. So that's what's going to be
called when your users select a form of payment. And what you have to do here
is something like your PSP library, create order
in result.token, something similar to that. So let's reload this. CRAIG LABENZ: Yeah, what's
it upset about there? JOSE UGIA: Well,
maybe like Ascii code. Just doing command
space and creating a unrecognizable character. That happened to me so, so
many times, so many times. I don't know. Maybe it's my typing skills. CRAIG LABENZ: That's
never happened to me. JOSE UGIA: Yeah, it's
definitely my typing style. But I have a really weird
typing style, I have to confess. CRAIG LABENZ: We
computer differently. JOSE UGIA: When you continue,
that payment selection is going to be sent
to this method. And then you're going to
call your PSP on that line, either through your back end or
directly through their library, containing the result
of the payment. If this request fails,
however you want to do it, something like, maybe, const
result, and this fails, a result equals some error. CRAIG LABENZ: Retry logic. JOSE UGIA: Then
yeah, retry logic. That's really in your
hands and something you have control over. CRAIG LABENZ: OK. Oh, there's another
question, and we've kind of lightly touched on
this, but I think it might be interesting
to talk a little bit more about the mechanics. A GDE from Thailand, Vuong-- I hope I'm saying that even
remotely close to correctly-- says, can we run this payment
process in the dev environment? Now we are in the dev
environment right now, but what are the exact
limitations of what we can and cannot do? I mean, obviously, we didn't
get a real token there. So Stripe is not going to care
about your token here value that we just got. So do we have to turn
off the dev environment to integrate with Stripe? Or can we kind of connect to
a dev environment in Stripe as well? JOSE UGIA: First of all,
thank you for the question. I really enjoy this
topic, and I think it's very important, especially
in the context of payments. You want to make sure
that everything works. You want to make sure that
this is part of your testing protocols or processes. So now, as Craig pointed
out, what you get is a dummy response
or result. That means that you have to test
both services separately. You have to test
Google Pay in one hand and then your payment
processor separately. Wouldn't it be great if you
could test everything together, like in a more end-to-end-like
test in which you could retrieve the test
result from Google Pay, and then send that to your PSP,
and your PSP confirming that and say, hey, this is
a test transaction, but this worked fine. You can go into production. That's something that is not
possible today on Google Pay nor Apple Pay as far as I know. We are, though,
working internally to tackle precisely
just that and give you a set of test cards. You probably familiar
with PSP's test cards. They have a collection. They are different
in each group. They have a collection of
test cards that you can use. CRAIG LABENZ: 4444
and all those. Yeah JOSE UGIA: Yeah. To test different scenarios. So we are working
on providing you with those cards on
Google Pay so that you can test the entire transaction
end to end with your PSP, which we're personally
very excited about, and we think it's going
to make a big difference to your testing
processes, hopefully. CRAIG LABENZ: Nice. Well, yeah. That would be amazing. OK. Last question for
now, I promise, then we return to the features. This is a great question
that I had as well and I think we got last week,
and it's definitely worth hitting again. Mangirdas asks, can we
load the payment items from an API, maybe
Firebase Remote Config? Or are these expected
to be constant? And he's asking this, of
course, because we just showed this hardcoded asset file
that wouldn't be very mutable. So Jose. JOSE UGIA: Yep. Well, thank you
for the question. We're getting such
good questions. This is incredible. It's literally the things
that I wanted to talk about, I was writing not to forget. And then everyone was helping
us cover those topics. So thanks for the
question again. We have a variable here, or a
param in the Google Pay button widget, that lets you add
payment items in here. You can put literally
anything valid in here. That is, with valid I mean
a list of payment items. You can construct
that in however way you find it more useful. You typically do
it, as you suggest, that you load that
information from somewhere. In fact, we would recommend you
doing that because as you know, client applications are, by
default, not safe in terms of security. So you want to make sure
that your important things like the price come from a safe
place or a safe environment like a protected
back end system. And so what you do, you
fetch that information from your back end, and
then with that information, you will construct
your payment items. Instead of hard coding
like we are doing here you would build
those little fields as a result of what you get
from your back end request, if that makes sense. CRAIG LABENZ: Now I have
a related question here because the payment
items, this is like what the user is buying. So of course, this
wouldn't be hardcoded because who knows what they're
going to put in their cart? A question that I
actually misread, Mangirdas's actual question and
what I thought he was asking, was about that Config. And that was the question that
I thought we got last week. And I have honestly
not even really studied what goes in that json,
the Google Pay Config. Is it a realistic
need for an app developer to have the contents
of that file be dynamic? JOSE UGIA: Yeah. And I think there's
a use case for that. Right now it's only possible
to either create them-- so let's take a
step back quickly. There's two ways of
integrating this plugin. One of them is what we
call the easy or the manage the quick setup in
which you have the widgets, you place them in your
UI and you're good to go. There's another,
more involved way in which you are doing
each request separately. In the advanced
use case, you can pass in the configuration
as a string as well. That means that you
have full control over changing that or making
that as dynamic as you need to. Now we are also working on
bringing that dynamicity, to if you can say that word,
that kind of dynamic nature to the widget as well. So we are--there's in fact, a
pull request open that will be merged in the next few days
that will give you the ability to add a dynamic configuration
to the quick or easy integration path as well,
because we agree with you that there's a good reason to have
a need to have this information change. You may have, for example,
in multiple countries, you may want to support
different payment methods, for example. There's a whole
gazillion of cases that you may want to support. So yeah. That's a good one. CRAIG LABENZ: All right. So all of the things
are flexible at runtime. OK. Well, I've interrupted
you for quite a while here with some great questions. And now I ask you to just
pick up your train of thought from 15 minutes ago. JOSE UGIA: Should we do Apple? CRAIG LABENZ: Sure. Yeah. We do have some questions,
actually, also about whether or not it supports iOS
and Apple and all that. So hooking up Apple Pay would
certainly answer that question. Do we need to switch emulators,
and is your iOS emulator ready to go? JOSE UGIA: I think so. But before we do that,
just one quick thing that I forgot to mention is that
you can have multiple button types because you may want
to have a pay with Google Pay or something different. So the type param in
the Google Play button will give you a few options. So you can go with donate, for
example, and then the label will obviously change. So you can use that to
make the Google Play button adapt to what you're
collecting payments for. CRAIG LABENZ: All right. JOSE UGIA: So yeah. In the same application-- that's
the whole purpose of Flutter-- we're going to add
a Apple Play button because we want to support
with this application both platforms. We need to start
a iOS simulator. And that's something that I'm
used to seeing here below. Oh, we just didn't have space. That's why I couldn't see it. So let's start
the iOS simulator. CRAIG LABENZ: In
the last episode, I was having trouble
getting this going, and we concluded that it would
only work on a physical device. Was that wrong? Was I just doing
something incorrect? JOSE UGIA: That was
not my conclusion. Maybe it was your conclusion. CRAIG LABENZ: Oh, OK. Well, great. I'd love to have my
conclusion disproved. JOSE UGIA: It should work. It could be that
there's something you need to enable
here in this simulator that I already have enabled. I don't recall needing to
do that at the beginning, but there's certainly
some wallets or Apple Pay configuration in here. Like here you can see
authorize Apple Pay. Again, I don't think
I needed to do that. For me it was just adding
an account to my simulator, and it was working. CRAIG LABENZ: All right. Well. JOSE UGIA: And I
don't think that was your issue, to be honest. OK. So similarly, we need a
configuration asset so let's go ahead and
look for a sample configuration for Apple Pay. So just so that I don't have to
write the whole thing myself. That will take a long time. And yeah, it's going to
take away some precious time that you don't want me
to take away from you. So we'll crop it and
we'll create a new asset called Apple Pay Config.json. Instead, you'll see
similar information here. Some of this is tailored more
towards what the Apple Pay library expects, like
the merchant identifier. Or you see that the
supported networks have a different format as well
as the merchant capabilities. You can find detailed
information about what is expected
here in the Apple Pay documentation the same as
you can do for the Google Pay configuration. You can find it in the reference
for the Google Pay online API. So let's say that this
all looks correct. So you can see here we
have some shipping method information as well that will
be added as options to the user. So going back to our Apple
Pay button in our UI, we are going to add
the configuration file. And for the result,
we're going to emulate what we had before on
Google Pay and just print it to see what's the outcome. And I think the same
payment icon should work for Apple pay as well. So I think we can just
go ahead and launch it. One question that I have,
maybe you can help me with, is if I'm running my app
on a Android simulator, can I run it at the same
time on an IoS simulator, or do I need to
stop the session? CRAIG LABENZ: You sure
should be able to. If you think back to Flutter
Interact in New York in 2019, this is a bit of a deep
cut, but Chris Sells, who was then still on the
Flutter team, demonstrated-- what was it called? The Flutter Octagon or
Octopus or something. I think it was actually
just seven, but nearly eight versions of the same
app running at the same time off one laptop connected to
a ton of different devices. JOSE UGIA: I wish
I'd been there. CRAIG LABENZ: It
was a fun event. Right before COVID hit. We had no idea that it was
going to be the last time we all got together for so long. JOSE UGIA: Maybe
next time, though. CRAIG LABENZ: But
yeah, you should be able to click and fire it up. JOSE UGIA: I should
have better chances on being part of the next event
after having been here to you twice. Maybe just it's just
wishful thinking, but that's what I
have in my mind. CRAIG LABENZ: You are
now on the list of people that I will reach out to
about speaking at events. While this builds, I think
there is a question that we can probably cover rather quickly. Luxmi asks, will this help
with in-app purchases? JOSE UGIA: It won't. Thank you for the
question, Luxmi. This comes back
to the distinction that we made at the very
beginning between the types of payments that
you typically can get on a mobile application. One of them will
be in a payment. Those are payments
which are generally digital goods which are bound
to your application and the App Store, or the Google Play
store, things like, for example, features of your app on a
premium version of your app, or digital currencies
or lifes in a game. Those will be good
examples of digital items that you need to collect
using in-app purchase and the in-app
purchase libraries. This is different. So those will not qualify
from using the online APIs for Google Pay or Apple Pay. The payments that we are
talking about in this session are payments for, typically,
physical items like clothing item, like a new speaker, like
a gym membership, those which are outside of the
policy of the app stores, and those that you typically
collect payments through PSPs or through customers
paying with cards directly. It's important to
make this distinction because if you qualify, or if
your app qualifies, what you're selling is part of the
policy of the App Store, collection in-app payments,
you have to use that one. But if it doesn't, then you
can use physical payments. You can use Google Pay,
Apple Pay, and your payment processor. So I hope that clarifies,
but if it doesn't, there's a really nice summary, at
least on the Google Play side, giving you a few bullet
points to help you to help you make the distinction. But rule of thumb
generally-- again, not for all cases-- generally,
digital goods, in-app payments, physical goods, you
can use your PSP with Google Pay or Apple Pay. CRAIG LABENZ: Nice. All right. We're up and running. JOSE UGIA: So we
have the button. And we'll see what
happens today. I don't like it when everything
works on the first attempt. Maybe there's something
bigger to happen later on. CRAIG LABENZ: Well, there
are some predictions in chat that it isn't going to work. JOSE UGIA: All right. CRAIG LABENZ: We'll see. JOSE UGIA: Make it a
bit bigger, and let's change the type as well like we
did for the Google Play button. As you can see, we have
now the available types are different because those
are the ones supported by Apple Pay. So let's say in store. That's a bit confusing
if we say in store because it looks like a
different in-app in store. That's not the case. That probably means
in a physical store. CRAIG LABENZ: Also, the
button is not changing. JOSE UGIA: And I think
that's because it's a-- well, it just refreshed and
it's not changing either. So my hypothesis was
that given that this is like a native platform
component on iOS, so this is building the Apple
Pay button using the Apple SDK, it needs to restart the app. That one's not working either. So let me try this one. Problems. I like it. CRAIG LABENZ: Surprising. JOSE UGIA: And let's see
if we have enough space. We do have enough space. CRAIG LABENZ: The 50
looks nice, though. 450. Oh, 45. JOSE UGIA: 45 is the actual one. Good. Type, and that's the right one. Apple button type. That should be fine. Let's see. Let me go for the basic obvious. Oh, we have two instances. I code the wrong one, I think. Yeah. Oh, maybe that was the case. Yeah, that was the problem. I was refreshing on the
Android one, I think. Correct. CRAIG LABENZ: Hey, look at that. All right. Well, that's a
little foot gun to be aware of when you've got
multiple simulators going in parallel. JOSE UGIA: So let's say bye. Why don't we go ahead and try
to pay with Apple Pay, Craig? CRAIG LABENZ: Let's do it. JOSE UGIA: All right,
let's try this. So I click the button. This is in Spanish. Why? Because I think
this is configured-- yeah, this is a Spanish phone. I can simply hit on
pay with my code. And then as the
payment succeeds, then you see a similar
response as the one we saw on Google Pay, this time
with Apple Pay information. And concretely, the
interesting part is the token, which for Apple
Pay, comes empty in test mode. CRAIG LABENZ: OK. So that's what
people in the chat were saying, that it wasn't
going to give a token. But we can still get this far. And we didn't get a token
on Google Pay, either. We just got a dummy string
that was like example token or something. Exactly as valuable as
the empty string here. JOSE UGIA: True, although it
looks more kind of working. Just gives you a weird feeling. CRAIG LABENZ: Right. It does, that's true. All right. Well, this is
everything that we're trying to do in twice
as long last time. JOSE UGIA: Not bad. There's something else that
you can change on the Apple Pay button, and that is the style. You can have a black,
white, or outlined button. So if you feel that your
application goes better with a white outline, you
can change it as well. Without even
knowing it, you were answering Hamza's question. Can you change the
pay button color? You changed. JOSE UGIA: There's
some connection here. CRAIG LABENZ: Now I'm wondering,
without maybe opening up a massive can of worms,
using the standard branded buttons is definitely
a good idea because that's what
users are used to. But what if I wanted to just
start this process from my own on click Handler? Like if I made my own
button for some reason, maybe I had odd responsive
constraints or something, and I have my own
widgets, but I want to trigger one of
these workflows. Is that something that the
pay package supports easily? JOSE UGIA: It does. There's two things
to your question. The first one is, can I use
different assets for the Apple Pay or Google Pay buttons? And the answer to that is no
because you would be violating the branding guidelines. So when you submit your
application for approval so you can use Apple Pay or
Google Pay in production, that will not go through. You will get an email
back saying, hey, you have to adjust your button
to look the way it is intended. And you can see more details
on that in the documentation. Now to the other part
of your question, you can have more
control over the flow. What we saw here is that you're
adding a widget to the UI, and you can see there's
some things happening in the back room that you
don't have full control over like the press
event, or what button to show in which
scenario if you're in the right platform, and if
the payment providers support it. There is a advanced
integration path that is also explained in the
documentation for this plugin that you can use to have full
control over the whole process. And we can take a look if
we have some time at the end as well, or maybe even now. CRAIG LABENZ: Yeah, there's
an interesting and related question in the chat. Fabian asks, can the language
of the button be changed? JOSE UGIA: Yes. So the plugin
supports localization. So if you add localization
information to your application right away, the button
will recognize that and will show the button
in the right language. But remember that
you have to include that in your application
the Flutter way. I cannot fully remember, but
I think it was a property on the app or on the theme. And then change the
locale of your phone, and then the button
will adapt to that. CRAIG LABENZ: Got it. Nice. Great. OK. So are you ready to move on or
is there more to cover here? Because I know you've
gestured multiple times about an easy path, which
we've currently gotten working, and a more advanced
customized path. JOSE UGIA: Should
we look for trouble and do the advanced one? CRAIG LABENZ: If you're ready. JOSE UGIA: All right. Let's try it. So let's say that you
want to have control over the events on how
the button is integrated and how things show. You have a little excerpt
here about the advanced usage. But basically, it's
not super complex. To be honest, I just like
to say that beforehand. But there's two main
things that happen when you use the pay plugin. The first one is
the library will check if the user that
is using your application can pay with that
payment provider, with Google Pay or
Apple Pay, in this case. And if the user
can pay, that is, if you have an iPhone or
an iOS device on Apple Pay, and then you have
a created account, and you have cards
of it, then that means the user can
pay with Apple Pay. Then the button will show. This is something that
happens automatically on the quick integration path. As you saw, there's
nothing else that we need to do to make that work. The other main important
call, or API event that happens is when the
user clicks the button, then you see the payment sheet
is coming from the bottom so that the user can
select a form of payment and confirm the payment so that
you get that information back as a result. So it's mostly two
calls that were being done automatically,
or automagically, for us in the quick path. Now if we wanted to take
control of that, we could do it. It could be that in
your application, you need to do that because you
have a really kind of detailed way of controlling your
checkout process in which, instead of if the user
cannot pay with one provider, instead of not
showing the button, you want to do something else,
maybe go to a different screen, maybe log to your back end. So for those scenarios,
the advanced path could be interesting to you. My recommendation would be
that if you are integrating this plugin for the
first time and you don't have a concrete
specific need, I'll encourage you to try the
quick path because I believe that path is going to
work for most of you. And as you saw, it's
very easy to integrate. And then if you see, or if
you come across a situation where you need to
go a bit deeper, maybe do things in a
more particular way for your application,
then that's when I would consider
the advanced flow. So without further ado,
let's take a look at that. So this is just one thing
that we add into the sauce, and that is a pay client. That is the little
object that will help us do those requests that
we were just talking about. So let's create that pay
client inside of our state to make it more concentrated on
the parts of our application, keeping things modular to
where they need to operate. So that will be an
instance of pay. And you will see that there's
a few ways to instantiate that. And one of them
would be with assets. And no way I'm not getting
the auto-complete for that. That's basically replicating
what we just did before, which is simply letting us pass
a list of configuration json files that the pay client
will have to deal with. So that looks very
similar to what we were passing the buttons before. So let's just add
the same thing. Why are we doing this? Because the client
needs to know what's the actual configuration for
both Google Pay and Apple Pay, in this case. And I'm getting an error here. Why? Because this is not being used. We are going to fix
that in a second. So we said that
there's two main calls. The first one we're
going to figure out is whether the user in
question can pay with-- let's do it on Google Pay
just to make this easier. I know where my simulator went. It's here. So let's use Google Pay for now. So this first
request that we have, to know whether the user
can pay with Google Pay, it's in a sinkhole. So we'll use something
called the feature builder that I'm not
very familiar with, but I have some help. So I'm sure we're going to
be able to figure that out. CRAIG LABENZ: With
our powers combined. JOSE UGIA: Let's try that. Let me comment that out so
we don't see anything else. And then I use a feature
builder that will load widgets as a result of an asynchronous
call, in this case, user can pay. So the builder, it
has this signature. That's the builder prompt
that has information about the actual query. And then that will
expect a widget as a return, whatever
we want to show. This feature builder
widget will also have a feature that is,
what do we want to load? What is the async call
that we want to make? That's going to be
part of the pay client. So quickly the user can pay. And we are going to pass the
pay provider of Google Pay because we want to find out
about whether the user can use Google Pay or not. So that's all we need. Now we need to respond to the
multiple instances of results, but this is [INAUDIBLE]
can give us. So we're going to
use curly braces. And then I think that's
one too much, maybe. So let's just add a placeholder
size box for all the cases that we are not going to control
from that just so that it doesn't throw an error. But basically, we want to
cover two different scenarios. One when the call is being made,
when we want to show something like a spinner or a loading
indicator to let the user know that, hey, there's
something going on. Just wait. Wait for it, it's going to come. And I think, if I
remember correctly, that's behind the
snapshot property. Concretely, connection state. I think that's connection state. CRAIG LABENZ: Yeah, It depends. The connection state
could be multiple things, or there could be a
data value that changes. I mean, I'm not sure what the
user can pay method returns, how that works. We'd have to interrogate
that to be totally sure. JOSE UGIA: It's going to make
a network request to the Google Pay servers. CRAIG LABENZ: OK. Then I think you're checking
to see--OK, this makes sense. JOSE UGIA: Yeah so let's
show a circular indicator while the whole thing loads. And then when the
connection is finished, so that is the request, we
have a result from the request. Then we're interested in two
different use cases as well. We want to know
because the answer, or the result of
this query is going to be either true or false. True, the user can
pay with Google Pay. False, these cannot
pay with Google Pay. And you really want to show
something different in your app based on that. So now we're going to
look at the snapshot data. And if that's true,
that means the user can pay with Google Pay. And in this case, we want to
return to do, return Google Pay button. And if that's not the case,
let's go back to our previous example and show a
text saying, hey, the user cannot pay
with Google Pay. Google Pay is not enabled
in this device, for example. Google pay is not
anywhere on this list. And it doesn't apply
anymore because we are returning a widget
in every single instance of our if else tree. [INAUDIBLE] Now before we use a widget
called Google Pay button, which has all that business
logic inside that is doing all those
queries for you, all those network
requests for you, we have a simplified
version, or UI-only version of the button that it's called
raw Google Pay button when you are interested
about the graphics, like it's the case here. And as you can see here,
there's only a few things that you can configure. The type of the
button, we are going to stick to our donate button. And the on pressed event. You can see that
this is-- actually, we can const this one
as well because it doesn't have any state inside. Keep me true on
those things, Craig, but I believe that's the
reason why you can const it. So we have all the
logic ready, so we can try to run this
and see what happens. I'm not sure I have everything. I do believe I do. But let's try. So what should happen
is that the pay client should be instantiated. It should make a call to
the user campaign method, and this method
should return true because I'm running this
on Android simulator with an account that
has Google Pay enabled. This is running on the iPhone. So in fact, let's let
it run because that should return false. I don't think it's finished yet. This is probably
from the previous. It's very convenient, though. We could just say, oh, it
works and go back to Android. CRAIG LABENZ: Right. You typed the exact
same sentence. JOSE UGIA: Let's see. Yeah, that's running now. So that's good. Now we are going to
go back to the Android simulator, for which I need
to make this bigger on Pixel. Run. Go back. CRAIG LABENZ: Now
while this is building, there's one thing I want to
talk about, which is line 119. The FutureBuilder has a
really kind of alarming foot gun where if you call
a method like this in line, and that method doesn't kind
of memo-ize its own network request, and if this
method makes a new network request every time
you call it, then you can unlock some
pretty terrible race conditions in your Flutter app. So the best practice for
that method on line 119 would be to put this in
a stateful widget, which I think we're in
a stateful widget because we're still in the
counterpart of the counter app. Yeah, and then just save
that future in init state. And then actually use
the future in the UI. JOSE UGIA: Something
like this, right? And then we have to
overwrite in InitState. Where is actually that? Is that something that I
can override in this space? CRAIG LABENZ: Yeah. Yeah. I'm not sure why you're-- JOSE UGIA: Oh no, not here. CRAIG LABENZ: Yeah, you just
can just make a new method basically, InitState. I'm not sure why your
snippets didn't pick it up. JOSE UGIA: Is it like override? CRAIG LABENZ: Yep. And then you can
call super.InitState, all that good stuff. CRAIG LABENZ: And then
user can pay future. Oh, that would have to be-- why is this complaining? Late. Does it have to be late? JOSE UGIA: Yeah. Late, I think, will work. Or nullable. Actually, nullable
is probably better. Is nullable a-- this? How you call it? CRAIG LABENZ: Oh, a question
mark at the end of the title. Now that I'm thinking about it,
would we want it to be late? JOSE UGIA: Late is
actually appropriate because we wanted to alert it
once and not change anymore. CRAIG LABENZ:
InitState will be run before the first build method. So late is fine. JOSE UGIA: User can pay
future that is pay client. User can pay. Pay provider, Google Pay. Doing things right. And then here, you can change
this with user can pay future. I like it more this way. CRAIG LABENZ: Perfect. JOSE UGIA: This works fine. So now we're making sure
that it's all equal at once. Great. Now I click the button. Nothing should happen. It's not even clickable
because the on pressed. I remember we are now in
the advanced integration. That is, there's nothing
being done for you. You have full control
over the whole flow. And that is if you haven't
set a press callback, the button will
not be clickable. So let's go ahead and do that. On pressed on
Google Pay pressed. And that doesn't exist. That's why it's complaining. Let's do it right above, which
makes more logical sense. Pressed. And then here, we'll be able
to do show payment selector. And we can save that
already, and the button should be clickable. Not yet. On Google Pay pressed. On Google pay pressed. CRAIG LABENZ: Guessing
it's a signature. Oh, invalid constant. Yeah. A closure. So we just, on line 135,
we've got to drop the const. Yeah, 135 down. JOSE UGIA: Oh. yeah. Sure. Yeah. We get red. And that's because-- CRAIG LABENZ: Yeah. Now we'll need to restart. JOSE UGIA: And now
it's clickable. All right. We are on track. Now what's the second call
that we are interested in? The second one on the
pay client as well is show payment
selector because now, when the button is clicked, now
you want to show the payment sheet so that users can select
their payment method that they want to pay with. And here, as you can see, we
need the payment items now. Not before, because we only
want to show the payment items that the user
is going to pay for. When the payment selector
goes up, it shows. So already if I do this, the
payment sheet is going to show. But what I really
want to do is capture the result of this request. And that result is being
sent directly as a response to this call. So I can directly
capture it as a map. I believe it's a map. It's actually a json
object as a result of this. This is in a
sinkhole, so I'll have to wait on it, which
means I will have to make this call a sink as well. And if I now print
that payment result, we should see something
very similar to what we saw when we
integrated the pay plugin through the quick way,
through the quick integration. And then we can
do it right away. Yeah. And continue. Now this time
what's different is that this has been done
through this method on line 80, and not as we did before
through the managed button. So now that you have the payment
result, the next step for you would be to send
that to your PSP. So if you're using a PSP just
similar to what we did here, if you're using
your PSP calls, PSP, and you can just simply do
your PSP lib create order. And remember I'm
just making this up. This is going to be different
on every app payment processor.token. And that will actually
create the order in your payment gateway. So it will be the same
outcome, the same results, but now through a completely
different integration path in which you have
control over the first call to the [INAUDIBLE]
the user can pay with, in this case, Google Pay. But the flow will be
similar with Apple Pay. Show the button, capture
the press callback, and then issue the
payment selector, get the result sent to your PSP. And the order is created. As you saw, only a couple
of steps more, but then full flexibility to do your
integration as you prefer. CRAIG LABENZ: Nice. Yeah, I like that. The more branded an
app is, the more likely its designers and
product folks are to want to control
that experience. So it's nice that
you can put the LEGOs back together yourself just
kind of however you want. JOSE UGIA: Precisely. Yeah. That's cool. So how are we
doing on questions? I have been really bad keeping
track on this this time. It's a bit of a challenge
when you're typing. CRAIG LABENZ: Yeah,
you're doing all the work. I'm watching the questions. You're putting together an
incredible live demo here. We do have some good questions. So we can get to them. There's one that's come
up a handful of times. But I think this was
the first person to ask, can we get a
refresher on the state of all of this for Flutter Web? JOSE UGIA: Yeah. That's one that I'm personally
also really expectant for and can't wait
for it to come out. So right now,
developments are not active on the web integration
for the Payments plugin. That said, it's definitely
on our pipeline, something that we'd like to put
out because there's web libraries for the providers
that are supported right now, Google Pay and Apple
Pay, so it's something that will make total sense. That's said, too, again, this
is an open source project. And if you take a
look at the ReadMe, it's a project for
which we expect the community to get involved. It's something that
will be very welcomed. In that same vein, we don't
see this as a Google project, necessarily, even though
it was started by Google. And so there's been
already good contributions from the community. But we would like that to
develop even further and just let it sail, and
go in the direction that everyone feels
that it's more appropriate for their purposes. So feel free to take a look. Take a look at the ReadMe and
the contribution guidelines. It's very easy to get set up. And if you don't feel like
committing code, that's OK. We have a section for
issues and discussions where your participation and
feedback would be fantastic. If you're willing to commit
code, that's even better. So we're waiting for you there. CRAIG LABENZ: Yeah. And a lot of the questions-- there's a set of questions
that we've gotten in the chat that I think could be
nicely asked on the-- or by that I mean, it'd
be nice to ask them on the repo in terms
of different country support, different kind
of back ends and whatnot. But here, before
we get too far-- I wanted to say that quickly
because it was just what you were talking about, Jose. But we've got a
question that I think pretty important
for anyone who is kind of new to this entire
space of app development. What does PSP stand for? JOSE UGIA: I'm not
searching for it because I don't know where it is. CRAIG LABENZ: I think it's
payment service provider, right? JOSE UGIA: Oh. Yeah. PSP is also a gaming console. CRAIG LABENZ: Nintendo. Or not Nintendo. Of course it's PlayStation. Yeah. oh it's PlayStation Portable. But for it's payment
service provider, I think. JOSE UGIA: Correct. Yeah. It's payment service
provider, or also known as payment gateway. That is a entity or a company
that provides you with services if you are collecting payments. Sometimes this is simply
processing the payment, that is, moving the funds
from your customer credit card or bank account into your
bank account as a merchant. But some other times this
also includes other features like fraud analysis,
like metrics, like merchant features,
like invoicing. Pretty much anything
that a business selling online would need or
would benefit from, it goes by the name of both
PSP as payment service provider or payment gateway. And I'm sure you have heard
about a few of those already. CRAIG LABENZ: Yep. Nice. Great question. So let's see. What are some other good ones? Oh, this one is
certainly worth covering. I love that Muhamad is
thinking about security, and they ask how to handle the
security on these payments. JOSE UGIA: Especially
with payments, right? CRAIG LABENZ: So can you
say a little bit about-- exactly. Right. Couldn't be more important. So you can say a
little bit just about are there security things
that a Flutter developer going through this process
has to keep in mind? And which of those things
are already handled by the various SDKs? JOSE UGIA: So I'd say
that unless your PCI DSS-- which is a whole
payments regulation-- PCI DD is compliant, then do
not manage payment information of your customers. Depending on the
country, I think that's illegal or
forbidden in some way. But also, it's definitely
not good for your business in the sense that if you
mishandle that information, then you will be
exposing your users. So most PSPs, most
payment gateways, if you use their libraries,
they will have proper security mechanisms. They are definitely
PCI DSS compliant and they will help you
keep your information safe. So for example, when
you're using a website, they will be using
iFrame to collect card information on the form. And the same goes for
the application data is being treated as securely
as possible that is, let's say, on one hand make sure you use
elements from your service providers in that sense
and payments do not deal with payment information
do not manage payment information yourself
unless you're doing that as part of your business. But then second, there's
a general rule of thumb that I apply that we
covered before earlier, and that is assuming
that client applications or websites running
on client browsers are by default unsecure,
or are by default breakable in the sense that
if someone gets physical access to
that device, that means that the information could
be compromised, even actually not only physical access, but if
a bad intended actor got access to your device, they
would have an opportunity to see what's part of that
application in terms of what's in that phone, either through
memory inspections or disk inspections and so on. So I generally like to
treat client applications as not secure. So and the reason
we talk about that is because I think
for payments, it's important to have every
kind of information that could be sensitive be dealt
with in a secure place, like your backends, for example. We were talking about the
price before our recommendation is that if you are doing price
or item calculation, anything that has to do with
payments, that you do that in a safe environment
that you can trust. You know that you're
back ends are private. They can only be
accessed externally or they have keys
that you're using to encrypt the information. So you get the
information from there. You show it in your app. But then when you're
creating a transaction again, then that's something
that happens, again, from your backend
server to the PSP. There are some PSPs that have
secure mechanisms from your app and you can use those very well. But as a general
rule of thumb, I am personally wary
of client apps. And I take special care
of those scenarios, and I certainly recommend
you to do the same thing. One additional thought is that
using payment facilitators like Google Pay or Apple Pay
definitely helps you there. And how does it do it? It does in the sense that when
you are asking for a payment mechanism-- for example, let's
say we go back to Google Pay, we are opening
the payment sheet, I'm selecting this Visa card,
and then I'm hitting continue-- that information will go
back through your app. But it will be encrypted. That is, only Google
Pay or the PSP will be able to decrypt
that information and see the context. So that's an extra layer
of security that you have. So even if someone was able
to get access to your device, they wouldn't be able to
do anything with that. So I know I gave a
collection of answers. But hopefully that makes sense. We can summarize it as,
don't trust client apps by default. Do not handle
payment information yourself unless your
PCI DSS is compliant. And Google Pay and Apple Pay
will help you stay more secure, if that makes sense. CRAIG LABENZ: Yeah. No, that's a great answer. I mean, any holistic
approach to security, there's so many different
facets to having a secure app. And I am going to put
that in air quotes. But it's always great
to be thinking about it. And Jose definitely nicely hit
on all of the basics, and just the state of
collecting payments. When you use those SDKs,
you go a very, very long way toward having a secure
checkout process. JOSE UGIA: They say that
full security is impossible, and getting close to 99.9%. The effort goes into infinite. So finding a sweet
spot, I think, is appropriate for your use
case and try to keep users safe. CRAIG LABENZ: Yeah, absolutely. All right. So we are kind of winding
down on questions about pay specifically. Oh, here we have a little
success story Thanks so much, Pay Library. I have successfully integrated
Google Pay with Stripe gateway for payment on Shopify. JOSE UGIA: Nice. Cool. That's great to hear. Well, if you have more
thoughts or feedback, we'd love to hear them. But it's great to
see that already. CRAIG LABENZ: Yeah, absolutely. By the way, I apologize to
everyone listening at home. We're streaming on
an unusual day today, and I didn't choose this day for
the recurring day for the show because it's
garbage day outside. So I'm trying to mute
myself while the garbage truck is farting around
picking up everybody's stuff. But can only do so much. Here's an ambitious question. How can we create a
payment processor? JOSE UGIA: Wow. Definitely ambitious. CRAIG LABENZ: Yeah. You're talking about founding
another Stripe, essentially. JOSE UGIA: Funny shorts. Yeah. Where to start from? Find a good name for your PSP. CRAIG LABENZ: Yeah. I think the answer to
this is to not do it. I mean, if you want to make
another payment processor, that's like a life
commitment to such a startup. And you wouldn't want
to take that lightly. And I'm guessing that you're
asking something else. But if you're
really asking that, then you'd want to know
way more about it than Jose and I put together. JOSE UGIA: Yeah. And probably it falls under the
category of business questions of trying to find a need that
is not solved by the main PSPs today. There's a very good
coverage today. We have, especially
with modern PSPs with a lot of APIs
and online services, it's gone a long way
compared to back in the day. You can now take
payments globally. You can do everything with
API calls, [INAUDIBLE] get information, capture
payments, do stage payments. It's just incredible. But if you have found something
that you think is not covered, and then again, we're back into
the second episode of business class for engineers
and payments, then it's something to look into. But yeah, it would be
something certainly complex. And you would be dealing with
sensitive information as well. So it's important to get the
right people in and get it right from the beginning. Otherwise, I think the internet
and reputation is not very forgiving in this field. CRAIG LABENZ: That's true. Yeah, people don't like
when companies leak all their users' credit cards. All right. So maybe a few kind
of generic questions. What was the one that
I wanted to go with? Oh, this one is kind
of pure Flutter. And say hello, should we
only use the build method for layouts, right? For initializations
and instance creation, we should use InitState. And short answer is yes. Yeah, when you're
laying out your app, everything goes into
the build method, and basically nothing else
goes in the build method. You are just printing the
next frames worth of widgets. And the most dynamic stuff
that would go in there would be the callbacks for
click events on those widgets. When you're setting
anything up, that's where you dive into InitState. And we did that-- I think it was after this
question actually appeared. But in this episode,
we had a future that was in line in
the build method, and then we pulled that
out into InitState. So you were definitely
on the right track. JOSE UGIA: Oh, maybe they
were just calling that out when they were seeing me typing,
and softly, gently suggesting, hey, you may want to
do it differently. CRAIG LABENZ: Could be. Yeah, I'm not sure the
actual timeline on that. That is possible. OK. Let's see here. This is another ambitious one. JOSE UGIA: A lot of those. CRAIG LABENZ: Can we make
an IAP without a back end? An IAP stands for
Identity Access Provider. So that would be something
like Firebase authentication or others. I don't know how to do
that without a backend. JOSE UGIA: I think
it's impossible. You need that social truth. CRAIG LABENZ: Yep. [INAUDIBLE] back end. JOSE UGIA: Yeah. Or some other source of
remote, trustable truth. CRAIG LABENZ: Like a
blockchain or something? JOSE UGIA: We could go wild. Yeah. I was just going
to that direction, or a group of people that
has remote earplugs that receive every request. Well, any form of external
social truth, I think you need. But the back end is a very
good one that works very well. CRAIG LABENZ: Yep. Yep. And obviously, Web3
and crypto and all that has kind of lost a
little bit of its luster over the last few months as I
think more and more developers realize that that
doesn't actually unlock an entire new
universe of wonderfulness. In theory, a blockchain could
be an identity access provider that was completely
decentralized. Unfortunately, blockchains are
extremely slow to write to. So you'd have a very, very,
very low bottleneck of new users that you could add
to your Rolodex because that
distributed trust is expensive to attain across
all of your different nodes. So I think you're going
to need a back end. JOSE UGIA: I didn't know that. That's actually pretty cool
information that you have, Craig, in your brain. CRAIG LABENZ: Every now and then
I hear something interesting and don't forget it immediately. Here's a question back
to the pay plugin. Is there any roadmap
for the project? JOSE UGIA: Yeah. So I'm going to go, as I said,
if you go to the discussions on issues in the Flutter plugin,
you will see a glimpse of that. So there's things
like web integration, making the configuration
be dynamic, as we have been discussing, here as well. Especially go to the bottom. You see a few of them. So there's certainly a roadmap. I'd say it's been managed the
same as every other open source project, so it's been
built with a contribution, not only in terms
of code, but also in terms of decision and roadmap
with those guidelines in mind as well. And so you will see action there
through discussions and issues. And those, the
most relevant ones will turn into a feature
requests that will then be implemented as just the
regular flow for open source projects. This is a great place to
start discussions on issues. CRAIG LABENZ: Yeah, absolutely. Nice. This does seem to
be quite structured and it's well-organized. Now Jose, I've been really
driving on questions. Have you seen any that
you want to get to? I can go to a few more
here before we wrap up. But if there's any
that you've seen, I don't want you to
not feel like you have control of the reins, either. JOSE UGIA: I haven't much. But I'm checking it right now. We have an [INAUDIBLE] from our
boss to decentralize payments, something that I think
connects very well with what you were
saying, or doing payments in that
centralized environment. And I think the only
place to do that right now is blockchain as far as I know. So I think your answer
very well fits into that. We have [INAUDIBLE]
asking at 6:46-- well, my time,
actually, so it might be a different time
in your time zone-- whether this will be
published in GitHub. And great news is that it's
already published in GitHub, and it's been published for
the last year and a half. So please do check it out. CRAIG LABENZ: Yeah. Now to fully answer
that question, I think to merge his
answer and your question, at least the way my brain
is seeing all of this, we didn't actually get we
didn't really stray very far away from the ReadMe, right? So that's what I
think you mean, Jose, by this has been published
for a super long time. In the code that
Jose wrote today-- is the raw Google button
and everything, is that also in the ReadMe? And where would someone find
out about the raw Google payment button? JOSE UGIA: Yeah,
it should be there. Let me double check and
see if I can find it. But yeah, you're actually
understanding the questions the right away. I'm misinterpreting
most of them. Yeah, so you have
an [INAUDIBLE].. Same integration in the
advanced user section. So I don't really think
you need that code. It's almost like 95%
similar to this one. Well, we do have the putting
the feature in a variable. So that's something
that we may want to do here because as someone
else pointed out before, this could be perceived
as a bad practice as well. CRAIG LABENZ: Yeah. And even if that function does
hold on to a single future internally, I would still
recommend the developers make the change that we
made because you're really depending on the client-- you're really depending
on the library to always behave in that way. JOSE UGIA: That's a good point. We have one really good
question from [INAUDIBLE],, how to handle the decimal
double value in total amounts. And I think that's
a good question because it's different
on different platforms. Concretely on Google Pay, it's
being treated as a string. So it's expecting a string
with a dot separation for all locales. Different locales have
different punctuation, as you probably are aware. And that's the reason
why you're asking. Whereas if I remember
correctly, the Apple Pay library expects an integer
or [INAUDIBLE],, basically a number. And so that was
a compromise that had to be done for the
main layer of the library, for the dark side
of the library. By the way, I love
when you say dark side. Just sounds like something else. CRAIG LABENZ: It does. JOSE UGIA: And that's very cool. Be on the dark
end, we have chosen to go with string, which
works for both areas. But there's additional
logic that we are doing on the Apple Pay
native side, on the iOS side if you look at the
plugin, to make sure that there's no catches in there
because as you will point out, different numbers with more
precision, for example, or large numbers could have
trouble on the rounding up. So we haven't found a, let's
say, 100% working solution. But this works for
majority of the cases. And in any case, it's
important to keep in mind that number is not
going to define what you charge your users. That's something that is defined
internally in your back end when you make the order. This is only there
for UI purposes so that when you
open up the payment sheet, if you have
a final price, the price will show up in here. So that's not going to
modify the final price, if that's a concern. CRAIG LABENZ: That
you actually charge. Right, right. Though of course, best
to not accidentally mislead your users, especially
with a decimal location error. Goodness, they would
be quite alarmed. JOSE UGIA: Two
places to the right. Big impact. CRAIG LABENZ: Yep. All right. We are near the end here. I do want to wish Jasbir
Khalif a happy birthday. Nice. JOSE UGIA: Happy
birthday, Jasbir. And thank you for
bringing your birthday. We really appreciate it. CRAIG LABENZ: Yeah. Hopefully they've stuck
around the whole time. All right. Maybe the final question
here, at least from my side. Spectator says, observable? Are using reactiveness? And this show is just
called Observable Flutter because you get to watch
people write Flutter. You get to observe the
Flutter, and observable is a class in Dart. I forget if it's from the
Dart SDK or the Flutter SDK. Somewhere there's some
popular observable class. And of course, it's the language
programming-wide pattern of observable
reactiveness and whatnot. So that's the cheeky
name for the show. Jose, any closing thoughts
about pay or anything else? JOSE UGIA: I'd say
the only thing that-- I think we have
covered everything. So the only thing
is that if you want to keep on engaging
with us, there's a couple of links that
we will post in Twitter on the Google Pay Devs
account, potentially on Flutter as well if we convince
them to retweet. We'll see. And look at Craig's face. Maybe it works. And those links are pointing to
the plugin in [INAUDIBLE] Dev, and then to the
GitHub repo as well. Remember that this is
a central place where you can engage with us,
engage with the plugin itself, contribute, add your thought,
feature requests, discuss because this is what, as
we covered earlier, what determines the path forward. So we'd love to see you there. We'll certainly
wait for you there. So yeah, that's
what I would say. CRAIG LABENZ: Absolutely. I would also point, all of our
viewers at 17 Days of Flutter, which, if my math checks out,
I believe that starts today because I think we're 17 days
away from Flutter Forward coming on January 25 in Nairobi. And the next episode
of Observable Flutter will be back at the normal
time this week, Thursday, so only like three days away. And I will be taking a stab
at the coding challenge that [? Khan ?]
mentioned in the video. She said there's going to be
a weekend coding challenge. So get your keyboards
and IDEs ready, and I am going to come in to
that episode with my keyboard and IDE ready. So on Thursday,
we'll be several days into the 17 Days of Flutter as
we approach Flutter Forward. And I invite everyone
to tune back in, and we're going to be
doing some video game things because that's a
big theme of the Learning to Fly season two
episode that's coming in the 17 Days of Flutter. All right. Jose, thank you. You waited-- I want to say it
was six months ago that you first reached out. And scheduling things
across the Atlantic Ocean is quite a headache. So thank you for your patience. Thank you for joining twice. I think we got through
a lot of stuff here. We showed the full end
to end of the pay plugin. We integrated it on Apple. We integrated it on Android. And I think folks are
going to be set up to collect payments in Flutter. JOSE UGIA: It was
well worth the wait. A lot of fun. So thank you for having us. CRAIG LABENZ: Yeah, absolutely. All right, everybody. Have a great week and I will
see you all on Thursday. JOSE UGIA: Bye.