TODD KERPELMAN: You know, in the old days,
if people wanted to store images into Firebase,
they would Base64 encode these images into massive strings,
and then try and save them that way.
It wasn't very efficient.
But these days, we've got Firebase Storage,
which lets you store and retrieve
large pieces of user-generated content like photos, music,
and movies all without needing your own servers.
Sound intriguing?
Want to start adding Firebase Storage into your iOS app?
Well, then you're at the right place.
Let's get started on this episode of "Firecasts."
[MUSIC PLAYING]
So this here is my simple iOS app
with a button and a progress view.
The idea is that when the user clicks the Upload button,
they'll be able to select an image or a movie
from their photo library.
Once they do, we'll use the Firebase Storage library
to upload this piece of media to Firebase Storage,
and then we can report back the upload progress
to our progress view, which will nicely fill up.
So I've already hooked up the code
to allow my user to select any image or video from their photo
library.
This should look pretty familiar to anybody
who's used a UI image picker or controller before,
but let's go over it.
So when the user clicks the Upload button,
I'm going to create an image picker controller.
Now our source type will be our photo library,
and I'm letting the user select both images and movies
as possible media types.
That's an important distinction, which you'll see later.
I'll set my delegate to self, show the view controller,
and I'm good to go.
So now down here on my delegate, most of the hard work
is being done in my Did Finish Picking Media with Info method.
So the first thing I'm going to do
is get the media type to see what my user selected.
If it's an image, then I'll try to get the original image
as a UI image object, and then I'll try and get the image data
as a JPEG.
Assuming that all works, I can now call
my yet-to-be-filled-out method Upload Image to Firebase
Storage, passing along that image data as a parameter.
Now if I get a movie instead, my image picker controller
doesn't give me the entire movie object.
That would be an awful lot of data to keep in the memory.
Instead, I get a URL pointing to where the movie exists locally
on the device.
This is a URL that begins with a file://,
probably something like this.
So I'm going to call a different yet-to-be-written method called
Upload Movie to Firebase Storage,
and I'll pass along the URL of the media to that method.
I'll do a little cleanup down here where I dismiss the view
controller, and then I also need to make sure
I dismiss my image picker if the user clicks Cancel,
and that's what I'm doing up here.
So that's where I'm starting off.
None of this has been Firebase specific so far.
It's just the basics for using a UI image picker controller.
Now the next thing I've already done with my project
is gotten Firebase up and running.
I've created a project in the Firebase console,
attached my iOS application to the project,
downloaded some constants, installed the Firebase library
through CocoaPods, and called for app dot configure.
In my AppDelegate.
If you don't know what I'm talking about,
you should watch this set-up video first and then come back.
So in general, there are three steps for uploading data
to Firebase Storage.
First up is creating a storage reference.
You can basically think of this as a URL
where you're pointing to the data's final location
in Firebase Storage.
Second, we'll start uploading the file through a storage task
object that we create.
And then finally, we'll update the progress meter, which we'll
do by observing when the storage task object receives a progress
event.
So let's start by creating our storage reference.
In Firebase Storage, references, they're basically like URLs,
except that instead of, say, beginning with HTTP
and pointing to a web page, they start with GS and point
to a specific location in the Firebase Storage cloud.
A typical reference looks a little something like this.
This first part here-- you can think of it
as the host-- is generally something
the Firebase library looks up for you.
As for the rest of the reference,
you can think of this as the path to the files location.
You're going to set that as the developer.
OK?
Let's get coding.
So first off, let me make sure I add Firebase slash storage
to my pod file.
I'll call pod install, and I am good to go.
Next, I'll jump in my view controller
and import Firebase at the top here.
Now to create the storage reference,
I can do that by first calling first storage
dot storage dot reference.
This will get me that storage host
I was talking about earlier.
After that, I can then call, say,
child my pics dot child demo pic dot JPEG
to create the rest of my path.
And while that works, it is a little wordy,
so I can shorten this to reference
with path my pics slash demo pic dot JPEG,
which does the same thing.
It just looks a little cleaner.
Next up, I'm going to create a little metadata
so I can specify the content type as a JPEG.
This step is optional, but it can be useful
as you'll see later.
Now I can start uploading the file.
I can do that with the Put Data Metadata Completion Handler
method.
I'll add in my data and my metadata objects
here that I have earlier.
And within my completion handler, I get back
and new metadata object that tells
me a little more about the image that just got uploaded along
with an error object in case there was any trouble.
So this is good, but I also want to be
able to monitor our progress as this image gets uploaded.
Luckily, this put data call returns a for storage upload
task object, so I'm going to create a variable
to capture that.
Now you can call certain methods on the storage task like pause,
resume, and cancel in case you want
to affect your upload while it's in progress.
But you can also add observers for when its state changes,
and that's what I'm going to do here.
This will let me update our progress bar
as our image gets updated.
So I'll call upload task dot observer status
with the status of progress.
This will get triggered every time
the upload task uploads a chunk of data to Firebase Storage.
Inside the handler here, I will get back a task snapshot
object.
Now this object, in turn, contains an optional progress
object, which has this very useful fraction completed
property.
So I can check and see if this progress object exists.
And if it does, I'll set the value of my progress view
to this fraction completed property.
And just like that, I'm reporting progress
to my progress view.
Hooray.
And since this is happening within a handler,
let's do that little weak self dance, shall we?
OK, there that's better.
And in case you're wondering, I don't actually
need to worry about removing this observer when
I'm done with it.
Upload task objects automatically
remove all observers on themselves when they're done,
which is one less thing for me to worry about.
All right, I think we're about ready to give this a try.
I'm going to select my image.
Firebase Storage will upload it and-- oh, that's bad.
Looks like I ran into a permission denied error.
And that's because the default security rules on the storage
bucket only allow me to upload data when I am signed in.
Here, I'll show you.
Let's go to the Firebase console.
I'm going to select Firebase Storage
and then click on the Rules tab.
Now these here are the security rules for Firebase Storage,
and they help manage what people can and can't do with it.
For example, you can limit people
to only upload files that are under a certain size
or give certain people read only access.
Now you see this line?
This says that only authenticated users
can read or write data.
You can see it here.
Allow read or write only if the authentication data is not
equal to null.
Now in my case, that doesn't work because I am not
assigned in user.
Aww.
So the proper solution here would probably
be to add a Firebase auth to my app.
But frankly, that's a whole other video,
and you're here to get started with Firebase storage,
so I'm going to do something kind of dumb and dangerous
and allow full access.
And this basically means that anybody can read or write
anything they want to my storage bucket.
So, again, for crying out loud, don't
do this in a production app.
In fact, I'm going to revert this change just as soon
as my screencast is over.
So we'll publish this and go back to our app.
We can give it one more try.
And this time, we can see that it is successfully
uploaded my image.
Awesome.
The progress bar did get updated too.
It just happens really fast here.
Anyway, I can confirm this by going to the Firebase console.
There's my folder for my pics, and inside here, here's
my demo pic.
Now note that because I specified my content
type as a JPEG image in the metadata,
Firebase knows that it's an image,
and I can see a preview of my image
right here in the browser, which is pretty nice.
So this is great, but how would my user
download this image later or share it with their friends?
We can't send them to the Firebase console.
Well, there are a few ways to do it.
I could, once again, create a storage reference
and call Data with Max Size Completion Handler on it.
This basically lets me download the data
as a big old NS data blob, which I can then
interpret as I see fit.
Notice this max size parameter here.
That's to make sure I don't run out of memory
by loading something that's too large.
But an easier way might be to take a look at this metadata
object that I got back in my completion handler.
See it has this nice little helper method called
Download URL, which returns, as you might have guessed,
a URL that I can use to download this data later.
Let's print it out and see what happens.
So I'm going to add this debug line to our callback
and run it again.
And now I've got a URL that looks like this.
We're accessing our image via Firebase Storage dot Google
APIs dot com, and right there is our storage host,
and there's the path to our image.
And this stuff at the end is a token
that our end user will need to download this image.
As a developer, I can revoke these tokens later
should I ever need to.
So I can go ahead and copy and paste this
into my browser's address bar and voila,
there is my lovely image.
So in my app, I could load this image using a plain old data
with contents of URL call.
Although for images in particular,
there are some really nice third party libraries
like PINRemoteImage or Alamofire Image
that are worth looking at too.
So that's everything you need to know to upload and download
images, but hang on.
We are not quite done yet.
What happens if the user selects a movie?
Well, if you remember in my image picker delegate,
I get back to URL when the user selects the movie instead
of the movie itself, most likely because we don't want to load
this entire thing into memory.
Well, as luck would have it, Firebase Storage
also has a put file method built just
for this purpose that takes in a URL
to a file instead of some image data.
So my upload move to Firebase Storage method
looks nearly the same as my image method
with that one little change.
So I will create my storage ref to point to, say, my movie
slash test movie dot mov.
We can add in some metadata to specify
this is a QuickTime movie.
I'll create a storage upload task
and set it to the result of storage ref dot put
file, where I will pass in the file URL and the metadata.
We can print out some useful data in the completion handler.
And, once again, I can observe any status changes
in my upload task.
Oh, and while I'm at it, let me also print out some debug info.
I'll show you why in a second.
So I'll run this, select my movie to upload,
and there you go.
I'm uploading movie two.
And you'll notice that when I move my app in the background,
my upload task continues to run, which is pretty nice.
So there you go.
Everything you need to get started with Firebase Storage.
Now if you want to know more, feel
free to check out our documentation.
But before you do, I have three tasks for you.
One, revert back those storage rules like now,
while you're thinking about it.
Two, think about what parts of your app
might work best for a Firebase Storage.
Have any cool screenshots or images
that your users might want to share with their friends?
Well, this is the perfect solution
for that kind of feature.
And three, subscribe to our YouTube channel!
We got lots of great tutorials like this one and a whole lot
more on the way.
So go on, subscribe.
You know you want to.
And as always, thanks for watching.
[MUSIC PLAYING]