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.09k stars 504 forks source link

Android crash - no non-static method CustomUnityPlayer;.hidePreservedContent() #926

Closed timbotimbo closed 1 week ago

timbotimbo commented 4 months ago

Description

This bug was first described in a larger issue #903, I'm just splitting it into a separate issue specific to this error.

On some Unity versions, android devices on Android 8 or lower will immediately crash when Unity is started.
(See more logs at the bottom)

java.lang.NoSuchMethodError: no non-static method "Lcom/xraph/plugin/flutter_unity_widget/CustomUnityPlayer;.hidePreservedContent()V"

Breaking change

I tested multiple Unity versions to find the exact version that breaks this.

The crash starts at Unity 2021.3.31 and 2022.3.10.
Both these versions have this entry in the changelog, that seems like the culprit.

  • Android: Show the last rendered frame when the application come back from the pause state. (UUM-30881)

Reproduction

  1. Build and run any project using this plugin, like the example.
  2. Click through the app until Unity launches in Flutter app.
  3. On Android <= 8 and the specified Unity versions, it will instantly crash.

Possible workaround

As noted in the original issue #903:

Adding the missing function signature to CustomUntityPlayer.kt in the plugin prevents the crash.

class CustomUnityPlayer(context: Activity, upl: IUnityPlayerLifecycleEvents?) : UnityPlayer(context, upl) {

+     // define a function with the correct name
+    fun hidePreservedContent() {
+        // do nothing here for now
+    }    

}

However this causes the last paused frame to show when closing and reopening a page with the unitywidget.

Trying to call something like super.hidePreservedContent results in

Cannot access 'hidePreservedContent': it is private in 'UnityPlayer'

So we might be able to call this private function using reflection.

Versions

❌ indicates a crash.

Unity: 2021.3.21 ✔
2021.3.28 ✔
2021.3.30 ✔
2021.3.31 ❌ 2021.3.34 ❌
2021.3.35 ❌
2021.3.36 ❌
2021.3.39 ❌

2022.3.0 ✔
2022.3.9 ✔
2022.3.10 ❌
2022.3.14 ❌ 2022.3.15 ❌ 2022.3.18 ❌ 2022.3.19 ✔ 2022.3.20 ✔

Android: Android 6 ❌
Android 7.1.2 ❌
Android 8 ❌ (reported) Android 9 ✔ Android 13 ✔

Devices: This seems to happen on any device on Android <= 8.

Logs

Log Unity 2021.3.31, Android 6 ``` E/AndroidRuntime( 8176): FATAL EXCEPTION: UnityMain E/AndroidRuntime( 8176): Process: com.xraph.plugin.flutter_unity_widget_example, PID: 8176 E/AndroidRuntime( 8176): java.lang.Error: FATAL EXCEPTION [UnityMain] E/AndroidRuntime( 8176): Unity version : 2021.3.31f1 E/AndroidRuntime( 8176): Device model : Wileyfox Wileyfox Swift E/AndroidRuntime( 8176): Device fingerprint: Wileyfox/Swift/crackling:7.1.2/N2G48B/eeea277114:user/release-keys E/AndroidRuntime( 8176): Build Type : Release E/AndroidRuntime( 8176): Scripting Backend : IL2CPP E/AndroidRuntime( 8176): ABI : arm64-v8a E/AndroidRuntime( 8176): Strip Engine Code : true E/AndroidRuntime( 8176): E/AndroidRuntime( 8176): Caused by: java.lang.NoSuchMethodError: no non-static method "Lcom/xraph/plugin/flutter_unity_widget/CustomUnityPlayer;.hidePreservedContent()V" E/AndroidRuntime( 8176): at com.unity3d.player.UnityPlayer.nativeRender(Native Method) E/AndroidRuntime( 8176): at com.unity3d.player.UnityPlayer.access$500(Unknown Source) E/AndroidRuntime( 8176): at com.unity3d.player.UnityPlayer$e$1.handleMessage(Unknown Source) E/AndroidRuntime( 8176): at android.os.Handler.dispatchMessage(Handler.java:98) ```
Log Unity 2022.3.10, Android 7 ``` E/AndroidRuntime(10917): FATAL EXCEPTION: UnityMain E/AndroidRuntime(10917): Process: com.xraph.plugin.flutter_unity_widget_example, PID: 10917 E/AndroidRuntime(10917): java.lang.Error: FATAL EXCEPTION [UnityMain] E/AndroidRuntime(10917): Unity version : 2022.3.10f1 E/AndroidRuntime(10917): Device model : Wileyfox Wileyfox Swift E/AndroidRuntime(10917): Device fingerprint: Wileyfox/Swift/crackling:7.1.2/N2G48B/eeea277114:user/release-keys E/AndroidRuntime(10917): CPU supported ABI : [arm64-v8a, armeabi-v7a, armeabi] E/AndroidRuntime(10917): Build Type : Release E/AndroidRuntime(10917): Scripting Backend : IL2CPP E/AndroidRuntime(10917): Libs loaded from : lib/arm64 E/AndroidRuntime(10917): Strip Engine Code : true E/AndroidRuntime(10917): E/AndroidRuntime(10917): Caused by: java.lang.NoSuchMethodError: no non-static method "Lcom/xraph/plugin/flutter_unity_widget/CustomUnityPlayer;.hidePreservedContent()V" E/AndroidRuntime(10917): at com.unity3d.player.UnityPlayer.nativeRender(Native Method) E/AndroidRuntime(10917): at com.unity3d.player.UnityPlayer.-$$Nest$mnativeRender(Unknown Source) E/AndroidRuntime(10917): at com.unity3d.player.UnityPlayer$D$a.handleMessage(Unknown Source) E/AndroidRuntime(10917): at android.os.Handler.dispatchMessage(Handler.java:98) E/AndroidRuntime(10917): at android.os.Looper.loop(Looper.java:154) E/AndroidRuntime(10917): at com.unity3d.player.UnityPlayer$D.run(Unknown Source) ```
timbotimbo commented 4 months ago

I just noticed that the 'workaround' caused a bug that Unity won't stop showing away the last paused frame, even on Android 13. This confirms that the Show the last rendered frame when the application come back from the pause state fix is the cause.

I have updated the issue above.

timbotimbo commented 4 months ago

Using reflection seem to fix it. (tested on Android 7 and 13).

// CustomUnityplayer.kt
import java.lang.reflect.Method

     // Unity 2021.3.31+ and 2022.3.10+ try to call this private function, which throws an error on Android <= 8. https://github.com/juicycleff/flutter-unity-view-widget/issues/926
     fun hidePreservedContent() {
        Log.i(LOG_TAG, "hidePreservedContent")

        // manually call the private function using reflection.
        UnityPlayer::class.java.declaredMethods
        .find { it.name == "hidePreservedContent" }
        ?.let {
            it.isAccessible = true
            it.invoke(this)
        }

     }

https://github.com/timbotimbo/flutter-unity-view-widget/tree/hide_preserved_content

timbotimbo commented 4 months ago

Looks like this is 'fixed' in Unity starting with 2022.3.19.
There are however no changes the the changelog that explain it.

timbotimbo commented 1 week ago

Closing this as it is fixed for Unity 2022.3 and likely won't ever get fixed for 2021.3. Anyone running into this error should update to a recent Unity 2022.3 version.