Swift Project – Digi Locker App
FREE Online Courses: Dive into Knowledge for Free. Learn More!
In this project, we will walk you through the steps of creating a Digi Locker app using SwiftUI. The Digi Locker app allows users to upload their files to Firebase Storage, delete files, and download them when needed. We will use the SwiftUI framework to design the user interface and Firebase Storage to handle file storage and retrieval.
About Swift Digi Locker App
Upon completing this project, you will have successfully developed a fully functional Digi Locker app, empowering users to effortlessly upload, delete, and download files from Firebase Storage.
Prerequisites for Digi Locker App Using Swift
To actively participate in this Swift Digi Locker project, the following items are required:
- Xcode is installed on your Mac.
- Basic knowledge of SwiftUI and Swift programming language.
- A Firebase account with a project set up. You will need the project’s Firebase configuration details to integrate Firebase Storage into the app.
Download Swift Digi Locker App
Please download the source code of Swift Digi Locker App from the following link: Swift Digi Locker App Project Code.
Steps to Create a Digi Locker App using Swift
Step 1: Setting up a new SwiftUI project in Xcode.
Step 2: Set Up Firebase Firestore
Step 3: Create the FirebaseManager
Step 4: Create the ContentView
Step 5: Create the DocumentPicker
Step 1: Setting up a new SwiftUI project in Xcode.
a. Launch Xcode and select the “Create a new Xcode Project” option.
b. Now select the platform as “iOS” and application type as “App”.
c. Now, Enter the name of the app and organization identifier, and select SwiftUI interface for building the UI of the app. Also, select Swift as the language for creating the app.
d. Select the folder where you want to save the app and click on Create.
e. Now your project is ready for development, and you will see something like below.
Step 2: Set Up Firebase Firestore
a. Go to the Firebase console and create a new project.
b. After adding a new project in the Firebase, the overview page for your project will open. Select the iOS platform for adding Firebase to your app.
c. Complete All the Steps in the order they guide you to complete.
d. After Completing all the tasks, your project in Xcode will look like this.
GoogleServices-info will be unique for all the users and will contain their key and authentication to store and modify their files in the Firebase storage. It will allow users to upload to their own storage bucket. So it is mandatory to follow the above steps clearly.
e. Enable Firebase storage for your project by selecting Storage in the sidebar, and then following the guide. Now your storage will be created and will look like below.
Make sure you have the necessary Firebase configurations added to your Xcode project.
Step 3: Create the FirebaseManager
- Create a new Swift file called FirebaseManager.swift.
- The FirebaseManager class is defined, which is responsible for handling interactions with Firebase Storage.
- The files property is an @Published array of strings that represents the file names in Firebase Storage. It notifies its observers whenever it changes.
- The filePins property is an @Published dictionary that stores the pin for each file. It notifies its observers whenever it changes.
- The downloadCompleted property is an @Published boolean that indicates whether a file download has been completed.
- The uploadFile(fileURL:) method takes a file URL as an input and then asks the user to set a pin for that file to protect it using the alert box. It then uploads the file to Firebase Storage.
- The deleteFile(fileName:) method takes a filename as input and deletes the corresponding file from Firebase Storage.
- The listFiles() function fetches the file list from Firebase Storage and updates the file property with the file names.
- The downloadFile(fileName:) method asks for a pin for that file. On entering the correct pin, it downloads that file from Firebase Storage and saves it to the device’s temporary directory.
import SwiftUI
import FirebaseStorage
class FirebaseManager: ObservableObject {
// An array of file names in Firebase Storage
@Published var files: [String] = []
// A dictionary to store the pin for each file
@Published var filePins: [String: String] = [:]
// A boolean indicating whether a file download has completed
@Published var downloadCompleted = false
// Uploads a file to Firebase Storage using the given file URL
func uploadFile(fileURL: URL) {
let storageRef = Storage.storage().reference()
// Prompts the user to enter a pin for the file
var pin = ""
let pinAlert = UIAlertController(title: "Enter Pin", message: "Please enter a pin to protect the file", preferredStyle: .alert)
pinAlert.addTextField { textField in
textField.isSecureTextEntry = true
}
pinAlert.addAction(UIAlertAction(title: "OK", style: .default) { _ in
if let enteredPin = pinAlert.textFields?.first?.text {
pin = enteredPin
// Uploads the file to Firebase Storage
_ = fileRef.putFile(from: fileURL, metadata: nil) { metadata, error in
if let error = error {
print("Error uploading file: \(error.localizedDescription)")
} else {
print("File uploaded successfully")
// Updates the files array after the upload is complete
self.listFiles()
// Stores the pin for the file
self.filePins[fileURL.lastPathComponent] = pin
}
}
}
})
UIApplication.shared.windows.first?.rootViewController?.present(pinAlert, animated: true)
}
// Deletes a file from Firebase Storage using the given file name
func deleteFile(fileName: String) {
// Creates a reference to the file in Firebase Storage
let storageRef = Storage.storage().reference().child(fileName)
// Deletes the file from Firebase Storage
storageRef.delete { error in
if let error = error {
print("Error deleting file: \(error.localizedDescription)")
} else {
print("File deleted successfully")
// Updates the files array after the deletion is complete
self.listFiles()
}
}
}
// Lists all files in Firebase Storage and updates the files array
func listFiles() {
let storageRef = Storage.storage().reference()
// Lists all files in Firebase Storage
storageRef.listAll { [weak self] result, error in
if let error = error {
print("Error listing files: \(error.localizedDescription)")
} else {
if let items = result?.items {
// Updates the files array with the names of the files in Firebase Storage
self?.files = items.map { $0.name }
}
}
}
}
// Downloads a file from Firebase Storage using the given file name and saves it to the device's temporary directory
func downloadFile(fileName: String) {
// Creates a reference to the file in Firebase Storage
let storageRef = Storage.storage().reference().child(fileName)
// Prompts the user to enter the pin for the file
var enteredPin = ""
let pinAlert = UIAlertController(title: "Enter Pin", message: "Please enter the pin to download the file", preferredStyle: .alert)
pinAlert.addTextField { textField in
textField.isSecureTextEntry = true
}
pinAlert.addAction(UIAlertAction(title: "OK", style: .default) { _ in
if let pin = self.filePins[fileName], let enteredPin = pinAlert.textFields?.first?.text, enteredPin == pin {
// Gets the download URL of the file
storageRef.downloadURL { url, error in
if let error = error {
print("Error getting download URL: \(error.localizedDescription)")
} else if let downloadURL = url {
// Perform the file download using the downloadURL
// For example, you can use URLSession to download the file
URLSession.shared.downloadTask(with: downloadURL) { localURL, response, error in
if let error = error {
print("Error downloading file: \(error.localizedDescription)")
} else if let localURL = localURL {
// Move the downloaded file to the desired location
// For example, you can use FileManager to move the file
let destinationURL = FileManager.default.temporaryDirectory.appendingPathComponent(fileName)
do {
// Moves the downloaded file to the device's temporary directory
try FileManager.default.moveItem(at: localURL, to: destinationURL)
// Sets the downloadCompleted boolean to true
self.downloadCompleted = true
print("File downloaded successfully \(destinationURL)")
} catch {
print("Error moving downloaded file: \(error.localizedDescription)")
}
}
}.resume()
}
}
} else {
print("Incorrect pin entered")
}
})
UIApplication.shared.windows.first?.rootViewController?.present(pinAlert, animated: true)
}
Step 4: Create the ContentView
- This step involves updating the code in the ContentView.swift file.
- The @StateObject property wrapper is used to create an instance of the FirebaseManager class as a state object.
- The body property is updated to display the list of files retrieved from Firebase Storage.
- If the firebaseManager.files array is empty, a message is shown indicating that there are no files and prompting the user to upload files.
- If the firebaseManager.files array is populated, a list is presented, showcasing each file’s name.
- Each file in the list has a context menu that contains a “Download” button, which calls the firebaseManager.downloadFile(fileName:) method.
- The list also supports deleting files. When a file is swiped and the delete action is triggered, the firebaseManager.deleteFile(fileName:) method is called.
- When the “Upload File” button is pressed, it prompts the document picker, enabling the user to choose a file to upload.
- The onAppear modifier is used to call the firebaseManager.listFiles() method when the view appears. This ensures that the list of files is loaded and updated.
- The .alert modifier is used to display an alert when a file has been successfully downloaded. The alert is shown when the firebaseManager.downloadCompleted property is set to true.
- The .onChange modifier is used to observe changes in the firebaseManager.downloadCompleted property. When a download is completed, it sets the showingDownloadAlert property to true and assigns a message to the downloadAlertMessage property.
- The ContentView_Previews struct provides a preview of the ContentView view.
import SwiftUI
struct ContentView: View {
// State variables to control the document picker and download alert
@State private var showingDocumentPicker = false
@State private var showingDownloadAlert = false
@State private var downloadAlertMessage = ""
// State object to manage Firebase interactions
@StateObject private var firebaseManager = FirebaseManager()
var body: some View {
VStack {
// If there are no files, show a message to upload files
if firebaseManager.files.isEmpty {
VStack {
Image(systemName: "exclamationmark.triangle")
.font(.system(size: 300))
.foregroundColor(.orange)
Text("There are no files, upload files")
}
.padding()
} else {
// Otherwise, show a list of files
List {
ForEach(firebaseManager.files, id: \.self) { file in
Text(file)
// Add a context menu to each file item with a "Download" button
.contextMenu{
Button(action: {
firebaseManager.downloadFile(fileName: file)
}) {
Label("Download", systemImage: "arrow.down.circle")
}
}
}
// Add support for deleting files
.onDelete { indexSet in
let fileName = firebaseManager.files[indexSet.first!]
firebaseManager.deleteFile(fileName: fileName)
}
}
}
// Add a button to upload files
Button(action: {
showingDocumentPicker.toggle()
}) {
Text("Upload File")
}
.sheet(isPresented: $showingDocumentPicker) {
// Show the document picker when the button is tapped
DocumentPicker { fileURL in
firebaseManager.uploadFile(fileURL: fileURL)
}
}
.frame(width: 200, height: 50)
.foregroundColor(.white)
.background(.green)
.font(.title2)
.cornerRadius(50)
}
.onAppear {
// Load the list of files when the view appears
firebaseManager.listFiles()
}
.alert(isPresented: $showingDownloadAlert) {
// Show an alert when a file has been downloaded
Alert(title: Text("File Downloaded"), message: Text(downloadAlertMessage), dismissButton: .default(Text("OK")))
}
.onChange(of: firebaseManager.downloadCompleted) { downloadCompleted in
// When a download is completed, show the download alert
if downloadCompleted {
showingDownloadAlert = true
downloadAlertMessage = "The file has been downloaded."
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}`
Step 5: Create the DocumentPicker
- Create a new Swift file called DocumentPicker.swift.
- The DocumentPicker struct is defined, which conforms to the UIViewControllerRepresentable protocol.
- The makeCoordinator function creates a coordinator object that handles the delegate methods of the UIDocumentPickerViewController.
- The updateUIViewController function is empty in this case since there are no updates needed for the view controller.
- The makeUIViewController function generates and provides a UIDocumentPickerViewController that is configured to permit document selection by the user.
- The Coordinator class is defined within the DocumentPicker struct and handles the delegate methods of the UIDocumentPickerViewController.
- The documentPicker(_:didPickDocumentsAt:) method is called when the user selects a document, and it passes the selected document’s URL to the onPicked closure.
- The documentPickerWasCancelled method is called when the user cancels the document picker.
import SwiftUI
import Foundation
import MobileCoreServices
// A struct conforming to the UIViewControllerRepresentable protocol that presents a document picker view controller
struct DocumentPicker: UIViewControllerRepresentable {
// A closure that is called when the user selects a document
var onPicked: (URL) -> Void
// Creates a coordinator object to handle the delegate methods of the UIDocumentPickerViewController
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
// Updates the view controller with the given context
func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: UIViewControllerRepresentableContext<DocumentPicker>) {
}
// Creates and returns a UIDocumentPickerViewController with the given context
func makeUIViewController(context: UIViewControllerRepresentableContext<DocumentPicker>) -> UIDocumentPickerViewController {
// Creates a UIDocumentPickerViewController that allows the user to select a document
let picker = UIDocumentPickerViewController(documentTypes: [String(kUTTypeItem)], in: .import)
// Sets the delegate of the picker to the coordinator object
picker.delegate = context.coordinator
return picker
}
// A class that handles the delegate methods of the UIDocumentPickerViewController
class Coordinator: NSObject, UIDocumentPickerDelegate {
let parent: DocumentPicker
init(_ parent: DocumentPicker) {
self.parent = parent
}
// Called when the user selects a document
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
// Gets the URL of the selected document
if let fileURL = urls.first {
// Calls the onPicked closure with the selected document's URL
parent.onPicked(fileURL)
}
}
// Called when the user cancels the document picker
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
// Handle cancellation if needed
}
}
Now the Digilocker app is ready to safeguard your files.
Swift Digi Locker App Output
Summary
Congratulations! You have successfully created the Digi Locker app using SwiftUI. Throughout this Swift Digi Locker App project, you have acquired the knowledge to carry out file uploads, downloads, and deletions from Firebase Storage. The app allows users to upload files, view a list of files, download files, and delete files. You can further enhance the app by adding more features based on your needs. Enjoy exploring and expanding your Digi Locker app.













Hlo