firebase / firebase-unity-sdk

The Firebase SDK for Unity
http://firebase.google.com
Apache License 2.0
199 stars 32 forks source link

[Bug] Crashlytics does not generate build id and crashes Android build at startup #918

Closed joaoborks closed 2 months ago

joaoborks commented 6 months ago

[REQUIRED] Please fill in the following fields:

[REQUIRED] Please describe the issue here:

I have a correctly set project that works for both platforms if built locally, but does not work when built by CI, and that is because the CI runner is a Linux machine with only the Android module installed. As described by unity-jar-resolver#412, the packages require the Unity iOS module to be installed, otherwise might cause issues when building. That is the exact case that happens on my CI setup.

Since my CI runner does not have the iOS Module, the Firebase.Crashlytics.Editor.dll can't be loaded and therefore cannot generate a crashlytics build id at build time, resulting in a crash with the following error on build:

The Crashlytics build ID is missing. This occurs when Crashlytics tooling is absent from your app's build configuration. Please review Crashlytics onboarding instructions and ensure you have a valid Crashlytics account.

Steps to reproduce:

Have you been able to reproduce this issue with just the Firebase Unity quickstarts (this GitHub project)?

Not tested, but I suppose it would not work if you'd have only the Android Module installed

What's the issue repro rate?

100%

What happened? How can we make the problem occur?

There are two ways to reproduce the issue:

Locally

Ensure you have the Firebase Crashlytics package installed, you do not have the Unity iOS Module installed, and clear your project's Library folder. Then, build the unity project from the command line.

On CI

Make sure you have the Firebase Crashlytics package installed. Run a build job for Android with a linux-android runner.

The outcome

Observing the build log, regardless of the way you built the app, you'll see the error:

Assembly 'Packages/com.google.firebase.crashlytics/Firebase/Editor/Firebase.Crashlytics.Editor.dll' will not be loaded due to errors:
Unable to resolve reference 'UnityEditor.iOS.Extensions.Xcode'. Is the assembly missing or incompatible with the current platform?
Reference validation can be disabled in the Plugin Inspector.

This will prevent the crashlytics build id from being generated at build time. And will ultimately crash the Android build at startup.

Our Workaround

We import the Firebase packages through .tgz and embed them into our repository for local UPM reference. So, to effectively workaround the issue:

  1. Unpack packages with assembly issues. What I mean by unpack is to extract the .tgz package file to a folder. In my case, they were:
    • External Dependency Manager Packages/com.google.external-dependency-manager/ExternalDependencyManager/Editor/<version>/Google.IOSResolver.dll
    • Crashlytics Packages/com.google.firebase.crashlytics/Firebase/Editor/Firebase.Crashlytics.Editor.dll
    • Firebase Core Packages/com.google.firebase.app/Firebase/Editor/Firebase.Editor.dl
  2. For each of the assemblies listed before, find their .dll.meta and .pdb.meta files (for example Firebase.Editor.dll.meta) and add the line:
    PluginImporter:
      serializedVersion: 1
      iconMap: {}
      executionOrder: {}
      isPreloaded: 0
    + validateReferences: 0
      platformData:
  3. Now, go into each of the extracted package folders (where the package.json file lives) and run npm pack on the terminal (make sure to install node if you don't have it)
  4. Finally, you will have a modified .tgz package you can replace in your project

You can tell when a build will work when you find this line in the build logs (I usually just ctrl + F "generated resource"):

Generated resource for com.crashlytics.android.build_id : <build-id>
UnityEngine.StackTraceUtility:ExtractStackTrace () (at /home/bokken/build/output/unity/unity/Runtime/Export/Scripting/StackTrace.cs:37)
UnityEngine.DebugLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[])
UnityEngine.Logger:Log (UnityEngine.LogType,object)
UnityEngine.Debug:Log (object)
Firebase.Crashlytics.Editor.AndroidPreBuild:WriteXmlResource (string,string,string,string) (at /Users/runner/work/firebase-unity-sdk/firebase-unity-sdk/editor/crashlytics/src/AndroidPreBuild.cs:87)
Firebase.Crashlytics.Editor.AndroidPreBuild:WriteBuildId () (at /Users/runner/work/firebase-unity-sdk/firebase-unity-sdk/editor/crashlytics/src/AndroidPreBuild.cs:100)
Firebase.Crashlytics.Editor.AndroidPreBuild:UpdateResourceFiles () (at /Users/runner/work/firebase-unity-sdk/firebase-unity-sdk/editor/crashlytics/src/AndroidPreBuild.cs:60)

Final Considerations

Our workaround is not the ideal way to fix the issue permanently. I believe that any platform-specific code should only be compiled if the platform is available, be that by constraining the assembly to a single platform, or by using UNITY_IOS or UNITY_ANDROID preprocessor directives.

The original issue on the unity-jar-resolver repository is 2 years old, and that is somewhat revolting. I understand that there are more urgent fixes and features on the line, but can it have some attention, please? It's ironic that an SDK to detect crashes ultimately causes your game to crash at startup because it was unable to find an id that itself was responsible for generating.

mrober commented 2 months ago

I took a look at this and notice you're only seeing the tool failure for iOS, but your issue is on Android. The Firebase Unity plugin has a different process for generating the build id / mapping file id for Android. It looks like that part didn't fail. It is possible the build id is being removed by a resource shrinker or something.

You can add a keep rule like this: https://github.com/firebase/firebase-android-sdk/blob/master/firebase-crashlytics/src/main/res/raw/firebase_crashlytics_keep.xml to your Android build. Or simply wait for the next version of Crashlytics which will include this keep rule automatically to deal with an upcoming change in the default behaviour of R8.

joaoborks commented 2 months ago

I took a look at this and notice you're only seeing the tool failure for iOS, but your issue is on Android.

That's not an accurate description of the issue. Since the Unity iOS Module is not installed, the Firebase.Crashlytics.Editor.dll does not load, even if we're only building for Android. The outcome is that the Android build does not have a build id information because the Firebase.Crashlytics.Editor.dll is not loaded and therefore will not execute the Crashlytics build post-process script that generates the build id.

The proposed workaround perfectly solves the issue.

mrober commented 2 months ago

That's not an accurate description of the issue.

Ok got it.

The proposed workaround perfectly solves the issue.

Since the workaround works, then the next release of the Unity plugin that includes the latest Crashlytics will resolve this issue, and you'll be able to remove the workaround. I'll close this for now since the workaround is working. Feel free to file a new issue if you run into the issue on the future version, and it might be better to file it in https://github.com/firebase/firebase-android-sdk if it is Android specific.