Firebase Storage GetFileAsync works on every platform except iPhones.

We’re using Firebase to store asset bundles which is then pulled down when the add needs them using Storage’s GetFileAsync() method. This has worked on every platform we’ve tested on, Android, Windows Editor, mac Editor, except not the iPhone. The storage error exception were also not helpful since all it says is “Unknown Error”

Here is the following relevant code:

Firebase reference:

public class FirestoreController : MonoBehaviour
{
    public static FirebaseFirestore firestoreInstance; //Firestore reference.  
    public static FirebaseStorage firebaseStorage;
    public static Firebase.Auth.FirebaseAuth firebaseAuth;
    public static StorageReference storageRef;

    private void Awake()
    {
        firestoreInstance = FirebaseFirestore.DefaultInstance;
        firebaseStorage = FirebaseStorage.DefaultInstance;
        firebaseAuth = Firebase.Auth.FirebaseAuth.DefaultInstance;
        storageRef = firebaseStorage.GetReferenceFromUrl("gs://<Storage Bucket>/");
    }
}

After the App signs-in anonymously (this has been tested to work properly). A GetFileAynch is called:

public async Task GetFile3(string _file) //generic download script for firebase storage.
    {                     
        string localPath = Application.persistentDataPath + "/" + _file; //save file into that folder.
        string platform = string.Empty;

        //checks platform. Windows uses the android bundle (editor-only).
        if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.WindowsEditor || Application.platform == RuntimePlatform.WindowsPlayer)
        {
            platform = "android/";
            //Debug.Log("Device is running on Android or Windows");
        }
        else if (Application.platform == RuntimePlatform.IPhonePlayer || Application.platform == RuntimePlatform.OSXPlayer || Application.platform == RuntimePlatform.OSXEditor)
        {
            platform = "ios/";
            //Debug.Log("Device is running on iPhone or Mac");
        }

        if (CheckConnectivity()) //if the device is connected to the internet, initiate download.
        {
            Debug.Log("Initiating download of: " + platform + _file);

            await FirestoreController.storageRef.Child("bundles").Child(platform).Child(_file).GetFileAsync(localPath).ContinueWith(task =>
            {
                if (!task.IsFaulted && !task.IsCanceled) //if download is successful.
                {
                    Debug.Log("file saved as " + localPath);
                }
                else //otherwise report error.
                {
                    Debug.Log(task.Exception.ToString());
                }
            });
        }
        else //otherwise don't bother.
        {
            Debug.Log("Cannot Download file due to lack of connectivity!");
        }
    }

The code stops work on iPhones at: FirestoreController.storageRef.Child(“bundle”).Child(platform).Child(_file).GetFileAsync(…)

The path to the file is correct, and it works and downloads and saves the correct file on the unity Editor on a Mac. Not sure why it doesn’t on an iPhone. The file is also accessible from there on.

I’m not sure why the iPhone is giving me trouble because the only error message i get from Firebase.Storage is this:

Device is running on iPhone or Mac

<>c__DisplayClass5_0:<GetFile3>b__0(Task)

System.Array:UnsafeStore(T[], Int32, T)

FirebaseStorageGetter:GetFile3(String)

AppUpdateChecker:.ctor()

System.Array:UnsafeStore(T[], Int32, T)

AppUpdateChecker:CheckForUpdates()

<>c:<GooglePlayChecker>b__2_0(Task`1)

System.Threading.ContextCallback:Invoke(Object)

System.Threading.ExecutionContext:RunInternal(ExecutionContext, ContextCallback, Object, Boolean)

System.Runtime.CompilerServices.MoveNextRunner:Run()

System.Action:Invoke()

System.Threading.ContextCallback:Invoke(Object)

System.Threading.Tasks.AwaitTaskContinuation:RunCallback(ContextCallback, Object, Task&)

System.Threading.Tasks.Task:FinishContinuations()

System.Threading.Tasks.Task`1:TrySetResult(TResult)

System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1:Create()

<>c:<SignInAnon>b__0_0(Task`1)

System.Threading.ContextCallback:Invoke(Object)

System.Threading.ExecutionContext:RunInternal(ExecutionContext, ContextCallback, Object, Boolean)

System.Runtime.CompilerServices.MoveNextRunner:Run()

System.Action:Invoke()

System.Threading.SendOrPostCallback:Invoke(Object)

UnityEngine.UnitySynchronizationContext:Exec()

UnityEngine.UnitySynchronizationContext:Exec()


(Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)


System.AggregateException: One or more errors occurred. ---> Firebase.Storage.StorageException: An unknown error occurred

   --- End of inner exception stack trace ---

---> (Inner Exception #0) Firebase.Storage.StorageException: An unknown error occurred<---

I’m not sure if the the app can’t see the file on Firebase Storage, or it can’t write to Application.PersistentDataPath because I’m using the wrong format for iOS.

Things we’ve already checked for:

  1. Building the iOS app on .NET4.x, required for the Firebase packages we used.
  2. All firebase packages is at the latest version 7.0.2, confirmed from the Package Manager.
  3. The app is build on Arm7 and Arm64, with IL2CPP.
  4. Write permission is set to Internal.

Are there anything specific to iPhones build settings that I might be overlooking?

The only Firebase feature I’ve used before is push notifications, but I seem to remember I had a confusing issue where a feature wasn’t working when I copied a debug build directly from my dev machine onto the test device, but suddenly worked fine if I distributed the app through TestFlight (and, later, the app store). I imagine iOS must have some special hooks that are only enabled if you use an “official” install path. (I had no analogous problem on Android.)

No idea whether that would be relevant for your problem, but if you haven’t tried that, it might be worth checking.

1 Like

Hm, can’t hurt to try it. Thanks! :smile:

EDIT: Problem solved. For iOS i needed to add “file://” before the Application.PersistentDatapath for the save location. :stuck_out_tongue:

7 Likes

Thanks for your solution. You saved my tens of hours. Love your mushroom man.
It would be better mentioned about “file://” thing in Application.PersistentDatapath document or firebase document. How could none of them did that?!

1 Like

Thank you !!
I love mushroom man too.

1 Like

I still ran into some ill-defined problems when using the file:// before the Application.PersistentDatapath.

One should only use it when passing paths to the Firebase library, but not when using regular System.IO methods.

I also updated all the Firebase libraries to the latest version (8.0.0 at the moment) because there are some initialization fixes in the 7.x patches. Hope that helps someone!

2 Likes

When you say working “on every platform” do you mean it is working on WebGL editor and build as well ?

No only on Android and Android devices. We’ve yet to try compiling to WebGL, since that wasn’t our target. Firebase doesn’t work on Windows standalone, so that’s also out of the question.

Thank you, you saved me :slight_smile:

Thank you ! I stumble across the issue and it’s also explained here : [Question] GetFileAsync fails on iOS with unknown error · Issue #402 · firebase/firebase-unity-sdk · GitHub