react-native-unity icon indicating copy to clipboard operation
react-native-unity copied to clipboard

Early iOS messages (from Unity to React Native) got dropped

Open Luluno01 opened this issue 2 years ago • 4 comments

When reentered Unity view for the second time, some messages sent from Unity a few milliseconds after mounted was dropped and were not passed to onMessage callback. Any workaround/fix that can avoid implementing a TCP-like protocol?

Luluno01 avatar Jul 20 '23 12:07 Luluno01

For Android I used pauseUnity and resumeUnity to make sure Unity only runs when the RN side is ready to handle the messages. For iOS, remounting Unity view automatically reloads the scene immediately even it was paused last time, and there is a small window for Unity to render a few frames and send some messages before it is paused again. The message sent within that window was dropped (onUnityMessage was not called at all). In fact, pausing before unmount and resuming after remount do not seem to work on iOS -- Unity view paused after rendering a few frames when remounted and was never able to be resumed by resumeUnity. After removing the pause-and-resume calls on iOS, it does render properly after resumed, but the window where early message is dropped still exists.

Luluno01 avatar Jul 20 '23 16:07 Luluno01

Hi, I think that sending the message just as the Unity component mounts (in the useEffect) might be a little bit to fast. I built the project directly in xcode and was able to notice an error message in the console saying "SendMessage: object someObject not found! ". My solution was firstly sending some initial message from the root gameObject's start function to RN, saying 'scene initialized' and than responding to this exact message in RN by sending back the necessary payload.

In my case, I am sending a video URL and not seeing any delay at all actually. I guess the 'Made with Unity' welcome screen compensates that time so that the next screen is already the video playing.

Hope it helps :)

stachbial avatar Oct 02 '23 16:10 stachbial

Hi, I think that sending the message just as the Unity component mounts (in the useEffect) might be a little bit to fast. I built the project directly in xcode and was able to notice an error message in the console saying "SendMessage: object someObject not found! ". My solution was firstly sending some initial message from the root gameObject's start function to RN, saying 'scene initialized' and than responding to this exact message in RN by sending back the necessary payload.

In my case, I am sending a video URL and not seeing any delay at all actually. I guess the 'Made with Unity' welcome screen compensates that time so that the next screen is already the video playing.

Hope it helps :)

Thanks for sharing a thought here. Yeah, that's what I am doing right now -- a custom protocol between Unity and RN where the handshake is initiated from Unity side and acknowledged by RN. While this approach works, it feels more like something that should be done from a lower level. Take network protocols as an example, this should be a job of transport layer protocols instead of application layer protocols.

Another concern is that if Unity is not guaranteed to receive some initial messages from RN, the same should be applied to the other direction. For example, when the phone is running low of RAM or for whatever reason the JS thread gets blocked, and therefore, Unity finishes initialization before the JS part on the RN side. In that case, RN will miss messages from Unity due to onMessage being undefined upon emitting those messages. This imaginary case may sound unlikely to happen, but when you realize that Unity does receive early messages from RN on Android, you should also realize that you shouldn't assume either side of RN or Unity always finishes initialization first. For this reason, I implemented elementary acknowledgement-retransmission in my custom protocol, which works great so far.

Ideally, I would expect a ready event emitted by react-native-unity without polluting the game logic, while a ready state is also available in case the RN side misses the ready event for whatever reason. But anyway, I am happy with current workaround as it seems to be the cheapest at the moment and it works.

Luluno01 avatar Oct 03 '23 09:10 Luluno01

Hi, I think that sending the message just as the Unity component mounts (in the useEffect) might be a little bit to fast. I built the project directly in xcode and was able to notice an error message in the console saying "SendMessage: object someObject not found! ". My solution was firstly sending some initial message from the root gameObject's start function to RN, saying 'scene initialized' and than responding to this exact message in RN by sending back the necessary payload. In my case, I am sending a video URL and not seeing any delay at all actually. I guess the 'Made with Unity' welcome screen compensates that time so that the next screen is already the video playing. Hope it helps :)

Thanks for sharing a thought here. Yeah, that's what I am doing right now -- a custom protocol between Unity and RN where the handshake is initiated from Unity side and acknowledged by RN. While this approach works, it feels more like something that should be done from a lower level. Take network protocols as an example, this should be a job of transport layer protocols instead of application layer protocols.

Another concern is that if Unity is not guaranteed to receive some initial messages from RN, the same should be applied to the other direction. For example, when the phone is running low of RAM or for whatever reason the JS thread gets blocked, and therefore, Unity finishes initialization before the JS part on the RN side. In that case, RN will miss messages from Unity due to onMessage being undefined upon emitting those messages. This imaginary case may sound unlikely to happen, but when you realize that Unity does receive early messages from RN on Android, you should also realize that you shouldn't assume either side of RN or Unity always finishes initialisation first. For this reason, I implemented elementary acknowledgement-retransmission in my custom protocol, which works great so far.

Ideally, I would expect a ready event emitted by react-native-unity without polluting the game logic, while a ready state is also available in case the RN side misses the ready event for whatever reason. But anyway, I am happy with current workaround as it seems to be the cheapest at the moment and it works.

Thanks for the answer. I agree with your thoughts in 100 percent. While this communication pipeline makes perfect sense in case of interacting with some game objects which require the whole process and the scene to be initialised independenty of the JS thread, its terrible for sending some initial parameters such as i.e. choosing which scene to render based on whats happening in RN. In the matter of fact, I suppose that this problem is not really react-native related, but rather about initialising the Unity part as an embedded view in general. I guess that, in the perfect scenario, the unity part of the app should use some loader files that could be accessed from the native app part as well. Considering the cons of the new architecture, exposing it for react native to be accessed 'in real time' would then be just a formality I hope.

stachbial avatar Oct 18 '23 19:10 stachbial