Swift Project – Digi Locker App
FREE Online Courses: Elevate Your Skills, Zero Cost Attached - Enroll Now!
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.
You give me 15 seconds I promise you best tutorials
Please share your happy experience on Google | Facebook