Integrate Unity Library with Expo Framework
Change Log
- [15/01/2025 13:00] Unity Library is now directly integrated into the
react-native-unity-pluginmodule. - [15/01/2025 13:00] Updated installation command for the
react-native-unity-pluginmodule.
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-512. 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-properties3. 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 prebuild2. 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 UnityBuild 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