Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Requests] Optionally disable the "invalid bundle id" modal dialogbox and improve the Unity Firebase initialization flow to help avoid null pointer exceptions. #643

Open
jhughes2112 opened this issue Apr 13, 2020 · 7 comments

Comments

@jhughes2112
Copy link

Please fill in the following fields:

Unity editor version: 2018.4LTS (or any)
Firebase Unity SDK version: 6.7.0 (or any)
Source you installed the SDK (.unitypackage or Unity Package Manager): .unitypackage
Firebase plugins in use (Auth, Database, etc.): Crashlytics, Messaging, Dynamic Link
Additional SDKs you are using (Facebook, AdMob, etc.): Facebook, Skillz
Platform you are using the Unity editor on (Mac, Windows, or Linux): Mac, Windows
Platform you are targeting (iOS, Android, and/or desktop): iOS, Android
Scripting Runtime (Mono, and/or IL2CPP): IL2CPP

Please describe the issue here:

Some people (like me) have many apps in one Unity project and each has a different bundle ID. Whenever the bundle ID is changed (due to a script we run in the editor), there is no function we call to tell Firebase to update its understanding of the current bundle ID. Instead, it triggers automatically according to some callback in Unity (presumably). This is really a bad design. What happens is, we have to change the bundle ID, swap the current .plist and .json files for GoogleServices, explicitly call AssetDatabase.SaveAssets(), and hope that we did this dance in the right order so that stupid bundle id selector window doesn't show up, because it sometimes pops up on a DIFFERENT MONITOR, and completely locks the Editor from accepting input until we deal with the modal dialog. Even having done this correctly, sometimes it decides to pop up when we hit Play, for no apparent reason. Please, don't ever put a modal dialog on my screen. Ever. Let me call a function to deliver the information you need directly, rather than gathering data indirectly via the environment (AssetDatabase, files, etc) at the wrong time. And if something doesn't look right, throw an error in the log and shut yourself off. Never interrupt the developer.

Further, on Android (and iOS?) if you install the C# .unitypackage for one of the Firebase modules, but don't actually install the .aar that goes with it, you get a null pointer exception at runtime. There's no way to know this is going to happen in the Editor, but you find out once you build for a device and it blows up during initialization.

Also, the fact that any and all calls will throw null pointer exceptions until after Firebases Initializes requires all your users to wrap the whole SDK with a proxy of some sort, so we don't accidentally blow up by touching a live wire. At least write the proxy on YOUR side of the SDK, so it returns an error code instead of blindly dereferencing null.

If you actually want people to LIKE using your products, you need to make it have a higher value-to-integration-pain ratio. Firebase has a lot of potential and some great features, but these kinds of issues take all the joy away.

Please answer the following, if applicable:

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

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

@jhughes2112 jhughes2112 added the new New issue. label Apr 13, 2020
@jmcguirk
Copy link

