Tích hợp Unity Library với Expo Framework
Change log:
- [15/01/2025 13:00] Thư viện Unity được tích hợp trực tiếp vào module
react-native-unity-plugin - [15/01/2025 13:00] Cập nhật lệnh cài đặt module
react-native-unity-plugin
1. Chuẩn bị app React Native
B1: Tạo một app react native demo bằng expo
# Cài đặt yarn
npm install -g yarn
# Cài đặt git LFS
brew install git-lfs
# Tạo project demo
yarn create expo-app --template default@sdk-51B2: Cài đặt lib tích hợp react-native-unity-plugin
cd "<REACT-NATIVE-ROOT-FOLDER>"
# Cài đặt 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"
# Cài đặt lib expo-build-properties để cấu hình gradle.properties
yarn add expo-build-propertiesB3: Thêm plugin react-native-unity-plugin và expo-build-properties vào app.json của project demo, cấu hình quyền cho iOS (copy phần nội dung trong plugins và infoPlist vào config của project)
{
"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"
}
}
}
}B4: Tạo thư mục native trên hai nền tảng android và iOS
npx expo prebuildSau bước trên trong project demo sẽ có thêm hai thư mục android và iOS
2. Thử nghiệm tích hợp lib Unity
Thêm mã nguồn thử nghiệm
Thêm file Unity.tsx vào thư mục <REACT-NATIVE-ROOT-FOLDER>/app/(tabs) với nội dung sau:
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.cloud/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 android, dưới đây là các hướng dẫn bằng cách sử dụng command line của 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
Mở file workspace trong folder ios bằng XCode
Chọn signing team (bước này dễ quên nên nhắc trong docs luôn)
important
Kết nối máy iPhone vật lý (do bản prebuild được build release cho device)
important
Chọn Build sang Release (Product > Scheme > Edit Scheme > Build Configuration trong thẻ Info > chọn Release)
Build app (đoạn này nên thành công và app được cài vào máy iPhone vật lý)