ANDREW BROGDON: Hey, everybody. I'm Andrew Brogdon
from the Flutter team. And today, I'm going
to show you how to quickly bring a Flutter app
to life with Cloud Firestore. If you haven't used it
before, Cloud Firestore is a NoSQL document
database that simplifies storing, syncing,
and querying data for your apps at a global scale. It's also a great way to put
a backend on a Flutter app without the hassle of
spinning up your own servers. Let me give you an example. Say you're starting a band. And you and your bandmates
can't agree on a name. You know, you play remixed
glam folk disco glitch metal and can't find anything
that captures your essence. So you decide to do a survey. You'll make an app that displays
a list of potential band names. And then, you and
your bandmates go out and show people the list. They tap on the names they like. And your app keeps track of how
many people vote for each name. Putting together the UI
for something like that is actually pretty
quick in Flutter, as you may have seen in
some of our other videos. But you also need a
backend data source shared between all the
devices running the app. How can you build
one and handle issues like security,
connections going offline, and all the rest of that stuff? This is where Cloud
Firestore can help. With it, you can
create a collection that will track
the possible band names and their popularity. Then, you integrate the Flutter
Firestore plugin into your app and build your widgets using
data from that collection. The apps sends new data back
in response for UI events like button taps. And Firestore handles
the rest of the details. It persists the new
info, sends updates to all the other
instances of the app, and keeps everybody
on the same page. All right, so that's the plan. Let's imagine
you've already done that first step of creating
the UI with mocked up data. How quickly can
we get it working for real with Firestore? Well, step one is to
create a Firebase project. You could do this in
a Firebase console. And I'm just going to call this
one Band Name Survey and click Create Project. And then a few seconds
later, it'll be good to go. Cool. Now, Firebase asks you to
register the individual apps for your project. Here, you can see me
registering an Android one. There we go. Click Register App. And make sure that you grab
the config file, right there, when you do the registration. I'll show you what to do
with that in a second. Once you have an app
registered, you'll see this screen
for your project. And you can use this
button to add a second app. I'll use it to create an
app registration for iOS. Flutter can build
for both platforms. And if you plan to
take advantage of that and release on
both, you actually need to register two
apps, one for each OS. One thing to note, when you
create a new Flutter project in Android Studio or Visual
Studio Code or whatever, you're asked for an organization
name in reverse domain order. This, along with
the name of the app, ends up as the package
name for Android and the bundle ID for iOS. So when Firebase asks
for those pieces of info, that's what they are. If you can't remember, just
open the underlying X code project or Android manifest
in your project source tree, and you can find what you need. OK. With the apps registered,
let's get Firestore going. I'm going to go over to
Database under Develop and choose Firestore as
my project's database. I'll leave it in
test mode for now. Hit enable. And in a few seconds, once
the spinner stop spinning, I'll have an
instance of Firestore that I can start playing with. Cool. Now, it's time to
make a collection. I'll just call it Band
Names and hit Next. And this will hold a document
for each possible band name. Let's see. And for my first document,
I'll just auto ID it. And I'll have the first
field be called Name. And that's a string. And for the first name,
how about Jam and the Angry Biscuits? There we go. And I need another field to
hold the number of votes. So that's a number, and
I'll start off with zero. Let me hit Save here. And there's my record. All right, so that's one. Now, let me go ahead and
add three more records using a technique I like
to call fast forwarding through prerecorded footage. So there's two. There's three. And there's four. My collection is ready. At this point, you've
got a working backend. The next step is to get
your app talking to it. And for that, you'll
see the Cloud Firestore plugin for Flutter. All right, you may
remember those config files we downloaded earlier
from the Firebase console. Time we get them in place. I'm going to drag the
Android configuration file, google-services_json,
into the Android/app directory in my Flutter project source. Next, I need to get the Firebase
gradle plugin for Android in place. Now, Android Studio's
Firebase Assistant can actually help you with this. But in case you're
using Visual Studio Code or some other
editor, I'm going to show you the manual way. Just open the build.gradle
file you find in your Flutter project's Android directory. And then add this line for
the Google services plugin to the dependency section. Then, open the app
level gradle file at android/app/build.gradle. And all the way
at the bottom, add a line to apply that plugin. And it's com google gms
and then google-services. Cool. All right, for iOS, I'm going
to open the underlying Xcode project created for
each Flutter app. It's called Runner. And I'm going to open
the workspace file itself since Flutter uses CocoaPods. Once that's open, I'll
drag the property list file downloaded from
the Firebase console into the project. And it'll go right in
that Runner folder. Cool. So that's the last
platform specific thing, which means I can spend the
rest of my time in Flutter code. Let me open this
project's pub spec file. This is the YAML file that lists
a Flutter project's metadata, including its dependencies. And I'm going to add the Cloud
Firestore plugin to the list. And once I've got that,
I'll do a packages get from the tools/flutter menu. That will pull
everything down and make sure I've got the Flutter
code and native dependencies in place to use Firestore. So with the Firebase config
files in place and the plugin imported, this app is ready
to start talking to Firestore. OK. With the Firestore collection
created and the plugin built into your
app, the next step is to code the app to use
live data from Firestore when building its widget tree. Now, we're starting with an
app that's been mocked up using hardcoded values. So most of the UI code
can stay just as it is. You just need to pass live
data into the build methods. Let me show you how it works. OK. So here's my app running on an
iOS simulator and an Android emulator. And it's all based
around this list view, which displays a row
for each potential band name. And there's a function called
build list item that builds out the widgets for each row. The first thing I need to
do is get the mock data out. So I'll scroll up and I'll
take out this mock class and the list of mock bad names. There we go. And I also need to import the
Dart code for the Firestore plugin. That's done at the
top of the file. So I'll just add an import
statement and Cloud Firestore. There we go. Let me come back down. I'd like for this list view
to display Firestore data. And I need it to
be rebuilt whenever there's a change to that data. So I'm going to wrap it in
a really handy widget called stream builder. The Firestore plugin
provides a snapshot stream for each collection, which
I'm going to use here. It's basically a running
stream of updates that emits a new value whenever
the data in the collection is changed. I'm subscribing the
stream builder to it. And so it'll
rebuild its children whenever there's an update. And rather than a
child, stream builder takes a builder function
as one of its properties. It will call this function
to rebuild its child widgets whenever the data
in the stream changes. Many of you watching
probably immediately recognize this as
reactive programming, which is a pattern Flutter
is designed to support. All right, now, when
I launch the app, Firebase won't have had
a chance to connect yet. So I'll get a snapshot
that doesn't have any data. In that case, I'll check for it
and just return a text widget that says loading. If the snapshot does
have data though, I'll use it to
return a list view, just like I was doing
before with that mock data. And format that up. Cool. I'll base the item count off the
number of Firestore documents in the Collection
Snapshot since I have one document for each name. And I'll need to change
the build list item function to take an individual
document snapshot instead of a mock data object. There we go. All right, let me scroll
up to build list item. And I'm going to replace this
mock with a document snapshot parameter. And then I can use that to
get the right band name. There we go. And I can get the
vote count, as well. All right, now,
when I run this code I get a bunch of
names and zeros, which is the right stuff. Plus, if I go back into
the Firestore console, I can now mess
with these numbers and see the app
react to the new data by automatically
updating the widgets. So this is definitely live data. OK. The only thing better
than reading live data is writing it. So the last step is to make
the list tiles on tap handler increase the vote count for
that particular band name. As you'll see, now
that everything else is set up and working, it's
actually pretty quick to implement. OK. So I'm back in build list item. And I need to put some code
in this on tap function that will increment
the vote count. So I'm going to use
my document snapshot to get a reference to the
live Firestore document and then update it with
an incremented count. This is a slightly
naive solution-- and I'll get into that
more in a second-- but it does work. So when I do a hot
reload now, I get this. And I could start tapping away. So I tap on the iOS side. And you can see the
Android side updates. Tap on Android, iOS update,
I could do this all day. Cool. Like I said though, this
isn't a robust solution. I'm incrementing data
that could be stale if some other
instance of the app has updated the
collection just before. So let's replace this
with a transaction and do it atomically. I could actually ask Firestore
to run a transaction for me. And then I'll give it a function
to execute within the scope of that transaction. And I'm going to mark
it async, because I'm going to need to
await on some things. So within this
function, which gets the transaction as
its only argument, I'll first get a fresh snapshot
of the data for the document, so a fresh copy of
that vote count. And then once
that's done, and I'm awaiting, because these
methods return futures, I'll do an update using
the document reference from the snapshot and an
incremented vote count that I know I can trust. There we go. All right, now,
when I do a reload, I get an app that mostly
looks and acts just like it did before, but it's free of
that potential race condition, which makes me very happy. All right, so in
just a few minutes, we've gone from
a mocked out demo to a real app that builds
for both iOS and Android with a Cloud Firestore
collection on the backend, keeping everybody
on the same page. You and your bandmates
have what you need to go out and find whether
Three Ferrets and A Banjo really is the name for you. That's it for today. But if you'd like to
learn more about Flutter, we've got links to guides, a
step-by-step code lab covering Firebase with Flutter, and
a bunch of other resources in the description
for this video. So check those out and head
to flutter.io to get started.
They have updated the codelabs as well which is great.