Skip to Content
SDKSDKsXenseAR Native SDKReact NativeIntegrate Unity Library with React Native - 1.0.3+

Integrate Unity Library with React Native

1. Prepare the React Native Application

1. Create a React Native Demo Project

npx @react-native-community/cli init "<react-native-project>" cd "<react-native-project>"

2. Install react-native-unity

npm install @azesmway/react-native-unity@latest mkdir -p unity/builds/android # Tạo thư mục Android mkdir -p unity/builds/ios # Tạo thư mục iOS

3. Dependencies for Demo Navigation

npm install @react-navigation/native npm install react-native-screens react-native-safe-area-context react-native-gesture-handler react-native-reanimated react-native-vector-icons npm install @react-navigation/native-stack

4. Create Demo Screens

mkdir -p screens
  • Create HomeScreen.js and UnityScreen.js inside <react-native-project>/screens:

HomeScreen.js

import React from 'react'; import { SafeAreaView, View, Text, Button, StyleSheet } from 'react-native'; export default function HomeScreen({ navigation }) { return ( <SafeAreaView style={styles.container}> <View style={styles.buttonContainer}> <Button title='Go to AR' onPress={() => navigation.navigate('Unity', { link: "https://xensear.vn/sunland/homescreen" })} /> </View> </SafeAreaView> ) } const styles = StyleSheet.create({ container: { flex: 1, }, buttonContainer: { marginTop: 20, alignItems: 'center', }, });

UnityScreen.js

