Skip to Content
SDKSDKsXenseAR Native SDKReact NativeIntegrate Unity Library with Expo framework

Integrate Unity Library with Expo Framework

Unity Plugin Repository 

Change Log

  • [15/01/2025 13:00] Unity Library is now directly integrated into the react-native-unity-plugin module.
  • [15/01/2025 13:00] Updated installation command for the react-native-unity-plugin module.

1. Prepare the React Native (Expo) Application

1. Create an Expo Demo Project

# Install yarn npm install -g yarn # Install git LFS brew install git-lfs # Create project demo yarn create expo-app --template default@sdk-51

2. Install integrated lib react-native-unity-plugin

cd "<REACT-NATIVE-ROOT-FOLDER>" # Install lib react-native-unity-plugin yarn add "react-native-unity-plugin@git+https://gitlab.com/educationxrmhmp-group/expo-unity.git#1.0.11-release.2" # Install lib expo-build-properties for gradle.properties configuration yarn add expo-build-properties

3. Add plugin react-native-unity-plugin and expo-build-properties to app.json of demo project, add iOS permissions (copy content in plugins and infoPlist to project’s config)

{ "expo": { "plugins": [ "react-native-unity-plugin", [ "expo-build-properties", { "android": { "minSdkVersion": 26 } } ] ], "ios": { "infoPlist": { "NSCameraUsageDescription": "Allow Expo experiences to use your camera", "NSLocationWhenInUseUsageDescription": "Allow Expo experiences to use your location", "NSMicrophoneUsageDescription": "Allow Expo experiences to access your microphone", "NSMotionUsageDescription": "Allow Expo experiences to access your device's accelerometer", "NSPhotoLibraryAddUsageDescription": "Give Expo experiences permission to save photos", "NSPhotoLibraryUsageDescription": "Give Expo experiences permission to access your photos" } } } }

4. Create native folders for android and iOS platform

npx expo prebuild

2. Integrate Unity lib

Add source code

Add file Unity.tsx into <REACT-NATIVE-ROOT-FOLDER>/app/(tabs) directory with bellow content:

import UnityView from 'react-native-unity-plugin' import { useRef, useCallback, useEffect } from 'react' import { View, AppState, AppStateStatus } from 'react-native'; import { useFocusEffect } from '@react-navigation/native'; import { useRouter } from 'expo-router'; const Unity = () => { const unityRef = useRef() const appState = useRef(AppState.currentState); const router = useRouter(); useEffect(() => { if (unityRef.current) { // message set scene let message = JSON.stringify({ type: "setPlatformType", message: "reactNative" }) const handleAppStateChange = (nextAppState: AppStateStatus) => { if ( appState.current.match(/active/) && nextAppState.match(/inactive|background/) ) { console.log("Pausing Unity"); // @ts-ignore unityRef.current.pauseUnity?.(true); } if ( appState.current.match(/inactive|background/) && nextAppState === "active" ) { console.log("Resuming Unity"); // @ts-ignore unityRef.current.pauseUnity?.(false); //sendUnityMessage("appLifecycle", "resume"); } appState.current = nextAppState; }; const subscription = AppState.addEventListener("change", handleAppStateChange); // @ts-ignore unityRef.current.postMessage("ReactNativeCommandHandler", "Handle", message) return () => { subscription.remove(); }; } }, []); function HandleUnityMessage(message: string) { console.log("Handlemessage", message); // Check if the message from the WebView indicates that it's ready if (message.includes("webviewReady") || message.includes("backToHomeScreen")) { if (unityRef.current) { //message to unity to set the home screen url let message = JSON.stringify({ type: "updateHomeScreenUrl", message: "https://cdn.xensear.vn/frontend/3.2/homescreen.html" }) // @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() } router.back(); } } return ( // If you wrap your UnityView inside a parent, please take care to set dimensions to it (with `flex:1` for example). // See the `Know issues` part in the README. <View style={{ flex: 1 }}> <UnityView // @ts-ignore ref={unityRef} style={{ flex: 1 }} onUnityMessage={(result: any) => HandleUnityMessage(result.nativeEvent.message)} fullScreen={false} androidKeepPlayerMounted={false} /> </View> ) } export default Unity

Build android package

Build project for android, bellow is the command line instruction for MacOS

# Example: export JAVA_HOME='/Applications/Android Studio.app/Contents/jbr/Contents/Home' export JAVA_HOME="<YOUR-JAVA-HOME-FOLDER>" # Example: export ANDROID_HOME=/Users/xr/Library/Android/sdk export ANDROID_HOME="<YOUR-ANDROID-SDK-FOLDER>" cd "<REACT-NATIVE-ROOT-FOLDER>/android" ./gradlew assembleRelease # connect to device adb reconnect # install to device adb install "app/build/outputs/apk/release/app-release.apk"

Build Xcode Project

Open file workspace inside ios folder using XCode
Choose signing team

⚠️ Important
Connect a physical iPhone device (the prebuild version is built in Release mode for a physical device).

⚠️ Important
Switch the build configuration to Release:

Product > Scheme > Edit Scheme > Build Configuration (Info tab) > Select Release

Build the application. This step should complete successfully, and the app should be installed on the connected physical iPhone device.

Last updated on