PhotosPicker with Firebase Storage / SwiftUI
Learn how to pick up a picture from your phone library with SwiftUI PhotosPicker and upload the data to Firebase Storage.
Difficulty: Beginner | Easy | Normal | Challenging
Environment : Xcode 14, iOS 16 & SwiftUI
Full code at the end of the article
Create new Xcode Project
Open Xcode > App template > SwiftUI Life Cycle and call it PictureStorage
Firebase Set Up
To integrate Firebase to your project, I invite you to check out this article and get back if you don’t know how to configure a project with Firebase:
During the process, make sure to add the following dependency:
- FirebaseStorage
Set Up Firebase Storage
Unlike Firestore or Realtime Database, the Firebase Storage framework is built to store larges assets. It will be our server to store documents such as videos, images, audio files etc…
Let’s set it up in our console, go to Firebase console > Storage panel. Then, click on get started and select “start in test mode”, then select whatever storage location.
Let’s code
Great! Now, we are ready to upload picture from our front-end to the Firebase backend. First let’s design the user interface to post pictures, import both frameworks at the top of the ContentView.swift file :
import PhotosUI
import FirebaseStorage
The PhotosUI framework will be useful to access the user photo library and FirebaseStorage to use their APIs to upload that selected picture.
Then, let’s observe these two State, add the following code over the body variable:
@State var data: Data?
@Statevar selectedItem: [PhotosPickerItem] = []
These reference will useful when selecting the picture and upload it as data. The PhotosPickerItem will be used to have a representation type of our data.
Let’s now create a form composed of a PhotosPicker with a button to upload to Firebase.
Copy/paste the code inside the body variable:
Great, we now have a button that let the user select one picture from his phone library. Following the selection, this image is displayed, if the user wish to change it, he can still click and select another one. Also, the button to publish is disabled if there are no images selected.
SwiftUI make it easy to manage the state of our user input in a few lines of code. You can run your application and test it out:
Upload to Firebase Storage
It’s now time to implement a function to uplaod the data we selected to Firebase Storage. To achieve this, we first need to make a reference, copy/paste the following code after the two State we wrote earlier:
let storageReference = Storage.storage().reference().child(“\(UUID().uuidString)”)
This will be useful to generate a new identifier each time we are uploading an image to Firebase. Now, add the function below inside the button action:
// Function to post data to Firebase Storage
storageReference.putData(data!, metadata: nil) { (metadata, error) in
guard let metadata = metadata else { return }
}
You can run the application, select a picture and you will see it on our Firebase console:
You can upload as many images as you want, every time you upload one, it will get a new identifier.
Conclusion
In this tutorial, we connected our application to Firebase Storage, setup the framework and upload a photo in just a few lines of code using the new SwiftUI PhotosPicker to access the photo library of our phone.
You can support my work by either buying my book on SwiftUI & Firebase or subscribing to enjoy unlimited access to my articles and all of Medium through my referral link.
Full code:
import SwiftUI
import PhotosUI
import FirebaseStorage
struct ContentView: View {
@State var data: Data?
@State var selectedItem: [PhotosPickerItem] = []
let storageReference = Storage.storage().reference().child("\(UUID().uuidString)")
var body: some View {
Form {
Section {
PhotosPicker(selection: $selectedItem, maxSelectionCount: 1, selectionBehavior: .default, matching: .images, preferredItemEncoding: .automatic) {
if let data = data, let image = UIImage(data: data) {
Image(uiImage: image)
.resizable()
.scaledToFit()
.frame( maxHeight: 300)
} else {
Label("Select a picture", systemImage: "photo.on.rectangle.angled")
}
}.onChange(of: selectedItem) { newValue in
guard let item = selectedItem.first else {
return
}
item.loadTransferable(type: Data.self) { result in
switch result {
case .success(let data):
if let data = data {
self.data = data
}
case .failure(let failure):
print("Error: \(failure.localizedDescription)")
}
}
}
}
Section {
Button("Upload to Firebase Storage") {
// Function to post data to Firebase Storage
storageReference.putData(data!, metadata: nil) { (metadata, error) in
guard let metadata = metadata else {
return
}
}
}.disabled(data == nil)
}
}
}
}