@dolami-inc/react-native-expo-unity 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -33,17 +33,13 @@ class ExpoUnityView(context: Context, appContext: AppContext) : ExpoView(context
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
if (bridge.
|
|
37
|
-
// Unity already
|
|
38
|
-
bridge.
|
|
39
|
-
Log.i(TAG, "Unity already ready, reparented view")
|
|
36
|
+
if (bridge.isInitialized) {
|
|
37
|
+
// Unity already created — attach the view to this container
|
|
38
|
+
bridge.attachToContainer(this)
|
|
40
39
|
} else {
|
|
41
|
-
//
|
|
40
|
+
// Create Unity player, then attach the view once ready
|
|
42
41
|
bridge.initialize(activity) {
|
|
43
|
-
|
|
44
|
-
bridge.addUnityViewToGroup(this)
|
|
45
|
-
Log.i(TAG, "Unity ready, view reparented into container")
|
|
46
|
-
}
|
|
42
|
+
bridge.attachToContainer(this)
|
|
47
43
|
}
|
|
48
44
|
}
|
|
49
45
|
}
|
|
@@ -51,7 +47,7 @@ class ExpoUnityView(context: Context, appContext: AppContext) : ExpoView(context
|
|
|
51
47
|
override fun onWindowFocusChanged(hasWindowFocus: Boolean) {
|
|
52
48
|
super.onWindowFocusChanged(hasWindowFocus)
|
|
53
49
|
val bridge = UnityBridge.getInstance()
|
|
54
|
-
if (!bridge.
|
|
50
|
+
if (!bridge.isInitialized) return
|
|
55
51
|
bridge.unityPlayer?.windowFocusChanged(hasWindowFocus)
|
|
56
52
|
}
|
|
57
53
|
|
|
@@ -61,13 +57,12 @@ class ExpoUnityView(context: Context, appContext: AppContext) : ExpoView(context
|
|
|
61
57
|
|
|
62
58
|
if (bridge.isInitialized) {
|
|
63
59
|
if (autoUnloadOnUnmount) {
|
|
60
|
+
bridge.detachFromContainer()
|
|
64
61
|
bridge.unload()
|
|
65
|
-
Log.i(TAG, "
|
|
62
|
+
Log.i(TAG, "Detached and unloaded (view detached)")
|
|
66
63
|
} else {
|
|
67
|
-
// Park Unity in the background instead of unloading
|
|
68
|
-
bridge.parkUnityViewInBackground()
|
|
69
64
|
bridge.setPaused(true)
|
|
70
|
-
Log.i(TAG, "
|
|
65
|
+
Log.i(TAG, "Paused (autoUnloadOnUnmount=false)")
|
|
71
66
|
}
|
|
72
67
|
}
|
|
73
68
|
|
|
@@ -18,10 +18,9 @@ import com.unity3d.player.UnityPlayerForActivityOrService
|
|
|
18
18
|
* Singleton managing the UnityPlayer lifecycle.
|
|
19
19
|
* Android equivalent of ios/UnityBridge.mm.
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* into that view. When it unmounts, we park it back in the background.
|
|
21
|
+
* Creates the Unity player and lets the ExpoUnityView add the
|
|
22
|
+
* FrameLayout directly — no background parking, since Unity 6's
|
|
23
|
+
* window management times out when reparenting from a background view.
|
|
25
24
|
*/
|
|
26
25
|
class UnityBridge private constructor() : IUnityPlayerLifecycleEvents, NativeCallProxy.MessageListener {
|
|
27
26
|
|
|
@@ -49,9 +48,6 @@ class UnityBridge private constructor() : IUnityPlayerLifecycleEvents, NativeCal
|
|
|
49
48
|
/** Tracked here (not on the Module) so it survives module recreation. */
|
|
50
49
|
var wasRunningBeforeBackground: Boolean = false
|
|
51
50
|
|
|
52
|
-
var isReady: Boolean = false
|
|
53
|
-
private set
|
|
54
|
-
|
|
55
51
|
val isInitialized: Boolean
|
|
56
52
|
get() = unityPlayer != null
|
|
57
53
|
|
|
@@ -62,6 +58,10 @@ class UnityBridge private constructor() : IUnityPlayerLifecycleEvents, NativeCal
|
|
|
62
58
|
val unityPlayerView: FrameLayout?
|
|
63
59
|
get() = unityPlayer?.frameLayout
|
|
64
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Creates the UnityPlayer. The caller is responsible for adding
|
|
63
|
+
* [unityPlayerView] to the view hierarchy immediately after [onReady] fires.
|
|
64
|
+
*/
|
|
65
65
|
fun initialize(activity: Activity, onReady: (() -> Unit)? = null) {
|
|
66
66
|
if (isInitialized) {
|
|
67
67
|
onReady?.invoke()
|
|
@@ -83,26 +83,12 @@ class UnityBridge private constructor() : IUnityPlayerLifecycleEvents, NativeCal
|
|
|
83
83
|
NativeCallProxy.registerListener(this)
|
|
84
84
|
Log.i(TAG, "Unity player created")
|
|
85
85
|
|
|
86
|
-
// Give Unity time to initialize its rendering pipeline
|
|
87
|
-
Thread.sleep(1000)
|
|
88
|
-
|
|
89
|
-
// Park the Unity view in the background (1x1px, behind everything)
|
|
90
|
-
addUnityViewToBackground(activity)
|
|
91
|
-
|
|
92
|
-
// Kick-start rendering
|
|
93
|
-
player.windowFocusChanged(true)
|
|
94
|
-
player.frameLayout?.requestFocus()
|
|
95
|
-
player.resume()
|
|
96
|
-
|
|
97
86
|
// Restore fullscreen state if Unity changed it
|
|
98
87
|
if (!wasFullScreen) {
|
|
99
88
|
activity.window.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN)
|
|
100
89
|
activity.window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
|
101
90
|
}
|
|
102
91
|
|
|
103
|
-
isReady = true
|
|
104
|
-
Log.i(TAG, "Unity initialized and ready")
|
|
105
|
-
|
|
106
92
|
onReady?.invoke()
|
|
107
93
|
} catch (e: Exception) {
|
|
108
94
|
Log.e(TAG, "Failed to initialize Unity", e)
|
|
@@ -117,67 +103,42 @@ class UnityBridge private constructor() : IUnityPlayerLifecycleEvents, NativeCal
|
|
|
117
103
|
}
|
|
118
104
|
|
|
119
105
|
/**
|
|
120
|
-
*
|
|
121
|
-
*
|
|
106
|
+
* Adds the Unity FrameLayout to the given container and starts rendering.
|
|
107
|
+
* Must be called after [initialize] completes.
|
|
122
108
|
*/
|
|
123
|
-
|
|
124
|
-
val frame = unityPlayerView ?:
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
(frame.parent as? ViewGroup)?.let { parent ->
|
|
128
|
-
parent.endViewTransition(frame)
|
|
129
|
-
parent.removeView(frame)
|
|
109
|
+
fun attachToContainer(container: ViewGroup) {
|
|
110
|
+
val frame = unityPlayerView ?: run {
|
|
111
|
+
Log.w(TAG, "Unity player view not available")
|
|
112
|
+
return
|
|
130
113
|
}
|
|
131
114
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
val layoutParams = ViewGroup.LayoutParams(1, 1)
|
|
135
|
-
activity.addContentView(frame, layoutParams)
|
|
136
|
-
Log.i(TAG, "Unity view parked in background")
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Moves the Unity view from wherever it currently is into the
|
|
141
|
-
* specified ViewGroup with MATCH_PARENT layout. Called when the
|
|
142
|
-
* React Native component mounts.
|
|
143
|
-
*/
|
|
144
|
-
fun addUnityViewToGroup(group: ViewGroup) {
|
|
145
|
-
val frame = unityPlayerView ?: return
|
|
146
|
-
|
|
147
|
-
// Remove from current parent
|
|
115
|
+
// Remove from current parent if any
|
|
148
116
|
(frame.parent as? ViewGroup)?.removeView(frame)
|
|
149
117
|
|
|
150
|
-
val layoutParams =
|
|
151
|
-
|
|
152
|
-
|
|
118
|
+
val layoutParams = FrameLayout.LayoutParams(
|
|
119
|
+
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
120
|
+
FrameLayout.LayoutParams.MATCH_PARENT
|
|
153
121
|
)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
122
|
+
container.addView(frame, 0, layoutParams)
|
|
123
|
+
Log.i(TAG, "Unity view attached to container")
|
|
124
|
+
|
|
125
|
+
// Kick-start rendering after the view is in the hierarchy.
|
|
126
|
+
// Use post to let the layout pass complete first.
|
|
127
|
+
frame.post {
|
|
128
|
+
unityPlayer?.windowFocusChanged(true)
|
|
129
|
+
frame.requestFocus()
|
|
130
|
+
unityPlayer?.resume()
|
|
131
|
+
Log.i(TAG, "Rendering started")
|
|
132
|
+
}
|
|
161
133
|
}
|
|
162
134
|
|
|
163
135
|
/**
|
|
164
|
-
*
|
|
165
|
-
* React Native component unmounts.
|
|
136
|
+
* Detaches the Unity view from its current parent without destroying it.
|
|
166
137
|
*/
|
|
167
|
-
fun
|
|
138
|
+
fun detachFromContainer() {
|
|
168
139
|
val frame = unityPlayerView ?: return
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
(frame.parent as? ViewGroup)?.let { parent ->
|
|
172
|
-
parent.endViewTransition(frame)
|
|
173
|
-
parent.removeView(frame)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
frame.z = -1f
|
|
177
|
-
|
|
178
|
-
val layoutParams = ViewGroup.LayoutParams(1, 1)
|
|
179
|
-
activity.addContentView(frame, layoutParams)
|
|
180
|
-
Log.i(TAG, "Unity view parked back to background")
|
|
140
|
+
(frame.parent as? ViewGroup)?.removeView(frame)
|
|
141
|
+
Log.i(TAG, "Unity view detached from container")
|
|
181
142
|
}
|
|
182
143
|
|
|
183
144
|
fun sendMessage(gameObject: String, methodName: String, message: String) {
|
|
@@ -203,7 +164,6 @@ class UnityBridge private constructor() : IUnityPlayerLifecycleEvents, NativeCal
|
|
|
203
164
|
|
|
204
165
|
fun unload() {
|
|
205
166
|
if (!isInitialized) return
|
|
206
|
-
isReady = false
|
|
207
167
|
Log.i(TAG, "unload called")
|
|
208
168
|
val action = Runnable {
|
|
209
169
|
unityPlayer?.unload()
|
|
@@ -221,13 +181,11 @@ class UnityBridge private constructor() : IUnityPlayerLifecycleEvents, NativeCal
|
|
|
221
181
|
override fun onUnityPlayerUnloaded() {
|
|
222
182
|
Log.i(TAG, "onUnityPlayerUnloaded")
|
|
223
183
|
unityPlayer = null
|
|
224
|
-
isReady = false
|
|
225
184
|
}
|
|
226
185
|
|
|
227
186
|
override fun onUnityPlayerQuitted() {
|
|
228
187
|
Log.i(TAG, "onUnityPlayerQuitted")
|
|
229
188
|
unityPlayer = null
|
|
230
|
-
isReady = false
|
|
231
189
|
}
|
|
232
190
|
|
|
233
191
|
// NativeCallProxy.MessageListener (Unity -> RN)
|