Also suffering from the same ergonomic pain here (we'll swap bundle ID based on environment and product ID) and frequently run into this dialog when doing so. I'd love to see this dialog suppressed based on a project setting (that can be checked into source) - or honestly, just dropped to an error/warning in BuildPlayer()

@roointan
Copy link

1 for null pointer exceptions prevention
I'm going to need the proxy too and I'm going to write one for our project.

@patm1987
Copy link

Hi @jhughes2112,

I'm sorry that you're having issues and thanks for your feature requests! It does help us track them internally if you break them up into multiple issues, but if you don't mind I'll try to address them as I can.

We do know that multiple targets are an issue, and one that many developers want. See firebase/firebase-unity-sdk#376 , we are tracking these.

For the dialog box, I understand that it is frustrating, but for many of our newer users would be more lost without that modal dialog. I'll try to log this as a separate feature request associated with this bug. I'm a heavy user of multiple virtual desktops on Windows (going back to the Microsoft PowerToys days), Linux, and MacOS, so I understand where you're coming from there.

With respect to native libraries, it can be confusing to have aar files in your Assets directory. Firebase relies heavily native interfaces to really take advantage of the underlying platforms and the C layer helps ensure that all game developers get an equally functional and tested experience on all supported platforms. If you use the new Unity Package Manager integration, many of user experience issues related to aar, a, so, and other "build artifacts" (to many VCS products) in your Assets directory will go away. There have been some issues found in the 6.13 Firebase release and rest assured that the team is working as fast as possible to improve that experience. I'm mostly excited about these improvements as I'll be able to upload projects to GitHub without requiring everyone to turn on Git LFS again!

Finally, the lazy singleton design is annoying in a purely Unity context. The project has roots back into early versions of Unity, when many developers (including some projects I worked on prior to Google) would ship core parts of their game as unit tested DLLs with Unity acting as a thin view model. The current Firebase design pattern avoids alienating similarly structured workflows (and fits well with ZenJect projects I've worked on), but can be frustrating in a modern vanilla Unity setup. I'd love to hear about the kinds of wrappers you're building and what the shape of the proxy you envision would look like!

I hope that all helps, and I'm definitely hanging around Twitter and StackOverflow if you get stuck on any individual thing (or need a temporary workaround)!

--Patrick

@patm1987 patm1987 changed the title Unity Integration is anger-inducing. Please address. [Feature Requests] Add support for multiple projects/bundle id's and improve the Unity Firebase initialization flow to help avoid null pointer exceptions. Apr 14, 2020
@patm1987
Copy link

I hope you don't mind that I changed the title. It'll be easier for my coworkers to follow the actionable requests in the issue this way!

@patm1987 patm1987 added type: feature request and removed new New issue. labels Apr 14, 2020
@patm1987 patm1987 changed the title [Feature Requests] Add support for multiple projects/bundle id's and improve the Unity Firebase initialization flow to help avoid null pointer exceptions. [Feature Requests] Optionally disable the "invalid bundle id" modal dialogbox and improve the Unity Firebase initialization flow to help avoid null pointer exceptions. Apr 14, 2020
@jhughes2112
Copy link
Author

@patm1987 I'm not offended at the title change. :-) What I would suggest is that FIrebase is integrated in a most egregious way, and breaks all kinds of best practices. Let me elaborate.

Never, ever assume a file exists for your pleasure at a specific path.
Example 1: We can't currently move the Firebase folder to a 3rd party folder, because it assumes .dll's and whatnot are specifically stored in Assets/Firebase. Please make it relative or irrelevant where the files are stored. It causes pain for people who move them only to find everything breaks for no obvious reason.
Example 2: The GoogleService-Info.plist and google-services.json files must exist in Assets/PlayServicesResolver, which by itself is an enormous problem because the contents of these files must be modified in order for Firebase to allow multiple bundle ids in one project. All it would take is a trivial script to LOAD these files and SEND their contents into your API, but instead your API reads the files directly. Don't do that. You haven't got a clue where the data might be stored or what format it's in. As an API, your job is to react to someone poking data into you, not read data for yourself. If you stay in your lane, we all get where we want to go faster.

As for the proxy that everyone has to write, it's because we can't call any of your functions before the Init is complete, which is asynchronous (and unity is not inherently async friendly). So most people set up a coroutine on an object that polls for completion of the Firebase Initialization, then does a Remote Config fetch and sets up another coroutine waiting for that to finish, then unblocks calls to the API proxy. So there's a ton of polling all around. Clever use of delegate callbacks make this less messy, but it's still something every dev will do once they are burned by the way Firebase handles exceptions a few times.

Case in point. Our last major push of 23 apps had recently included RemoteConfig. When you request a string from RemoteConfig that doesn't exist, you get a string back. When you request a DOUBLE from RemoteConfig, you get an exception. Didn't know that. We pushed out some data that caused the apps to fetch something unexpected and blew up about 300,000 users' experiences, since uncaught exceptions in our apps are fatal. Thanks, guys. Not documented behavior.

I know, it just sounds like I'm griping, and I am, but the quality bar can be raised so much higher with such little effort, that it's really astonishing you haven't had more developer feedback telling you so. And just so you know I'm not just a crank (although I do accept cranky as appropriate), I wrote the first chapter on Game Engine Gems, entitled "What to Look For When Evaluating Middleware for Integration". So I'm opinionated. :-)

I hope some of this strikes a chord and positive change comes out of it. Firebase has a lot to offer, but it asks a lot more of developers than you probably know.

JH

@jhughes2112
Copy link
Author

jhughes2112 commented Apr 15, 2020

I would also mention, since we're on the subject, that I had to spend a lot of time reverse-engineering how to make FirebaseApp.Create work properly to force Firebase to use my specific app configuration while in the Unity Editor. Again, it's utterly broken because Default is whatever happens to be stored in "StreamingAssets/google-services-desktop.json", and we can't control that at runtime, so Firebase generates Default with whatever is in there, then I have to create a different AppOptions with what I really want there, but there's no way to overwrite Default nor remove Default, so I have to call it something else... anything else. If I could simply feed the Default AppOptions correctly before Firebase initializes, all this problem would go away. Again, because you're reading files rather than looking to be told what to do.

For reference, here's what I had to do to init properly. It's a rat's nest of poking and reverse engineering.

Debug.Log("FirebaseInit start initialization.");
		pathToConfig = Path.Combine(Application.dataPath, "StreamingAssets/google-services-desktop.json");

		// Set log level so we can see exceptions being thrown in the game.
		Firebase.FirebaseApp.LogLevel = Firebase.LogLevel.Debug;
		Task<Firebase.DependencyStatus> initTask = Firebase.FirebaseApp.CheckAndFixDependenciesAsync();
		initTask.ContinueWithOnMainThread(t => { 
				Firebase.DependencyStatus status = t.Result;
				if (status!=Firebase.DependencyStatus.Available)  // failed to init Firebase for one reason or another
				{
					Debug.LogError(System.String.Format("Could not resolve all Firebase dependencies: {0}.  QUITTING", status));
					Application.Quit();
				}

#if UNITY_EDITOR
				Firebase.AppOptions appOptions = new Firebase.AppOptions();
				string appName = Firebase.FirebaseApp.DefaultName;
				// Pull in the google-services-desktop.json file
				string jsonConfig = File.ReadAllText(pathToConfig);
				appOptions = Firebase.AppOptions.LoadFromJsonConfig(jsonConfig);
				appName = "current_app_name";  // just a disambiguating string

				// Create the app we want to actually work with (in UNITY_EDITOR this is often NOT the same as the default app, but on device it should be the same thing)
				Firebase.FirebaseApp.Create(appOptions, appName);
#endif
				initialized = true;
				Debug.Log("FirebaseInit initialization complete!");
				Firebase.Analytics.FirebaseAnalytics.LogEvent(Firebase.Analytics.FirebaseAnalytics.EventAppOpen);
			});

@shunia
Copy link

shunia commented Apr 20, 2020

And the modal dialog fails A LOT, just hang in the middle, with the progress bar shows 12% or 36% - with version 6.11.0, for scripting build which I use the code below to process my build for package name change:

GenerateXmlFromGoogleServicesJson.ForceJsonUpdate();
GooglePlayServices.PlayServicesResolver.Resolve(
            null, false, b =>
        {
            if (!b)
            {
                Debug.LogError("Build - Google play service resolve failed");
                return;
            }
    
            PostBuild();
        });

I have to retrigger my build script one more time to come over this problem.

I did tried the version 6.13.0, it won't stuck, but got many other issues and I just have to roll back.

So if you are able to, better take the newest version a try.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants