Skip to content

Commit 24c0077

Browse files
committed
Added support for Unity 2023 and higher
1 parent 2ffb158 commit 24c0077

5 files changed

Lines changed: 294 additions & 156 deletions

File tree

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
The plugin that allows you to embed a Unity project into React Native as a full-fledged component. The plugin now supports the new architecture.
44

5+
### Android
6+
Attention! Added support for Unity 2023 and above
7+
58
> [!IMPORTANT]
69
> For iOS, it is no longer necessary to embed a project created with Unity. Only the built `UnityFramework` is used. It should be placed in the plugin folder at the path - `<YOUR_RN_PROJECT>/unity/builds/ios`
710

android/src/main/java/com/azesmwayreactnativeunity/ReactNativeUnity.java

Lines changed: 128 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -6,146 +6,153 @@
66
import android.view.ViewGroup;
77
import android.view.WindowManager;
88

9-
import com.unity3d.player.UnityPlayer;
10-
import com.unity3d.player.IUnityPlayerLifecycleEvents;
11-
129
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
1310

11+
import java.lang.reflect.InvocationTargetException;
12+
1413
public class ReactNativeUnity {
15-
private static UnityPlayer unityPlayer;
16-
public static boolean _isUnityReady;
17-
public static boolean _isUnityPaused;
18-
public static boolean _fullScreen;
19-
20-
public static UnityPlayer getPlayer() {
21-
if (!_isUnityReady) {
22-
return null;
14+
private static UPlayer unityPlayer;
15+
public static boolean _isUnityReady;
16+
public static boolean _isUnityPaused;
17+
public static boolean _fullScreen;
18+
19+
public static UPlayer getPlayer() {
20+
if (!_isUnityReady) {
21+
return null;
22+
}
23+
return unityPlayer;
2324
}
24-
return unityPlayer;
25-
}
26-
27-
public static boolean isUnityReady() {
28-
return _isUnityReady;
29-
}
3025

31-
public static boolean isUnityPaused() {
32-
return _isUnityPaused;
33-
}
26+
public static boolean isUnityReady() {
27+
return _isUnityReady;
28+
}
3429

35-
public static void createPlayer(final Activity activity, final UnityPlayerCallback callback) {
36-
if (unityPlayer != null) {
37-
callback.onReady();
38-
return;
30+
public static boolean isUnityPaused() {
31+
return _isUnityPaused;
3932
}
40-
if (activity != null) {
41-
activity.runOnUiThread(new Runnable() {
42-
@Override
43-
public void run() {
44-
activity.getWindow().setFormat(PixelFormat.RGBA_8888);
45-
int flag = activity.getWindow().getAttributes().flags;
46-
boolean fullScreen = false;
47-
if ((flag & WindowManager.LayoutParams.FLAG_FULLSCREEN) == WindowManager.LayoutParams.FLAG_FULLSCREEN) {
48-
fullScreen = true;
49-
}
50-
51-
unityPlayer = new UnityPlayer(activity, new IUnityPlayerLifecycleEvents() {
52-
@Override
53-
public void onUnityPlayerUnloaded() {
54-
callback.onUnload();
55-
}
56-
57-
@Override
58-
public void onUnityPlayerQuitted() {
59-
callback.onQuit();
60-
}
61-
});
62-
63-
try {
64-
// wait a moment. fix unity cannot start when startup.
65-
Thread.sleep(1000);
66-
} catch (Exception e) {
67-
}
68-
69-
// start unity
70-
addUnityViewToBackground();
71-
unityPlayer.windowFocusChanged(true);
72-
unityPlayer.requestFocus();
73-
unityPlayer.resume();
74-
75-
// restore window layout
76-
if (!fullScreen) {
77-
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
78-
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
79-
}
80-
_isUnityReady = true;
81-
callback.onReady();
33+
34+
public static void createPlayer(final Activity activity, final UnityPlayerCallback callback) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
35+
if (unityPlayer != null) {
36+
callback.onReady();
37+
38+
return;
8239
}
83-
});
84-
}
85-
}
8640

87-
public static void pause() {
88-
if (unityPlayer != null) {
89-
unityPlayer.pause();
90-
_isUnityPaused = true;
41+
if (activity != null) {
42+
activity.runOnUiThread(new Runnable() {
43+
@Override
44+
public void run() {
45+
activity.getWindow().setFormat(PixelFormat.RGBA_8888);
46+
int flag = activity.getWindow().getAttributes().flags;
47+
boolean fullScreen = false;
48+
if ((flag & WindowManager.LayoutParams.FLAG_FULLSCREEN) == WindowManager.LayoutParams.FLAG_FULLSCREEN) {
49+
fullScreen = true;
50+
}
51+
52+
try {
53+
unityPlayer = new UPlayer(activity, callback);
54+
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | InvocationTargetException e) {}
55+
56+
try {
57+
// wait a moment. fix unity cannot start when startup.
58+
Thread.sleep(1000);
59+
} catch (Exception e) {}
60+
61+
// start unity
62+
try {
63+
addUnityViewToBackground();
64+
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {}
65+
66+
unityPlayer.windowFocusChanged(true);
67+
68+
try {
69+
unityPlayer.requestFocusPlayer();
70+
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {}
71+
72+
unityPlayer.resume();
73+
74+
if (!fullScreen) {
75+
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
76+
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
77+
}
78+
79+
_isUnityReady = true;
80+
81+
try {
82+
callback.onReady();
83+
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {}
84+
}
85+
});
86+
}
9187
}
92-
}
9388

94-
public static void resume() {
95-
if (unityPlayer != null) {
96-
unityPlayer.resume();
97-
_isUnityPaused = false;
89+
public static void pause() {
90+
if (unityPlayer != null) {
91+
unityPlayer.pause();
92+
_isUnityPaused = true;
93+
}
9894
}
99-
}
10095

101-
public static void unload() {
102-
if (unityPlayer != null) {
103-
unityPlayer.unload();
104-
_isUnityPaused = false;
96+
public static void resume() {
97+
if (unityPlayer != null) {
98+
unityPlayer.resume();
99+
_isUnityPaused = false;
100+
}
105101
}
106-
}
107102

108-
public static void addUnityViewToBackground() {
109-
if (unityPlayer == null) {
110-
return;
111-
}
112-
if (unityPlayer.getParent() != null) {
113-
// NOTE: If we're being detached as part of the transition, make sure
114-
// to explicitly finish the transition first, as it might still keep
115-
// the view's parent around despite calling `removeView()` here. This
116-
// prevents a crash on an `addContentView()` later on.
117-
// Otherwise, if there's no transition, it's a no-op.
118-
// See https://stackoverflow.com/a/58247331
119-
((ViewGroup) unityPlayer.getParent()).endViewTransition(unityPlayer);
120-
((ViewGroup) unityPlayer.getParent()).removeView(unityPlayer);
121-
}
122-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
123-
unityPlayer.setZ(-1f);
103+
public static void unload() {
104+
if (unityPlayer != null) {
105+
unityPlayer.unload();
106+
_isUnityPaused = false;
107+
}
124108
}
125-
final Activity activity = ((Activity) unityPlayer.getContext());
126-
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(1, 1);
127-
activity.addContentView(unityPlayer, layoutParams);
128-
}
129-
130-
public static void addUnityViewToGroup(ViewGroup group) {
131-
if (unityPlayer == null) {
132-
return;
109+
110+
public static void addUnityViewToBackground() throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
111+
if (unityPlayer == null) {
112+
return;
113+
}
114+
115+
if (unityPlayer.getParentPlayer() != null) {
116+
// NOTE: If we're being detached as part of the transition, make sure
117+
// to explicitly finish the transition first, as it might still keep
118+
// the view's parent around despite calling `removeView()` here. This
119+
// prevents a crash on an `addContentView()` later on.
120+
// Otherwise, if there's no transition, it's a no-op.
121+
// See https://stackoverflow.com/a/58247331
122+
((ViewGroup) unityPlayer.getParentPlayer()).endViewTransition(unityPlayer.requestFrame());
123+
((ViewGroup) unityPlayer.getParentPlayer()).removeView(unityPlayer.requestFrame());
124+
}
125+
126+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
127+
unityPlayer.setZ(-1f);
128+
}
129+
130+
final Activity activity = ((Activity) unityPlayer.getContextPlayer());
131+
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(1, 1);
132+
activity.addContentView(unityPlayer.requestFrame(), layoutParams);
133133
}
134-
if (unityPlayer.getParent() != null) {
135-
((ViewGroup) unityPlayer.getParent()).removeView(unityPlayer);
134+
135+
public static void addUnityViewToGroup(ViewGroup group) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
136+
if (unityPlayer == null) {
137+
return;
138+
}
139+
140+
if (unityPlayer.getParentPlayer() != null) {
141+
((ViewGroup) unityPlayer.getParentPlayer()).removeView(unityPlayer.requestFrame());
142+
}
143+
144+
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT);
145+
group.addView(unityPlayer.requestFrame(), 0, layoutParams);
146+
unityPlayer.windowFocusChanged(true);
147+
unityPlayer.requestFocusPlayer();
148+
unityPlayer.resume();
136149
}
137-
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT);
138-
group.addView(unityPlayer, 0, layoutParams);
139-
unityPlayer.windowFocusChanged(true);
140-
unityPlayer.requestFocus();
141-
unityPlayer.resume();
142-
}
143150

144-
public interface UnityPlayerCallback {
145-
void onReady();
151+
public interface UnityPlayerCallback {
152+
void onReady() throws InvocationTargetException, NoSuchMethodException, IllegalAccessException;
146153

147-
void onUnload();
154+
void onUnload();
148155

149-
void onQuit();
150-
}
156+
void onQuit();
157+
}
151158
}

android/src/main/java/com/azesmwayreactnativeunity/ReactNativeUnityView.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,34 @@
44

55
import android.content.Context;
66

7-
import com.unity3d.player.UnityPlayer;
8-
97
import android.annotation.SuppressLint;
108
import android.content.res.Configuration;
119
import android.widget.FrameLayout;
1210

11+
import java.lang.reflect.InvocationTargetException;
12+
1313
@SuppressLint("ViewConstructor")
1414
public class ReactNativeUnityView extends FrameLayout {
15-
private UnityPlayer view;
15+
private UPlayer view;
1616
public boolean keepPlayerMounted = false;
1717

1818
public ReactNativeUnityView(Context context) {
1919
super(context);
2020
}
2121

22-
public void setUnityPlayer(UnityPlayer player) {
22+
public void setUnityPlayer(UPlayer player) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
2323
this.view = player;
2424
addUnityViewToGroup(this);
2525
}
2626

2727
@Override
2828
public void onWindowFocusChanged(boolean hasWindowFocus) {
2929
super.onWindowFocusChanged(hasWindowFocus);
30+
3031
if (view == null) {
3132
return;
3233
}
34+
3335
view.windowFocusChanged(hasWindowFocus);
3436

3537
if (!keepPlayerMounted || !_isUnityReady) {
@@ -38,7 +40,7 @@ public void onWindowFocusChanged(boolean hasWindowFocus) {
3840

3941
// pause Unity on blur, resume on focus
4042
if (hasWindowFocus && _isUnityPaused) {
41-
view.requestFocus();
43+
// view.requestFocus();
4244
view.resume();
4345
} else if (!hasWindowFocus && !_isUnityPaused) {
4446
view.pause();
@@ -48,6 +50,7 @@ public void onWindowFocusChanged(boolean hasWindowFocus) {
4850
@Override
4951
protected void onConfigurationChanged(Configuration newConfig) {
5052
super.onConfigurationChanged(newConfig);
53+
5154
if (view != null) {
5255
view.configurationChanged(newConfig);
5356
}
@@ -56,8 +59,13 @@ protected void onConfigurationChanged(Configuration newConfig) {
5659
@Override
5760
protected void onDetachedFromWindow() {
5861
if (!this.keepPlayerMounted) {
59-
addUnityViewToBackground();
62+
try {
63+
addUnityViewToBackground();
64+
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
65+
throw new RuntimeException(e);
66+
}
6067
}
68+
6169
super.onDetachedFromWindow();
6270
}
6371
}

0 commit comments

Comments
 (0)