juicycleff / flutter-unity-view-widget

Embeddable unity game engine view for Flutter. Advance demo here https://github.com/juicycleff/flutter-unity-arkit-demo
BSD 3-Clause "New" or "Revised" License
2.14k stars 523 forks source link

Unity app is rendering on top of Flutter UI in Android versions below 10 #347

Open thassio-vinicius opened 3 years ago

thassio-vinicius commented 3 years ago

I'm using a tab system for our app, with the middle tab (i.e. train tab) being the tab where the Unity games are supposed to be played. We have two games bundled together inside the Unity project and it's my understanding that you can't send a message to Unity before the Unity project is launched and the Unity controller is ready, which is why our business logic requires the Unity app to be launched beforehand so the user can choose between one of the two games. For that, I've been using a Stack widget with the Unity widget launching the initial scene on the background and the "Play game X" buttons on the foreground.

Everything works just fine in iOS and Android 10 (both for debug and release mode), but Android 9 in particular seems to be facing some issues. Here are some screenshots to illustrate the issue (taken from a Xiaomi Mi Note 3 with Android 9):

The loading screen is actually the initial Unity scene, which is rendering over the Flutter UI for the other two tabs. Here's how it's supposed to work (screenshots taken from a LG Velvet with Android 10):

Here's the code for the Train tab, where the Unity widget currently is:

Widget build(BuildContext context) {
    final TabsModel model = Provider.of<TabsModel>(context);

    print("model game to load on train tab " + model.gameToLoad.toString());

    return Stack(
      fit: StackFit.expand,
      children: [
        UnityWidget(
          onUnityMessage: onUnityMessage,
          onUnitySceneLoaded: onUnitySceneLoaded,
          onUnityCreated: onUnityCreated,
          fullscreen: false,
          onUnityUnloaded: () {
            print("unloaded");
          },
        ),
        if (model.gameToLoad.isEmpty)
          Positioned.fill(
            child: AnimatedOpacity(
              duration: Duration(milliseconds: 500),
              opacity: model.gameToLoad.isEmpty ? 1 : 0,
              child: Container(
                color: Theme.of(context).backgroundColor,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    Padding(
                      padding: const EdgeInsets.all(48.0),
                      child: CustomPrimaryButton(
                          onPressed: model.gameToLoad.isEmpty
                              ? () => loadGame(
                                    gameToLoad: 'SoundSeeker',
                                    model: model,
                                  )
                              : null,
                          label: 'Play sound seeker'),
                    ),
                    Padding(
                      padding: const EdgeInsets.all(48.0),
                      child: CustomPrimaryButton(
                          onPressed: model.gameToLoad.isEmpty
                              ? () => loadGame(
                                    gameToLoad: 'BusyBarista',
                                    model: model,
                                  )
                              : null,
                          label: 'Play busy barista'),
                    ),
                  ],
                ),
              ),
            ),
          ),
      ],
    );
  }

I can also provide some code for the tabs structure if needed.

cmd-dev commented 3 years ago

I am having the same issue. Even Navigator.push and Navigator.pop is not working, plus unityController.quit(silent:true) crashes the app

juicycleff commented 3 years ago

Please unityController.quit(silent:true) is deprecated and you should run flutter clean

thassio-vinicius commented 3 years ago

@juicycleff any suggestions about my issue? I'm still experiencing it

nmfisher commented 3 years ago

@thassio-vinicius I wonder if you're encountering an issue similar to the one I was dealing with:

https://github.com/juicycleff/flutter-unity-view-widget/issues/190#issuecomment-799506016

In short, on my Android 8 device, the Unity widget was rendering on top of every Flutter widget (with transparency correctly set), or below every Flutter widget that was higher in the stack (with no transparency to show widgets beneath).

This was solved by calling setZOrderOnTop(false) on the SurfaceView from the UnityPlayer, but then the "transparency" in the Unity widget was only showing the first frame of the widget tree from when the Unity widget was rendered (so if I changed the background when the Unity widget was visible, the background wouldn't update).

Many people have indicated that, in the regular Android rendering pipeline, a SurfaceView can only sit at the top of the View hierarchy or at the bottom. I suspect Flutter subverts this by compositing everything in the View hierachy directly to its own texture, but this may not work 100% (hence the issues I was experiencing, and possibly the issue you are experiencing).

You may want to try following what I did in the above issue to try and render the Unity transparency correctly. I don't have an Android 9/10 device to correctly test this, though.

thassio-vinicius commented 3 years ago

@nmfisher I've followed your tutorial step by step and the only thing that kind of worked was forcing Unity to render a TextureView instead of a SurfaceView. Unfortunately, I think this solution doesn't meet our business logic, which has multiple different scenes and the ability to quit the current game (by returning to the initial scene and having Flutter listening to that change using the API to display the correct widget on top of the stack).

The app's inicial state seems to work just fine, but once I click in one of the games, the Unity Widget goes to the foreground as expected, but it shrinks down to about 70% of it's actual size (because of the bottom and top bars maybe?), even though I'm able to interact with the in-game buttons like they were in their regular positions. When I try to quit a game, though, the Flutter UI never reappears and I can only see that loading animation (the initial Unity Scene). Apparently, this solution is only working for when you don't need to switch scenes or toggle between Flutter and Unity UI. Nonetheless, thank you so much for your time and for your assistance with this issue. I hope we can get a fix for this as soon as possible. For now, I think the only option is to target Android 10 devices and newer versions

NOTE: The Unity version I've used is 2019.4.14f1. Not sure if 2020.1 and 2021.1 are strictly necessary for your solution to work properly

hoongtong commented 3 years ago

@thassio-vinicius We encountered the same issue when developing our app, I was wondering if you found another solution for Android 9 or under instead of using a TextureView. @juicycleff Will there perhaps be an official fix for this issue?

MaxymShtoyko commented 3 years ago

@hoongtong @juicycleff @nmfisher did you manage to find any solutions?

thassio-vinicius commented 3 years ago

@thassio-vinicius We encountered the same issue when developing our app, I was wondering if you found another solution for Android 9 or under instead of using a TextureView. @juicycleff Will there perhaps be an official fix for this issue?

I haven’t found any solution for this yet, but I did find out that the problem isn’t restricted to android 9 only, older android versions seem to suffer from the very same problem. So far I can confirm that android 7 and 8 are on the list. Until we get an official fix for this, the only thing left to do is set your minimum sdk to level 29 (android 10)

juicycleff commented 3 years ago

@thassio-vinicius I'm sorry for being silent on this, I can't get my hands on a device to try it out. But just to be certain, please make sure your unity dependencies does not require older Android device

thassio-vinicius commented 3 years ago

@thassio-vinicius I'm sorry for being silent on this, I can't get my hands on a device to try it out. But just to be certain, please make sure your unity dependencies does not require older Android device

@juicycleff are you talking about minimum API level on Player Settings? If so, mine is set to 23 (android 6.0) but I'll be updating that to API 29 (android 10) once my company's product is ready to be released.