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.

new swift project in xcode

b. Now select the platform as “iOS” and application type as “App”.

select the platform as ios

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.

enter the name of 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.

project is ready for development

Step 2: Set Up Firebase Firestore

a. Go to the Firebase console and create a new project.

firebase console

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.

after adding new project in firebase

c. Complete All the Steps in the order they guide you to complete.

complete all the steps

d. After Completing all the tasks, your project in Xcode will look like this.

your project in xcode

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.

enable firebase project

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

swift digi locker output

digi locker app project output

digi locker output

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

Leave a Reply

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