Skip to content

[Bug] Remote config fetch seems to hang forever on iOS on random sessions #920

Open
@BrooklynDipi

Description

@BrooklynDipi

[REQUIRED] Please fill in the following fields:

  • Unity editor version: 2022.3.11f1
  • Firebase Unity SDK version: 11.6.0
  • Source you installed the SDK: tgz via UnityPackageManager
  • Problematic Firebase Component: RemoteConfig
  • Other Firebase Components in use: Auth, Crashlytics, Analytics, and External Dependency Manager
  • Additional SDKs you are using: Facebook
  • Platform you are using the Unity editor on: Windows 11, MacOS
  • Platform you are targeting: iOS, Android
  • Scripting Runtime: IL2CPP
  • Pre-built SDK from the website or open-source from this repo: Google APIs for Unity Archive

[REQUIRED] Please describe the issue here:

(Please list the full steps to reproduce the issue. Include device logs, Unity logs, and stack traces if available.)

When using RemoteConfig on iOS devices, the function, FetchAsync(), has a roughly 30% chance of failing. This also occurs with FetchAndActivateAsync(). I use this tool to version check the application on start-up. If the application is out of date, it stops the user from progressing. Sometimes this function does not complete so the values needed to evaluate your continuation are not accurate. This issue does not occur on Android.

I found a similar issue to this that occurred back in 2022 here on the quickstart bug page. They seemed to have solved it by setting the External Dependency Manager's iOS resolver settings to "Link Frameworks Statically" in addition to an SDK update. I suspect this is the issue that is possibly occurring for me currently. That said, I am unable to set "Link Frameworks Statically" to true as it breaks FacebookSDK.

The reason I suspect this is a similar issue is because of the logs I receive in XCode when running on iOS. I have debug logs that print the fetched version number as well as the current application version number. In this 30% chance window, I see the call stack for FetchAsync() begin but it does not produce any results, and the string that is set by its fetched values always results in an empty string.

I am hoping though that perhaps I am making a silly mistake and that this is not the reason. I have tried many different approaches to using the RemoteConfig API that have all resulted in a lack of consistency on iOS only. Android has been functional every time. I generally initialize Firebase in Awake() in our Auth script and I have previously hooked in the FetchAsync() function to that script, where its called after CheckAndFixDependenciesAsync(). No difference was made.

I made sure to review and try approaches from the documentation here.

Steps to reproduce:

What's the issue repro rate? (eg 100%, 1/5 etc)

  • Seems to be roughly 30%. I have tested this by simply closing and reopening the app on an iOS device to see if I get the intended results.

What happened? How can we make the problem occur?
This could be a description, log/console output, etc.

  • Fetch values from remote config with "Link Frameworks Statically" set to false.

Relevant Code:

using DG.Tweening;
using Firebase;
using Firebase.Extensions;
using Firebase.RemoteConfig;
using System;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;

public class RemoteConfigVersionControl : MonoBehaviour
{
    public static RemoteConfigVersionControl Instance;

    public GameObject UpdateGraphic;

    [HideInInspector]
    public bool isVersionCurrent = false;

    [HideInInspector]
    public string thisVersionNumber;

    [HideInInspector]
    public string currentVersionNumbers;

    private void Awake()
    {
        Instance = this;

        thisVersionNumber = Application.version;

        currentVersionNumbers = "0";
    }

    private async void Start()
    {
        await FirebaseApp.CheckAndFixDependenciesAsync();

        await FetchDataAsync();
    }

    private Task FetchDataAsync()
    {
        Debug.Log("Fetching data...");

        Task fetchTask = FirebaseRemoteConfig.DefaultInstance.FetchAsync(TimeSpan.Zero);

        return fetchTask.ContinueWithOnMainThread(FetchComplete);
    }

    private void FetchComplete(Task fetchTask)
    {
        if (!fetchTask.IsCompleted)
        {
            Debug.LogError("Retrieval hasn't finished.");
            return;
        }

        var remoteConfig = FirebaseRemoteConfig.DefaultInstance;

        var info = remoteConfig.Info;

        if (info.LastFetchStatus != LastFetchStatus.Success)
        {
            Debug.LogError($"{nameof(FetchComplete)} was unsuccessful\n{nameof(info.LastFetchStatus)}: {info.LastFetchStatus}");
            return;
        }

        // Fetch successful. Parameter values must be activated to use.
        remoteConfig.ActivateAsync()
          .ContinueWithOnMainThread(
            task =>
            {
                Debug.Log($"Remote data loaded and ready for use. Last fetch time {info.FetchTime}.");

                currentVersionNumbers = FirebaseRemoteConfig.DefaultInstance.GetValue("VersionNumber").StringValue;

                VersionComparison();
            });
    }

    public void VersionComparison()
    {
        Debug.Log("THIS VERSION NUMBER: " + thisVersionNumber);

        Debug.Log("CURRENT VERSION NUMBER: " + currentVersionNumbers);

        if (currentVersionNumbers == "0")
        {
            isVersionCurrent = true;
        }
        else if (currentVersionNumbers.Contains(thisVersionNumber))
        {
            isVersionCurrent = true;
        }
        else
        {
            isVersionCurrent = false;
        }
    }

    public void EnableUpdateGraphic()
    {
        if (UpdateGraphic != null)
        {
            var UpdateGraphicImage = UpdateGraphic.GetComponent<Image>();

            UpdateGraphic.SetActive(true);

            UpdateGraphicImage.DOFade(1, .5f);
        }
    }
}

Call stack for unfinished function

Fetching data...
RemoteConfigVersionControl:FetchDataAsync()
<Start>d__6:MoveNext()
System.Runtime.CompilerServices.AsyncVoidMethodBuilder:Start(TStateMachine&)
RemoteConfigVersionControl:Start()

Call stack for finished function

Fetching data...
RemoteConfigVersionControl:FetchDataAsync()
<Start>d__6:MoveNext()
System.Threading.ExecutionContext:RunInternal(ExecutionContext, ContextCallback, Object, Boolean)
System.Runtime.CompilerServices.MoveNextRunner:Run()
UnityEngine.WorkRequest:Invoke()
UnityEngine.UnitySynchronizationContext:Exec()

Remote data loaded and ready for use. Last fetch time 1/3/2024 9:03:55 PM.
<>c__DisplayClass8_0:<FetchComplete>b__0(Task`1)
Firebase.Extensions.<>c__DisplayClass4_1`1:<ContinueWithOnMainThread>b__1()
Firebase.<>c__DisplayClass5_0`1:<RunAsync>b__0()
Firebase.ExceptionAggregator:Wrap(Action)
Firebase.Dispatcher:PollJobs()
Firebase.Platform.FirebaseHandler:Update()

THIS VERSION NUMBER: 1.03.408
RemoteConfigVersionControl:VersionComparison()
<>c__DisplayClass8_0:<FetchComplete>b__0(Task`1)
Firebase.Extensions.<>c__DisplayClass4_1`1:<ContinueWithOnMainThread>b__1()
Firebase.<>c__DisplayClass5_0`1:<RunAsync>b__0()
Firebase.ExceptionAggregator:Wrap(Action)
Firebase.Dispatcher:PollJobs()
Firebase.Platform.FirebaseHandler:Update()

CURRENT VERSION NUMBER: 1.03.395
1.03.406

RemoteConfigVersionControl:VersionComparison()
<>c__DisplayClass8_0:<FetchComplete>b__0(Task`1)
Firebase.Extensions.<>c__DisplayClass4_1`1:<ContinueWithOnMainThread>b__1()
Firebase.<>c__DisplayClass5_0`1:<RunAsync>b__0()
Firebase.ExceptionAggregator:Wrap(Action)
Firebase.Dispatcher:PollJobs()
Firebase.Platform.FirebaseHandler:Update()

image

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions