Search code examples
c#firebaseunity-game-enginefirebase-storage

Downloading an entire firebase storage folder's content in Unity


Hello im trying to download an entire folder's content from firebase into an android device.

The firebase hierarchy looks like the following: enter image description here

So far I can only download a single file using the following code:

// ------------------------- FILE DOWNLOADING ------------------------------------- //
Debug.Log("Download Attempt...");

if (Permission.HasUserAuthorizedPermission(Permission.ExternalStorageWrite))
{
    Debug.Log("STEP1...");
    //Firestore Reference
    storage = FirebaseStorage.DefaultInstance;
    storageReference = storage.GetReferenceFromUrl("gs://houdini-ac884.appspot.com");
    StorageReference riversRef = storageReference.Child("uploads/3895d968-65bf-4e2d-a964-763e22742fdf.meta");
    //StorageReference 
    //pathReference = storage.GetReference("uploads/3895d968-65bf-4e2d-a964-763e22742fdf.meta");
    // Create local filesystem URL
    Debug.Log("STEP2...");
    var Directory_path = ("SparseSpatialMap/" + "3895d968-65bf-4e2d-a964-763e22742fdf.meta");
    var path = (Application.persistentDataPath + "/" + Directory_path);   
    Debug.Log("STEP3...");
    // Download to the local filesystem
    //pathReference.GetFileAsync(path).ContinueWithOnMainThread(task => 
    //{
    riversRef.GetFileAsync(path).ContinueWithOnMainThread(task => 
    {
        if (!task.IsFaulted && !task.IsCanceled) 
        {
            Debug.Log("Finished downloading...");
            easyar.GUIPopup.EnqueueMessage("Download Completed", 5);
        }
        else
        {
            Debug.Log("DOWNLOAD FAILURE !!!!!!!!!!!!!");
            Debug.Log(task.Exception.ToString());
            easyar.GUIPopup.EnqueueMessage("FAIL EXCEPTION", 5);
        }

        Debug.Log("STEP4...");
    });
} 
else 
{
    Debug.Log("No Permissions");
    easyar.GUIPopup.EnqueueMessage("FAIL, No permissions", 5);
    Permission.RequestUserPermission(Permission.ExternalStorageWrite);
}

Debug.Log("End of Download Attempt...");
// ------------------------- FILE DOWNLOADING END ------------------------------------- //

From what I understand there isnt a firebase function to download all files in folder and I would have to use something else. Any help would be apreciated thanks


Solution

  • There's a REST API to get the metadata information of all the files present inside a folder.

    https://firebasestorage.googleapis.com/v0/b/YOUR_PROJECT_ID/o?preifx=path/to/folder
    

    The param passed to the above API is the path to the folder.

    First you need to get a list of files present in a folder. The below method gets a list of file:

    async Task<List<FileMetadata>> GetFilesInFolder(string path)
    {
        const string baseUrl = "https://firebasestorage.googleapis.com/v0/b/";
        const string projectId = "PROJECT_ID";
    
        // Build the REST API URL
        string url = $"{baseUrl}{projectId}/o?prefix={path}";
    
        // Send a GET request to the URL
        using (HttpClient client = new HttpClient())
        using (HttpResponseMessage response = await client.GetAsync(url))
        using (HttpContent content = response.Content)
        {
            // Read the response body
            string responseText = await content.ReadAsStringAsync();
    
            // Deserialize the JSON response
            ListFilesResponse responseData = JsonConvert.DeserializeObject<ListFilesResponse>(responseText);
    
            // Return the list of files
            return responseData.Files;
        }
    }
    

    After you get the list of metadata of the files, start downloading each of them.

    List<FileMetadata> files = await GetFilesInFolder(folderPath);
    
    // Download each file
    foreach (FileMetadata file in files)
    {
        // Get the file's download URL
        string downloadUrl = file.DownloadUrl;
    
        // Download the file using the URL
        using (HttpClient client = new HttpClient())
        using (HttpResponseMessage response = await client.GetAsync(downloadUrl))
        using (HttpContent content = response.Content)
        {
           
            byte[] fileData = await content.ReadAsByteArrayAsync();
    
            // Save the file to the device
        
        }
    }
    

    Also do add the response objects from Firebase's endpoints

    class ListFilesResponse
    {
        public List<FileMetadata> Files { get; set; }
    }
    
    // Class that represents metadata for a file in Firebase Storage
    class FileMetadata
    {
        public string Name { get; set; }
        public string DownloadUrl { get; set; }
    }