import UnityView from '@azesmway/react-native-unity' import { React, useRef, useCallback, useEffect } from 'react'; import { View, Text, StyleSheet } from 'react-native'; import { useFocusEffect } from '@react-navigation/native'; export default function UnityScreen({ navigation, route }) { const unityRef = useRef(); const { link } = route.params; useEffect(() => { if (unityRef.current) { let message = JSON.stringify({ type: "setPlatformType", message: "reactNative" }) // @ts-ignore unityRef.current.postMessage("ReactNativeCommandHandler", "Handle", message) } }, []); function HandleUnityMessage(message) { console.log("Handle message", message); if(message.includes("unityReady") || message.includes("backToHomeScreen")) { if (unityRef.current) { //message set scene let message = JSON.stringify({ type: "updateHomeScreenUrl", message: link }) // @ts-ignore unityRef.current.postMessage("ReactNativeCommandHandler", "Handle", message) } } else if (message.includes("getNativeParameters")) { } else if (message.includes("backToNativeView")) { if (unityRef.current) { // @ts-ignore unityRef.current.unloadUnity() navigation.goBack() } } } return ( <View style={{ flex: 1}}> <UnityView // @ts-ignore ref={unityRef} style={{ flex: 1 }} onUnityMessage={(result) => HandleUnityMessage(result.nativeEvent.message)} fullScreen={false} androidKeepPlayerMounted={false} /> </View> ) }

  • Modify App.tsx:
import * as React from 'react'; import { NavigationContainer } from '@react-navigation/native'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; import HomeScreen from './screens/HomeScreen'; import UnityScreen from './screens/UnityScreen'; const Stack = createNativeStackNavigator(); export default function App() { return ( <NavigationContainer> <Stack.Navigator initialRouteName='Home' screenOptions={{ headerShown: false }}> <Stack.Screen name='Home' component={HomeScreen}/> <Stack.Screen name='Unity' component={UnityScreen}/> </Stack.Navigator> </NavigationContainer> ) }

2. Integrate Unity Library into React Native Android

⚠️ The @azesmway/react-native-unity library does not fully support Unity AAR-based integration. Manual modifications to the original library are required. All required changes are documented below.


1. Copy unityLibrary

Copy the unityLibrary folder into: unity/build/android

Open file node_modules/@azesmway/react-native-unity/android/build.gradle comment line number 111

ℹ️ The library does not properly support Unity integration via AAR. The unity-classes.jar referenced in this line is already bundled inside the generated AAR during the Unity build phase. Keeping this line may cause duplicate class conflicts during Gradle build.

// implementation files("${project(':unityLibrary').projectDir}/libs/unity-classes.jar")

Open file node_modules/@azesmway/react-native-unity/android/src/main/java/com/azesmwayreactnativeunity/ReactNativeUnityViewManager.java and edit function pauseUnity:

@Override public void pauseUnity(ReactNativeUnityView view, boolean pause) { if (isUnityReady()) { assert getPlayer() != null; if (pause) { getPlayer().pause(); } else { getPlayer().resume(); } } }

2. Modify the following files inside the <react-native-project/android> directory

--------------------------------------------------------------- ---------------- "android/gradle.properties" ------------------ --------------------------------------------------------------- # add this line android.minSdkVersion=26 --------------------------------------------------------------- ----------------- "android/settings.gradle" ------------------- --------------------------------------------------------------- # add this line include ':unityLibrary' project(':unityLibrary').projectDir=new File('..\\unity\\builds\\android\\unityLibrary') --------------------------------------------------------------- -------------- "android/android/app/build.gradle" ------------- --------------------------------------------------------------- dependencies { // add this line implementation fileTree(dir: "${project(':unityLibrary').projectDir}/libs", include: '*.aar') } --------------------------------------------------------------- -------- "android/app/src/main/res/values/strings.xml" -------- --------------------------------------------------------------- // add this line inside resource block <string name="game_view_content_description">GameView</string>

3. Open file node_modules/@azesmway/react-native-unity/android/src/main/java/com/azesmwayreactnativeunity/UPlayer.java

Edit function requestFrame:

public FrameLayout requestFrame() { try { //Attempt to invoke getFrameLayout() for the newer UnityPlayer class Method getFrameLayout = unityPlayer.getClass().getMethod("getFrameLayout"); return (FrameLayout) getFrameLayout.invoke(unityPlayer); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { // If it is old UnityPlayer, use isInstance() and cast() to bypass incompatible type checks when compiling using newer versions of UnityPlayer if (FrameLayout.class.isInstance(unityPlayer)) { return FrameLayout.class.cast(unityPlayer); } else { return null; } } }

4. Build Android APK

# JAVA_HOME in Android Studio location is <android-studio-folder>/jbr export JAVA_HOME="<java-home-folder>" # ANDROID_HOME in Android Studio location can be copied from SDK Manager export ANDROID_HOME="<android-sdk-folder>" cd "<react-native-project>/android" ./gradlew assembleRelease # connect to device adb reconnect # install to device adb install "<react-native-project>/android/app/build/outputs/apk/release/app-release.apk"

3. Integrate Unity Library into React Native iOS

⚠️ The @azesmway/react-native-unity library does not fully support Unity Framework integration by default. Manual modifications to the original library configuration are required for proper integration. All necessary changes are documented below.


1. Copy UnityFramework.framework to unity/builds/ios

Open file node_modules/@azesmway/react-native-unity/react-native-unity.podspec, add frameworks into project.

ℹ️ Some third-party dependencies are distributed as standalone frameworks.
In Unity-generated Xcode projects, these frameworks are automatically linked during export.
However, in a React Native iOS project, these frameworks are not linked by default and must be explicitly declared (e.g., in the Podspec) to ensure successful compilation and runtime execution.

s.vendored_frameworks = [ "ios/UnityFramework.xcframework", "ios/NSR.xcframework", "ios/StcCorder.xcframework" ]

Build podfile

⚠️ This step is mandatory because the Podspec inside node_modules was modified. Without reinstalling Pods, the new frameworks will not be linked correctly.

cd "<react-native-project>" rm -rf ios/Pods && rm -f ios/Podfile.lock && npx pod-install

2. Add privacy configs in order to use camera, location, microphone, … to file <react-native-project>/ios/<app-name>/info.plist

<key>NSCameraUsageDescription</key> <string>Allow Expo experiences to use your camera</string> <key>NSLocationWhenInUseUsageDescription</key> <string>Allow Expo experiences to use your location</string> <key>NSMicrophoneUsageDescription</key> <string>Allow Expo experiences to access your microphone</string> <key>NSMotionUsageDescription</key> <string>Allow Expo experiences to access your device's accelerometer</string> <key>NSPhotoLibraryAddUsageDescription</key> <string>Give Expo experiences permission to save photos</string> <key>NSPhotoLibraryUsageDescription</key> <string>Give Expo experiences permission to access your photos</string>

3. Open workspace file inside ios folder using XCode

  • Connect Physical Device

  • Choose signing team

  • Set Build Configuration to Release (Product > Scheme > Edit Scheme > Build Configuration in Info > chọn Release)

  • Build app (Select the connected physical device as the run target)


Last updated on