After calling the unload method, black screen is shown on android
Opened this issue · 11 comments
Hello!
Thanks for maintaining this library!
I have noticed this kind of behavior on android:
Open example app > Open screen with unity scene > Unload & Go back > Open screen with unity scene again > Unity scene is black.
Video demo:
DouWan_20221219_143743.mp4
Relevant files:
MacOS: 13.01
The example project is taken from @azesmway's zip file, exported from unity by him, in other issues' comment sections in this repository but this issue happens of project in this repository too.
Does anyone have any idea if the fix for this issue exists?
Same issue, but no need to unloadUnity
, just destroying and recreating the component (through navigation) simply lead to blank screen (white screen in my case). I was suspecting if I should manually clean up the old unity
stuff so I tried calling unloadUnity
before unmount, but it leads to null pointer dereference in vk::CommandBuffer::BindVertexBuffers
in libunity.so
...
Another information I would to offer is that both onPlayerQuit
and onPlayerUnload
did not get fired. Not sure if they are related...
Update: previously I was calling unloadUnity
in the clean up code of useEffect
, so onPlayerUnload
did not fire. After moving the call to outside onPlayerUnload
did work, but it's still a blank screen after getting back to the screen containing UnityView
.
To be precise, I get another null pointer dereference exception when letting UnityView destroy itself:
01-09 18:55:11.321 4485 4485 I SurfaceView: onWindowVisibilityChanged(8) false android.view.SurfaceView{dbf0a7d VFE...... ......ID 0,0-1080,2005 #7f090163 app:id/unitySurfaceView} of ViewRootImpl@cdd1dd5[MainActivity]
01-09 18:55:11.322 4485 4485 I SurfaceView: surfaceDestroyed callback.size 1 #2 android.view.SurfaceView{dbf0a7d VFE...... ......ID 0,0-1080,2005 #7f090163 app:id/unitySurfaceView}
01-09 18:55:11.322 4485 4485 D Unity : PersistentUnitySurface.preserveContent: android.view.SurfaceView{dbf0a7d VFE...... ......ID 0,0-1080,2005 #7f090163 app:id/unitySurfaceView}
01-09 18:55:11.323 4485 4485 D Unity : PersistentUnitySurface.PlaceholderView.Copy: android.view.SurfaceView{dbf0a7d VFE...... ......ID 0,0-1080,2005 #7f090163 app:id/unitySurfaceView}
01-09 18:55:11.352 4485 7315 D Unity : SetWindow 0 0x0
01-09 18:55:11.352 4485 7353 W tamory.petamor: 0xebadde09 skipped times: 0
01-09 18:55:11.353 4485 7353 E CRASH : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
01-09 18:55:11.353 4485 7353 E CRASH : Version '2021.3.16f1 (4016570cf34f)', Build type 'Development', Scripting Backend 'il2cpp', CPU 'arm64-v8a'
01-09 18:55:11.353 4485 7353 E CRASH : Build fingerprint: 'samsung/star2qltezh/star2qltechn:10/QP1A.190711.020/G9650ZHU9FUE3:user/release-keys'
01-09 18:55:11.353 4485 7353 E CRASH : Revision: '14'
01-09 18:55:11.353 4485 7353 E CRASH : ABI: 'arm64'
01-09 18:55:11.353 4485 7353 E CRASH : Timestamp: 2023-01-09 18:55:11+0800
01-09 18:55:11.353 4485 7353 E CRASH : pid: 4485, tid: 7353, name: Thread-81 >>> com.example <<<
01-09 18:55:11.353 4485 7353 E CRASH : uid: 10250
01-09 18:55:11.353 4485 7353 E CRASH : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xb9
01-09 18:55:11.353 4485 7353 E CRASH : Cause: null pointer dereference
01-09 18:55:11.353 4485 7353 E CRASH : x0 0000000000000000 x1 0000007510cecba0 x2 00000074965c1380 x3 0000000000000000
01-09 18:55:11.353 4485 7353 E CRASH : x4 0000007510cecba0 x5 00000007fe7861cc x6 0000000000000000 x7 0000000000000005
01-09 18:55:11.354 4485 7353 E CRASH : x8 0000000000000000 x9 00000074b367c3dc x10 00000000ffffffff x11 0000007510cecbf0
01-09 18:55:11.354 4485 7353 E CRASH : x12 0000007510cecba0 x13 0000000000000000 x14 0000000000000000 x15 0000007510cecbe0
01-09 18:55:11.354 4485 7353 E CRASH : x16 0000000000000000 x17 00000074965c1380 x18 0000006a344bc000 x19 0000000000000001
01-09 18:55:11.354 4485 7353 E CRASH : x20 0000000000000001 x21 0000006a90bc9780 x22 0000006a90bd0c30 x23 0000006a90bda380
01-09 18:55:11.354 4485 7353 E CRASH : x24 0000000000000001 x25 0000006a90bd0c30 x26 0000006a90bda380 x27 0000006b7b7fc020
01-09 18:55:11.354 4485 7353 E CRASH : x28 0000006a200000c0 x29 0000006b7b7fbba0
01-09 18:55:11.354 4485 7353 E CRASH : sp 0000006b7b7fb880 lr 0000006b4ec8a334 pc 0000006b4ec8a34c
01-09 18:55:11.354 4485 7353 E CRASH :
01-09 18:55:11.354 4485 7353 E CRASH : backtrace:
01-09 18:55:11.354 4485 7353 E CRASH : #00 pc 000000000088534c /data/app/com.example-P4RgAXnLb3uA7t88jr3TVg==/lib/arm64/libunity.so (GfxDeviceVKBase::EnsureCurrentCommandBuffer(vk::CommandBuffer::Type, bool)+340) (BuildId: 9f7c3d6ea46a437a3f214a16d511bbb3bf2131fa)
01-09 18:55:11.354 4485 7353 E CRASH : #01 pc 0000000000880b3c /data/app/com.example-P4RgAXnLb3uA7t88jr3TVg==/lib/arm64/libunity.so (GfxDeviceVK::ClearImpl(GfxClearFlags, ColorRGBAf const*, int, unsigned int, float, unsigned int)+368) (BuildId: 9f7c3d6ea46a437a3f214a16d511bbb3bf2131fa)
01-09 18:55:11.354 4485 7353 E CRASH : #02 pc 000000000095c6a4 /data/app/com.example-P4RgAXnLb3uA7t88jr3TVg==/lib/arm64/libunity.so (GfxDeviceWorker::RunCommand(ThreadedStreamBuffer&)+2240) (BuildId: 9f7c3d6ea46a437a3f214a16d511bbb3bf2131fa)
01-09 18:55:11.354 4485 7353 E CRASH : #03 pc 0000000000963d74 /data/app/com.example-P4RgAXnLb3uA7t88jr3TVg==/lib/arm64/libunity.so (GfxDeviceWorker::RunExt(ThreadedStreamBuffer&)+44) (BuildId: 9f7c3d6ea46a437a3f214a16d511bbb3bf2131fa)
01-09 18:55:11.354 4485 7353 E CRASH : #04 pc 0000000000963d3c /data/app/com.example-P4RgAXnLb3uA7t88jr3TVg==/lib/arm64/libunity.so (GfxDeviceWorker::Run()+140) (BuildId: 9f7c3d6ea46a437a3f214a16d511bbb3bf2131fa)
01-09 18:55:11.354 4485 7353 E CRASH : #05 pc 000000000095bbcc /data/app/com.example-P4RgAXnLb3uA7t88jr3TVg==/lib/arm64/libunity.so (GfxDeviceWorker::RunGfxDeviceWorker(void*)+4) (BuildId: 9f7c3d6ea46a437a3f214a16d511bbb3bf2131fa)
01-09 18:55:11.354 4485 7353 E CRASH : #06 pc 000000000036ab18 /data/app/com.example-P4RgAXnLb3uA7t88jr3TVg==/lib/arm64/libunity.so (Thread::RunThreadWrapper(void*)+796) (BuildId: 9f7c3d6ea46a437a3f214a16d511bbb3bf2131fa)
01-09 18:55:11.354 4485 7353 E CRASH : #07 pc 00000000000e6f20 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+36) (BuildId: d00c50b4798c95f2447d684ed3ea7dcb)
01-09 18:55:11.354 4485 7353 E CRASH : #08 pc 00000000000850c8 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: d00c50b4798c95f2447d684ed3ea7dcb)
01-09 18:55:11.365 4485 7364 I SwappyDisplayManager: Terminating looper thread
01-09 18:55:11.369 4485 4485 I SurfaceView: remove() android.view.SurfaceView{dbf0a7d VFE...... ......ID 0,0-1080,2005 #7f090163 app:id/unitySurfaceView} Surface(name=SurfaceView - com.example/com.example.MainActivity@dbf0a7d@0)/@0xad431a3
01-09 18:55:11.372 4485 4485 I SurfaceView: onWindowVisibilityChanged(0) true android.view.SurfaceView{dbf0a7d VFE...... ......ID 0,0-1080,2005 #7f090163 app:id/unitySurfaceView} of ViewRootImpl@cdd1dd5[MainActivity]
01-09 18:55:11.387 861 861 I SurfaceFlinger: DEVICE | 0x7c28c51af0 | 0000 | RGBA_8888 | 0.0 0.0 1080.0 2220.0 | 0 0 1080 2220 | com.example/com.example.MainActivity$_4485#0
01-09 18:55:11.396 1625 2800 V WindowManager: Relayout 4485: mAttrs={(0,0)(fillxfill) sim={adjust=resize} layoutInDisplayCutoutMode=always ty=BASE_APPLICATION fmt=RGBA_8888 wanim=0x1030305 preferredDisplayMode=1 sysuil=true
01-09 18:55:11.399 4485 4485 I ViewRootImpl@cdd1dd5[MainActivity]: Relayout returned: old=(0,0,1080,2220) new=(0,0,1080,2220) req=(1080,2220)0 dur=8 res=0x1 s={true 501223137280} ch=false
01-09 18:55:11.406 4485 4485 I SurfaceView: surfaceCreated 1 #8 android.view.SurfaceView{dbf0a7d VFE...... ......ID 0,0-1,1 #7f090163 app:id/unitySurfaceView}
01-09 18:55:11.407 4485 7315 D Unity : SetWindow 0 0x7495e03010
01-09 18:55:11.407 4485 7315 D Unity : AndroidDisplayManagerVulkan::AttachWindow(0x7495e03010, 0)
+1
I added a loading indicator and wait for 1 second each time I come to my unityView screen.
{loading ? (
<Loader color={colors.primary} />
) : (
<UnityView
ref={unityRef}
style={{flex: 1}}
onUnityMessage={result => {
console.log('onUnityMessage:', result.nativeEvent.message);
}}
/>
)}
added useEffect focus
function of navigation and in that function I made loading true and after one second I made it false and then I can see the unityView instead of black/white screen.
@aawolf1099 Sounds interesting. Would you mind sharing more details about the "useEffect focus
function"? Did you mean useFocusEffect
?
Okay I found the focus
event. I set loading
to true
inside the listener, and then back to false
1 second later. It is no longer a white screen, but the FPS drops significantly when it is back. Another issue is that it is keeps running in the background because the window is still focused. Attempting to manually pauseUnity
on blur
and resumeUnity
on focus
leads to black screen (not white, though).
Okay I tried set loading
to false in blur
event handler and it does pause Unity.
After looking into the source code, I found androidKeepPlayerMounted
is another workaround. It keeps the player mounted so that we can manually pauseUnity
on blur and resumeUnity
on focus. It does not lead to any null pointer dereference or segment fault because the lifecycle is simpler in this case.
while using androidKeepPlayerMounted
, I have been experiencing issues while using react-native-navigation's navigate.reset()
when it includes a path that contains unity. #62 has been my issue so far, I am wondering if anyone here has ran into a similar issue or has fixed the problem for their project.
After looking into the source code, I found
androidKeepPlayerMounted
is another workaround. It keeps the player mounted so that we can manuallypauseUnity
on blur andresumeUnity
on focus. It does not lead to any null pointer dereference or segment fault because the lifecycle is simpler in this case.
Thanks for finding this! It was very helpful. I ended up using the androidKeepPlayerMounted
option and useFocusEffect
with pauseUnity
on blur and resumeUnity
on focus and it worked like a charm.
Considering the naming of the option, any Idea if this would work on IOS? I plan on testing it but figured I'd ask first to determine if there was another method for IOS or whether it'd be tested yet.
It seems on iOS the Unity instance is kept alive in the background already (not sure if it is "mounted" or not).
@Luluno01 Thank you. That's good to know concerning iOS.
Although the Android mounting method works great, my use case necessitates that I completely restart my game when a new user logs in. As such, I tried using the unload method along with the delay that @aawolf1099 mentions, but it leaves the game in an undesirable state and trying to rerender the game again crashes the app.
@Luluno01 Thank you. That's good to know concerning iOS.
Although the Android mounting method works great, my use case necessitates that I completely restart my game when a new user logs in. As such, I tried using the unload method along with the delay that @aawolf1099 mentions, but it leaves the game in an undesirable state and trying to rerender the game again crashes the app.
This is perfectly legit requirement. Unfortunately, it seems Unity doesn't implement any interface to restart itself on Android. My current approach is to unload everything from within the game and reload the scene, which helps a bit, but if you are using some Unity plugins or features that touch native code or native resources, it might be insufficient to just reload the scene.
Considering how unstable it is to embed Unity view into React Native, I start to think if not embedding it directly is a better idea. On Android, it is easy to do so. You just add android:process=":unity"
to UnityPlayerActivity
and use an intent to start a separate Unity activity (communication between React Native and Unity will be another problem). It is then easy to restart the Unity process without killing the entire app. On iOS, however, I haven't found a similar solution where you can start a new task window that runs in a separate process but still belongs to the same app.
Actually I just found another workaround. I found that when there is a black screen, if I send the app to the background and then switch back, it starts to render properly. So, I made some changes (#78) to the binding to expose UnityPlayer.windowFocusChanged
, which is invoked under the hood when the app is sending to the background and bringing to the foreground, and it does get the view out of black screen.