Build a Cross-Platform Mobile App in 30 Minutes with Firebase (Cloud Next ’18)
Articles,  Blog

Build a Cross-Platform Mobile App in 30 Minutes with Firebase (Cloud Next ’18)


JAMES DANIELS:
I’m James Daniels. I’m an engineer on
the Firebase team. Who here has used
Firebase before? Cool. Got a good representation
in the room. So I’m going to recap
a couple little things. So it might be a
repeat for those of you familiar with the product. And then I’m going to jump
into a live demonstration. I’m going to do some
coding, hopefully. That’s the live demo warning. I’m on stage in front of a
lot of people writing code. Sometimes things happen. But I’m lucky because I
have a lot of rubber ducks here to help me out. So I’m an engineer
on the Firebase team. What is Firebase? So Firebase is a suite of tools,
built on top of Google Cloud at Google, for you to
develop applications faster, better, stronger. And the idea here is that
we have developer tools. We have our backend services. We have tools for
monitoring app quality. We have tools to help you
grow your application. And then the all
important part is earning. You have tools to
help you monetize. So on the developing side, we
have the Realtime Database. If you’re familiar
with Firebase, that is the bread and butter. That was the product
that Google acquired. The Realtime Database
is a JSON store that synchronizes in real time
to all your connected clients over web sockets. It’s pretty cool. This is a little bit
of an outdated slide. We actually have a new service
called Cloud Firestore, which I’ll jump into in a second. We also have user
authentication. This allows you to
sign in your users. This product is free. It integrates with
Google, GitHub, Facebook, out-of-the-box. And then you can also provide
your own custom authenticators. So if you are in an
enterprise environment, you can spin up
something that interacts with your own backends. If you already have your own
custom authentication app, maybe something legacy,
maybe something you still want to keep up, but you
want your mobile applications to be using Firebase. Custom authentication lets
you integrate the two. We have hosting. We have Cloud Storage. So this is uploading binaries. Cloud Messaging. So Firebase Cloud Messaging
is the new version, basically, of Google Cloud Messaging. It has a lot of new
features and it also integrates with iOS,
which is pretty awesome. And then there’s a
remote configuration. And I’m a backend guy. I’m a developer,
so I like these. But there’s also tools to help
you make your apps better, right? So there’s the
Test Lab, where you can submit your
applications that will run robo tests on them. This is also in iOS now. We also have crash reporting. And recently, about year
ago, we acquired Fabric. So the industry standard
for crash reporting, Crashlytics, is now
integrated into our toolset. We also have all of our
Grow products and Earn. I’m going to be coding for
you, so I’ll skip over those. But if you need to grow your
products and some money, check those out. So the idea with
Firebase, in general, is we’ve actually written
the client SDKs for you. In a way, it’s a
candy-coated Google Cloud. We built these tools for you. We built the SDK. We built the SDKs in
multiple languages. It’s iOS, Android, Web, C++,
Unity, all kinds of stuff. And the idea is that the shape
of the code looks the same. So when you go create
a web app and you’re calling the Realtime Database,
it looks similar to the iOS. Sure, the APIs may be
slightly different, but the same shape
of the code applies. All of our client SDKs integrate
with Firebase authentication, out-of-the-box. So you log in and
when it makes requests against either Firestore
or the Realtime Database, the user’s logged in. You have those credentials. It’s instantaneous. It’s magic, and it’ll just
update the views on the page. They integrate with
security rules. This is very important. If you have a Firebase
project, maybe a demo project, where you didn’t
secure things, you might have noticed us sending
out emails about this, scanning for security rules. The idea is because
the client is directly interacting with the database,
how do you do typical security? If you had a REST server,
you’d, in the middle, between your app
and your database, do all kinds of checks
and verifications. This is actually where
security rules come in. So it’s JSON structure. You can go in there
and write rules there are some great
examples there, but I won’t to touch on that. But it’s very, very important. And then finally, we added
this last year at Next. It’s Cloud Functions
for Firebase. This has been the number
one, most requested feature since it was a startup. Like forever was
cool, serverless. But I still need a
server because you don’t have compute, right? So Cloud Functions
gives you a bunch of neat little
hooks into Firebase, and this is just a flavor on
top of Google Cloud Functions. So this is a Firebase
flavor, and it just gives you extra hooks. You can listen to a path
in the Realtime Database. You can listen to a
path on Firestore. You can listen for
users being created. So Firestore is more like
a traditional database than the Realtime Database. If you used the
Realtime Database, it’s just a JSON store. There are some caveats. Querying isn’t great. When you fetch
data, it goes deep. It gives you all the
data under that node. So it changes how you
structure your data. Firestore, we started on
this after the acquisition. We’re like, well, how can the
cool things about Firebase be brought to Google
Cloud technologies, and the cool things about
Google Cloud technologies be brought into Firebase? It’s kind of the peanut butter
and jelly of the Firebase acquisition. And I will jump into
this a little bit. So I’m going to flip over
to the live demonstration. I’m going to be doing
a little bit of coding. I’m going to write an
application, hopefully. We’ll see. Anything can happen. I can’t even control my windows. There. So what I’ve actually done
here is, because the Wi-Fi can sometimes be a little flaky and
node packages are a black hole, I actually went ahead and
generated two projects and did some basic
configuration on them. But otherwise,
they’re blank slates. So what I did,
actually, here is I generated an Angular application
inside my Firebase function. So here, I just initialized
Firebase in a directory. And it asked me what
I wanted to enable. I chose Hosting. I chose Firestore. I chose Functions. And it created those
directories for me. I then went up and spun up an
ng application in the same one. So if you see here, we
have our typical Angular. Who here uses Angular,
or has used Angular? All right, cool. So Angular is a framework,
a web framework, for building applications. The reason I chose it
for this demonstration is just because I’m most
familiar with it and it will me get code done
better, easier, quicker, and maybe I’ll learn some
cool things about Angular along the way. So that’s the
Angular application. I actually did a little bit
of configuration ahead of time on this, where I
just configured it to bring in the Firebase SDKs. So this is the
AngularFire2 library. So with Firebase, we
have our main SDKs. So we have our iOS SDK. We have our Android SDK. We have our Unity SDKs. We also built, on top of
these, these smaller SDKs, where they’re basically
a compatibility layer between whatever
framework you’re developing in and the main SDK. So AngularFire is a library that
I’m one of the maintainers of. And AngularFire tries to
make the Firebase JS SDK work a little bit better
out-of-the-box with Angular. So that means things like
dependency, injection. That means things like
observables, rather than promises. And I’ll touch on those when
I jump into the code more. I also went ahead
and initialized a Flutter application, just a
default Flutter application. And I went ahead and pulled
in a couple of the Firebase libraries. So this is the Fire
Flutter library. So similar to
AngularFire, we’ve built just a little compatibility
shim on top of the SDKs. And what Fire
Flutter’s going to do is if you’re building
for iOS, it’s going to be calling the iOS SDK. It’s going to do all the setups
and hookups for you there. And if you’re
using Android, it’s going to do the Gradle builds
and set up all the dependencies there. Who here has played
with Flutter? Less people. All right. Flutter is a cross-platform
development environment– so it’s largely
targeting iOS, Android– where you develop an
application in Dart, and it allows you to compile
for both iOS and Android in the same code base. It’s actually really slick. So this actually show
the Flutter application. So right now, I’m in
the Flutter directory, and this is just straight
off the press, Flutter initialized new application. This is the directory structure. So here, we have
our dependencies. This is the main project route. Walks through all that. Developer dependencies. Uses material design. It has a lot of nice
things built in there. But the meat and
potatoes of our code base is actually just here,
simply in main.dart. So we build our main,
our entry point. It runs the application. I build my app. There’s a stateful widget. That’s my home page. And then there’s a
home page state here, which actually holds the state. And that matters
for hot reloading. I’ll show that in a second. And here, I’m building
a new scaffold. I’m including the title
bar, a body, and then an action button. So let’s actually spin this up. You can just do Flutter Run All. So that dash d is
telling it which device I want to spin up on. I’m just going to be
using emulators right now, so this is configured to use
the iOS and Android emulator. So it’s building
the application. You see it starting
x code build here. The cool thing about Flutter
is it’s actually compiling down to the native byte code. There’s no performance loss
because it’s JavaScript, or something like
that, where it’s going through an interpreter. This is actually rate
to the byte code. It compiles to a native
Android and iOS application. So that just spun up. So let’s go ahead
and bring up our iOS and our Android simulator. There. Sometimes the Android
emulator, you’ve got to do weird things
to get it to work. But this is actually the base
template that it built for us. So what we have is
just an application. You see there’s this main
bar, that’s the title bar. The cool thing is it knows
the interface guidelines for both Android
and iOS out-of-box. So you’ll note on
the Android device, it’s a left-aligned title,
and the iOS is center. They’re both material design,
because we chose that option, but they’re both made to look
like the native application themselves. And how Flutter works
behind the scenes is this is actually more like
how a video game renders, as opposed to,
say, React Native, or Cordova, or something like
that, where it’s a web page and then you have to
use CSS to make it look like a native application. This is actually rendered like a
video game, where it’s actually painting the elements
and it’s just a canvas. So it’s very, very fast. So here, this is the
basic sample application. I did tinker with that,
as opposed to counter. And this is just
incrementing a counter. Now, why a counter? Why is the default
template come there? So if I actually go to the code
and I change this, something something stateful, and
I go to my terminal, I can hit a lowercase r to
hot reload those applications. So you see, something something
stateful, same in iOS. And if you notice
those counters, I’m not putting that in
Firebase yet or anything. Those counters are the state of
the application in that widget. And I just changed
the code and the view changed to represent that,
and I didn’t lose my counters. I can do a full
reload with capital R. And now, you’ll see
I have lost my state. So doing certain
things, you’ll need to reload the state, of course. But for most little minor
operations in your app. When you’re doing some
surgery, you can just change that, hit lowercase r. It rebuilds keeping that state,
which is very, very cool. So that’s our
Flutter starting app. Let’s go over to Angular. So I’m just going to start ng
serve, spin up the application, and see what we have. There we go. We have an application
running locally. So let’s get coding and
rip apart some stuff, do some Firebase calls. So I’ll switch over
to my Angular app. So this here, I’m pulling
those libraries, AngularFire2. I’m initializing them. And then in the
environment here, I’ve actually pulled in my Firebase
environment configuration. So you can get this just by
going to the Firebase console and hitting Add a
New Application, and it gives you the JSON. They’ll give you the
plist, if you’re iOS, or the JSON if you’re Android. And you can just drop
those into your projects. The cool thing here,
like I mentioned, all the security
is actually going to be based around
the security rules. That’s your way of enforcing
access to your database. So none of this is private. It can be [? right ?]
in your GitHub repo. If it’s open source,
it can be in the open, so long as you have configured
those security rules. And that’s your gatekeeper,
as opposed to trying to keep client side secrets
secret, which is impossible. You can obfuscate, but
anyone can reverse it. So let’s go to our component,
and we just have our base app component here. So let’s do some stuff here. So I’m going to go ahead
and create a constructor. So I created my constructor. And the constructor
allows me to use Angular dependency injection. So if I go ahead and pull in– let’s do authentication for us. So I will pull in
AngularFire auth. And colon. TypeScript. I’ve been bouncing between
Dart and TypeScript, so the typings are
going to get me. So that’s one of the nice
things about Angular, why I primarily like it, it has
a good TypeScript experience out-of-the-box. So I’m now pulling
in AngularFire auth. Like I mentioned,
AngularFire off is just built on top
of the Firebase SDK. So I have extra calls
here, extra candy coating. But if I ever need to
call a Firebase auth API, I can just do
afAuth.auth, and then sign in anonymously, or with
a phone number or email. But here, I’m actually
going to go ahead and I’m going to keep
track of the user. So I’ll do a public user. Behavior, Subject, User. Let’s pull in user. Import user from. There we go. So here, I’m actually
pulling in the type and it’s pulling
in from Firebase. I have that installed. This is a behavior subject
here, and I’ll touch on what a behavior subject is. Who’s here used Rx of any form,
like reactive programming? All right, a couple of you. Rx is awesome, you
should look at it. It’s really hard to grok
at first, but it does– I’m sure if you find a
functional programming person at your company, they’ll
just rant about it nonstop. So what I’m going
to do here is I’m going to do afAuth.authState. So the authState
is an observable that emits a new value whenever
Firebase’s authState changes. So I’m going to subscribe
to this, and I get a user. And I’m going to
put that user into– I don’t think I’m
going to use this. So now I’m inserting that
into the behavior subject. So one of the things
about observables is observables are just a
sequence of values over time. They aren’t actually stateful. So things like keeping
track of my current user is often helpful to
actually use what’s called the behavior subject. So a behavior subjects
actually has state. So you can look at the
current state whenever. So why this is important
is, say, I have a button. I click the button and
it does some action, and I care about
who the user is, or if the user is logged in. It’s helpful to, outside of
the observables, actually pull in the current user. And I can actually
just shorten that. That’s implicit. So now, let’s go ahead and add
a login and log out action. Let’s actually console
log that for now, just so we see what
we’re working with. So we’ll console log the user. Let’s add a login function
and a logout function. So we’re going to call this
afAuth.auth.signInWithPopup. And console provider. And now we have to
pull in Firebase. So we’ll pull in Firebase,
as well as the user type. And here, we’re actually
initializing the Google auth provider, and then we’re
calling sign in with pop-up. This is not specific
to AngularFire. This is just the JS SDK. You can just ignore
the afAuth section, where you go auth, sign in with
pop-up, and then the provider. And then logos is
very simple as well. So we’re calling auth to get
into that initialized JS SDK auth object, and then
we call sign out. So that’s that, and now let’s
add some stuff for HTML. Let’s see. What could we call it? Login. And I have that backwards. I knew something went wrong. And let’s only show the
login if the user is not currently signed in. So NGF, user. We’ll do a sync,
triple equals null. So what we’re doing here is the
user, of course, is an async. It’s an observable. So what we’re going
to be doing is looking, letting it
resolve first here, working with that observable. And then once it’s resolved,
check whether or not it’s triple equals to null,
and we’ll add a login. Similarly, we can do a log out. All right. And if the live demo
gods are good to me, we’ll see this login button. Let’s bring up the
Chrome inspector here. So that’s the
current user state. And I messed up something. Oh, I need quotes. Yeah. And the paren, too, right? Good call. Rubber ducks at the ready. So we had login. And now we’ve logged in. Oh, the given provider
is not enabled. I just created a new project. So let’s actually go ahead
and turn on Google auth, and go to sign in
methods, and let’s turn on Google authentication. So there. Now we’re logged in, and
we see the Log Out button. You can hit Log Out. You can log back in. And you’ll see here, it consoled
out the whole user object from Firebase. So we have a lot going on. We got my display name, my
horrible when Gmail first came out username. Everyone’s embarrassed by their
first email address, right? Archangel Microsoft
Flight Simulator, that was my call sign. And we have a bunch of
metadata and keys here, as well as the URLs. So let’s go ahead and do
something a little bit more interesting. Let’s go ahead and get some
data from Firestar here. Grabbing my speaker notes. I don’t have a second
screen so I got this little iPad stand here. Pretty slick. So what we want to do
in getting the data, we actually care
about who our user is, but we want our collection
to change based on the user logging in, logging out. So what we’re going to do is
introduce a couple operators on top of our observable. So we can go ahead and
do afAuth.authState. So we care about the user. And instead of
subscribing to it, instead of calling the
current value, what we’re going to do here is pipe it. And I’m going to create
a new observable. So let me import switch map
from our RxJS operators. So what we’re going to
do is we have a user, and now we’re going to turn
it into another observable and swap it. So a switch map is like a map. A map just replaces
something in line. You replace it with
something else. A switch map allows you to
switch it for an observable, but the cool thing
that it does is it cancels all the
prior subscriptions to that prior value. It cancels everything out. There are cases where you
have to be aware of that side effect, but for authentication,
that’s exactly what we want. When the user logs
out, we want to stop listening to the
database at that path and instead listen
to it at a new place. So if there is a user, then
what we’re going to switch map it for– is actually, let’s pull in– so we’re going to pull
Angular Firestore module. We can now bring that in here. We’ll go to Firestore. And now, we’ll swap out the
user for something interesting. So we’ll pull in
Angular Firestore and we’ll do a query
on a collection. See bonuses. So we can do things like this. So we’ll do this
for now because I think I have something in that. We’ll do of and
then an empty array. So observables are the
base concurrency primitive in Angular. That’s the large reason why
we built Angular Firestore. And here, I am actually doing
a query on the wrong syntax, slightly different
syntax in here. So this is built on
top of the JS SDK. In the JS SDK, you would have
done it like I just did where, you do .collection, .where,
and then build on top of it. But there is a slightly
different SDK at work here. So we’re listening
to the messages, and then this is a QueryBuilder. So we’re going
ahead and checking where the two equals,
the user UID, and then we’re listening
to value changes. If there is no user,
just do an empty array. That’s return those. Let’s do public. That one’s great. Let’s pull an observable. And now, to see what
we’re working with, hit Subscribe and
just console login. So empty array. We’re logged in. That’s probably
because of my query. And then empty array
when we’re logged out. Let’s log back in. And let’s see. What’s my UID? So let’s grab my UID here,
and we’ll go to the Firestore. And I don’t have a To field. Let’s change To to that user. I noticed something
changed in the background. That was actually the return. So this is actually
making a live connection to the database. So whenever anything
changes in the database, it gets updated here. Let’s add that to the view. Real quick, we can just
do what I call messages. And that, again,
that’s an async. And let’s call that– and we have to get
rid of the Subscribe. Let’s go ahead–
that’s printing out. So let’s go and
modify some values, and you’ll see that
update in Realtime. And that’s really the benefit of
making these observable-based, is that’s actually doing
the binding to the view. The Firestore or the
Realtime Database is actually keeping
that connection open. If I wanted to just get it once,
there’s ways of doing that. I could just do a Get
instead of a Subscribe. But by default,
this is a good way of interacting with
their database. Now, what I’m doing here
is this is value changes, so this is unique
to AngularFire. So the value changes is
just getting me the raw base objects out of the database. And then when the
user’s logged out, we return this empty array. And the cool thing here
is this is automatically going to clean up all of
our prior subscriptions. So this is one of the powers
of reactive programming. I’m doing the switch map, and
if I were writing this just by myself, I’d have
to do a lot of IFs. I’d have to do a lot of ELSEs. I’d have to cancel
subscriptions. That’s a lot of
work, and anywhere where you have a condition,
you’re bound to mess up. So I’m going to cheat here. Running a little low on time,
so I’ll pull my Dart code. And of course,
there’s a conflict. So I made a small
modification here. I’m actually now
swapping out the body. Let’s see here. And I want the incoming change. So I’m swapping out the body
for a message list component. The message list is
now this block of code. So this is a stateless
widget, all the states held in Firestore. So I don’t care if a
reload destroys it. I’m actually
initializing Firestore. This is the build
method, so whenever this gets instantiated,
it’s going to call the build and this is going to
draw the components. So this is a stream. This is Flutters,
like an observable. It’s a stream of
values, an observable. And it’s an observable
of query snapshots. So the stream source here,
that’s this argument, is coming from the Firestore
messages, where it proved true. Firestore collection
messages, where proved true. And if you’re familiar
with the Realtime Database, one of the cool
things about Firestore is I can append more
WHERE conditions on here, and they’re all hands. We can pull in the
snapshots from that. And if it has data– if it does not have
data, it’s loading. So let’s put a text widget
in there that says loading. Let’s get the count and
then create a ListView. So this is really
common in programming with Firebase, whether it
be Flutter, JavaScript, iOS, Android, you actually
include your drawing code inside that callback. You can do some performance
tweaking on top of it, but the idea is that whenever
that callback triggers, its because data in the database
changed that you care about. So let’s redraw the list. So this is now the ItemBuilder. So we send it the count. This would be just like a
RecyclerView in Android, or ListView on iOS. And we have this builder. We grab the document’s snapshot. And we’ll do a title from
the document to message, and then the subtitle
from the FROM name. So let’s go ahead and
save that and reload. So there. We see the wow. Just like on Web, if I go
in here and alter things, it updates in Realtime. So we didn’t get very far
in building our application, but we got interacting
with the Firestore. We got interacting with
authentication on the Web. But we have some next steps. We could use FCM for
our push notifications. So the idea with FCM
is you can register for those push notifications. It gives you a token. You could then call that
token against the admin SDK and be able to send a push
notification– iOS, Android, and the web, web
browsers that support it. That’s the reason why I didn’t
build the Angular app as a PWA. I showed the Flutter
is particularly on iOS. Safari doesn’t
allow Web Push yet. The app that I’m building,
we wanted integration with our LDAP. I’ll touch on that in a second. We need to add the
security rules, of course, to make sure that
our data is secure. And then finally,
with the Flutter app, we can build production
versions of our application, but we need to sign those. So you can sign
those using Fastlane. That’s a tool that
I like to use. Open source, it allows you to
log in to the Apple Developer Portal, pull the credentials,
sign the application, all built in Ruby. It’s a cool script. And we can deploy
that to an MDM server if we’re doing an
internal deployment. And that formula allows
you to build, especially for an enterprise app, internal
use very, very quickly. If you’re interested in
actually deploying your own app, seeing how you could integrate
with Legacy endpoints, or SOAP APIs, or do some extra cool
stuff, our boot camp on Friday, Firebase plus Apigee, so
Apigee being the API portal. And we’ll do some cool
stuff, where we’ll actually allow third parties access
to our Firestore data, and you’ll actually get to
deploy your own application.

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *