Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,45 @@ export default Unity;
- `pauseUnity?: (pause: boolean)` - pause the Unity
- `windowFocusChanged(hasFocus: boolean = false)` - simulate focus change (intended to be used to recover from black screen (not rendering) after remounting Unity view when `resumeUnity` does not work) **ANDROID ONLY**

# Troubleshooting

## iOS: Unity view not rendering / blank screen

The `UnityView` component **must** have non-zero dimensions. Always use `style={{ flex: 1 }}` on both the parent container and the `UnityView` itself. The native `layoutSubviews` method checks for positive width and height before attaching the Unity root view.

## iOS: `MTLTextureDescriptor has width of zero` crash

This is the same root cause as above. The Unity Metal renderer crashes if it receives a zero-sized texture. Ensure the view has layout dimensions before the component mounts.

## Android: Build fails with Java-related errors

Unity's Android export requires a specific JDK version. Add the following to `android/gradle.properties`, pointing to the JDK that matches your Unity version:

```gradle
org.gradle.java.home=/path/to/your/jdk
```

For Unity 6000.x, JDK 17 is typically required (e.g., Zulu JDK 17).

## React Native 0.85+ / New Architecture (Fabric)

This package supports New Architecture out of the box via codegen. On RN 0.85+, New Architecture is the default. Ensure:

- `newArchEnabled=true` in `android/gradle.properties`
- Your Podfile uses `install_modules_dependencies` (standard in RN 0.71+)

The podspec automatically detects and configures Fabric dependencies when available.

## iOS: UnityFramework not found during `pod install`

Ensure you have built the `UnityFramework.framework` from your Unity project and placed it at:

```
<YOUR_RN_PROJECT>/unity/builds/ios/UnityFramework.framework
```

The `pod install` step copies this framework into the package. If the path is wrong, you will see a warning during installation.

# Contributing

See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
Expand Down
14 changes: 1 addition & 13 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,14 +1,3 @@
buildscript {
repositories {
google()
mavenCentral()
}

dependencies {
classpath "com.android.tools.build:gradle:7.4.2"
}
}

def isNewArchitectureEnabled() {
return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
}
Expand Down Expand Up @@ -66,7 +55,7 @@ android {
}
}

lintOptions {
lint {
disable "GradleCompatible"
}

Expand Down Expand Up @@ -98,7 +87,6 @@ repositories {
}
google()
mavenCentral()
jcenter()
}


Expand Down
21 changes: 19 additions & 2 deletions android/src/main/java/com/azesmwayreactnativeunity/UPlayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,30 @@ public void requestFocusPlayer() throws NoSuchMethodException, InvocationTargetE
}

public FrameLayout requestFrame() throws NoSuchMethodException {
// Unity 6+: UnityPlayer no longer extends FrameLayout, use getFrameLayout()
try {
Method getFrameLayout = unityPlayer.getClass().getMethod("getFrameLayout");

return (FrameLayout) getFrameLayout.invoke(unityPlayer);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
return unityPlayer;
// Fall through to getView()
}
// Unity 6+ alternate: try getView()
try {
Method getView = unityPlayer.getClass().getMethod("getView");
Object view = getView.invoke(unityPlayer);
if (view instanceof FrameLayout) {
return (FrameLayout) view;
}
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
// Fall through
}
// Legacy Unity (pre-6): UnityPlayer itself extends FrameLayout
// Cast through Object to bypass compile-time type check
Object player = unityPlayer;
if (player instanceof FrameLayout) {
return (FrameLayout) player;
}
return null;
}

public void setZ(float v) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Expand Down
56 changes: 47 additions & 9 deletions ios/RNUnityView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ - (void)initUnityModule {
}

[self setUfw: UnityFrameworkLoad()];

if (![self ufw]) {
NSLog(@"[RNUnity] ERROR: UnityFrameworkLoad returned nil");
return;
}

[[self ufw] registerFrameworkListener: self];

unsigned count = (int) [[[NSProcessInfo processInfo] arguments] count];
Expand All @@ -61,23 +67,53 @@ - (void)initUnityModule {
array[count] = NULL;

[[self ufw] runEmbeddedWithArgc: gArgc argv: array appLaunchOpts: appLaunchOpts];

if (![[self ufw] appController]) {
NSLog(@"[RNUnity] ERROR: appController nil after runEmbedded");
return;
}

[[self ufw] appController].quitHandler = ^(){ NSLog(@"AppController.quitHandler called"); };
[self.ufw.appController.rootView removeFromSuperview];

if (@available(iOS 13.0, *)) {
[[[[self ufw] appController] window] setWindowScene: nil];
} else {
[[[[self ufw] appController] window] setScreen: nil];
// Remove Unity's rootView from Unity's own view hierarchy
UIView *unityRootView = self.ufw.appController.rootView;
[unityRootView removeFromSuperview];

// Hide Unity's window so it doesn't cover React Native's UI
UIWindow *unityWindow = [[[self ufw] appController] window];
unityWindow.hidden = YES;

// Restore React Native's window as key window
UIWindow *rnWindow = [[[UIApplication sharedApplication] delegate] window];
if (!rnWindow) {
// iOS 13+ scene-based: find the first connected scene's window
if (@available(iOS 13.0, *)) {
for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) {
if ([scene isKindOfClass:[UIWindowScene class]]) {
UIWindowScene *windowScene = (UIWindowScene *)scene;
for (UIWindow *w in windowScene.windows) {
if (w != unityWindow) {
rnWindow = w;
break;
}
}
if (rnWindow) break;
}
}
}
}
if (rnWindow) {
[rnWindow makeKeyAndVisible];
}

[[[[self ufw] appController] window] addSubview: self.ufw.appController.rootView];
[[[[self ufw] appController] window] makeKeyAndVisible];
[[[[[[self ufw] appController] window] rootViewController] view] setNeedsLayout];
// Add Unity's rendering view to self (the RN component view)
unityRootView.frame = self.bounds;
[self addSubview:unityRootView];

[NSClassFromString(@"FrameworkLibAPI") registerAPIforNativeCalls:self];
}
@catch (NSException *e) {
NSLog(@"%@",e);
NSLog(@"[RNUnity] EXCEPTION: %@", e.reason);
}
}

Expand All @@ -88,6 +124,8 @@ - (void)layoutSubviews {
self.ufw.appController.rootView.frame = self.bounds;
[self addSubview:self.ufw.appController.rootView];
}


}

- (void)pauseUnity:(BOOL * _Nonnull)pause {
Expand Down
59 changes: 59 additions & 0 deletions lib/commonjs/UnityView.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions lib/commonjs/UnityView.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions lib/commonjs/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions lib/commonjs/index.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions lib/commonjs/specs/UnityViewNativeComponent.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions lib/commonjs/specs/UnityViewNativeComponent.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 49 additions & 0 deletions lib/module/UnityView.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions lib/module/UnityView.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions lib/module/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions lib/module/index.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading