react-native 에서 unity 임베딩하기

CodeLog·2021년 8월 15일
3
post-thumbnail

📌사용된 라이브러리

💻 PC 환경 : macOS Big Sur v11.4

⚙️ 사용된 라이브러리 : GitHub - azesmway/react-native-unity-play: Play an unity view in react native

위 라이브러리는 react-native에 unity 프로젝트를 임베딩 할 수있는 라이브러리 이고 테스트로 적용하면서 만났던 여러 문제에대해 해결해 가는 내용을 담고있습니다.

🚧본 내용은 안드로이드 기반으로 작성되었으며 차후 ios관련 내용도 추가하겠음.

react-native 프로젝트를 만들기 위해서 필요한 개발환경이 먼제 셋팅되어있다는 것을 가정하고 프로젝트 생성부터 진행 합니다.

react-native project 생성

$ react-native init unityAndRN

생성된 프로젝트로 이동

cd unityAndRN

unityAndRN project가 정상적으로 빌드 되는지 확인한다.

❗️만약 첫 빌드에서 실패 했다면 metro에서 reload하지 말고 다시 빌드하면 된다.

$ npx react-native run-android

라이브러리 설치

$ npm install react-native-unity-play --save

❗️라이브러리를 설치하고 바로빌드를 진행할 경우 build.gradle 4.1.3 관련 error 가 발생합니다. 조치내용은 아래에서 천천히 진행 하겠음

unity project export 셋팅 (android)

UNITY VERSION >= 2020.x

unity에서 임베딩 할 project open 후

unityHub open

build 할 project의 EDITOR VERSION을 클릭 후 원하는 version 및 플랫폼을 선택해서 Open한다

🌟unity → Preferences → External Tools 에서 Android JDK, SDK, NDK 경로를 설정 할 수있다.


기본 추천 경로

OpenJDK : /Applications/Unity/Hub/Editor/2021.1.16f1/PlaybackEngines/AndroidPlayer/OpenJDK
SDK : /Applications/Unity/Hub/Editor/2021.1.16f1/PlaybackEngines/AndroidPlayer/SDK
NDK : /Applications/Unity/Hub/Editor/2021.1.16f1/PlaybackEngines/AndroidPlayer/NDK
Gradle : /Applications/Unity/Hub/Editor/2021.1.16f1/PlaybackEngines/AndroidPlayer/Tools/gradle

File → Build Settings

export 할 Platform 클릭 후 Switch Platform을 클릭 하면 해당 Platform에 unity로고가 생성 된다.

  • Export projeect : 체크

Projeect Settings → Resolution and Presentation

  • Start in fullscreen mode : 체크 해제
  • Render outside safe area : 체크 해제

setting이 완료되면 Export한다!!

export한 파일은 아래와 같은 구성을 갖는다.

export된 unity 파일을 react-native project에 적용

react-native project에서 root 디렉터리에 unity/builds/android 디렉터리를 구성한다

android/app/libs 폴더를 생성

android로 export 한 unity 파일을 unity/builds/android에 이동시킨다.

unity/builds/android/unityLibrary/libs/ 의 하위 파일을 모두 android/app/libs로 복사

android/app/build.gradle 에 아래 내용 추가

defaultConfig {
    ...
    ndk {
        abiFilters "armeabi-v7a", "arm64-v8a"
    }
}

android/app/build.gradle 파일 내 dependencies 블럭에 내용 추가

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

android/build.gradle 에서 아래 내용 추가


allprojects {
    repositories {
        flatDir {
            dirs "$rootDir/app/libs"
        }

android/build.gradle 에서 아래 내용으로 업데이트 한다

classpath("com.android.tools.build:gradle:4.1.3")

android/gradle.properties에서 아래 내용 추가

unityStreamingAssets=.unity3d

android/settings.gradle 에 아래 내용 추가


include ':unityLibrary'
project(':unityLibrary').projectDir=new File('..\\unity\\builds\\android\\unityLibrary')

android/app/src/main/res/values/strings.xml 폴더에 아래 내용 추가

<string name="game_view_content_description">Game view</string>
<string name="unity_root">unity_root</string>

android/app/src/main/AndroidManifest.xml 에 아래 내용 업데이트

<application
  ...
  android:extractNativeLibs="true" 

<activity
  android:name=".MainActivity"
  ...
  android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density"
  android:hardwareAccelerated="true"
>

minSdkVersion을 21이상으로 설정

unity/builds/android/unityLibrary/src/main/AndroidManifest.xml 내 아래 태그 삭제

<intent-filter>...</intent-filter> 태그를 삭제

unity/builds/android/unityLibrary/src/main/AndroidManifest.xml 에서 아래 내용 삭제

 android:icon="@mipmap/app_icon" 
 android:theme="@style/UnityThemeSelector" 삭제

android/unityLibrary/build.gradle 아래 내용주석 처리

//    implementation(name: 'native-toolkit', ext:'aar')
//    implementation(name: 'support-compat-27.1.1', ext:'aar')
//    implementation(name: 'support-v4-27.1.1', ext:'aar')

node_modules/react-native-unity-play/android/build.gradle 아래 내용 추가

❗️라이브러리 제작자가 repositories 허브를 누락하여 build.gradle 4.1.3 error 가 발생했습니다.

buildscript {
    repositories {
        mavenCentral()
        google()
        jcenter()
    }

unityAndRN/unity/builds/android 의 local.properties 파일을 unityAndRN/android 에 복사하고 아래 내용을 삭제한다.

sdk.ndk=/Applications/Unity/Hub/Editor/2021.1.16f1/PlaybackEngines/AndroidPlayer/NDK

📌licenses error 발생

안드로이드 스튜디오에서 Google Play licensing Library를 설치해도 해당 error는 해결되지 않는다

File /Users/kjw/.android/repositories.cfg could not be loaded.
Checking the license for package Android SDK Build-Tools 29.0.2 in /Applications/Unity/Hub/Editor/2021.1.16f1/PlaybackEngines/AndroidPlayer/SDK/licenses
License for package Android SDK Build-Tools 29.0.2 accepted.
Preparing "Install Android SDK Build-Tools 29.0.2 (revision: 29.0.2)".
"Install Android SDK Build-Tools 29.0.2 (revision: 29.0.2)" ready.
Installing Android SDK Build-Tools 29.0.2 in /Applications/Unity/Hub/Editor/2021.1.16f1/PlaybackEngines/AndroidPlayer/SDK/build-tools/29.0.2
"Install Android SDK Build-Tools 29.0.2 (revision: 29.0.2)" complete.
"Install Android SDK Build-Tools 29.0.2 (revision: 29.0.2)" finished.
> Task :unityLibrary:stripDebugDebugSymbols FAILED
59 actionable tasks: 2 executed, 57 up-to-date

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':unityLibrary:stripDebugDebugSymbols'.
> NDK from ndk.dir at /Applications/Unity/Hub/Editor/2021.1.16f1/PlaybackEngines/AndroidPlayer/NDK had version [21.3.6528147] which disagrees with android.ndkVersion [20.1.5948944]

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 12s

error Failed to install the app. Make sure you have the Android development environment set up: https://reactnative.dev/docs/environment-setup.
Error: Command failed: ./gradlew app:installDebug -PreactNativeDevServerPort=8081

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':unityLibrary:stripDebugDebugSymbols'.
> NDK from ndk.dir at /Applications/Unity/Hub/Editor/2021.1.16f1/PlaybackEngines/AndroidPlayer/NDK had version [21.3.6528147] which disagrees with android.ndkVersion [20.1.5948944]

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 12s

    at makeError (/Users/kjw/Desktop/Project/unityAndRN/node_modules/execa/index.js:174:9)
    at /Users/kjw/Desktop/Project/unityAndRN/node_modules/execa/index.js:278:16
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at async runOnAllDevices (/Users/kjw/Desktop/Project/unityAndRN/node_modules/@react-native-community/cli-platform-android/build/commands/runAndroid/runOnAllDevices.js:94:5)
    at async Command.handleAction (/Users/kjw/Desktop/Project/unityAndRN/node_modules/react-native/node_modules/@react-native-community/cli/build/index.js:186:9)
info Run CLI with --verbose flag for more details.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! unityAndRN@0.0.1 android: `react-native run-android`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the unityAndRN@0.0.1 android script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

안드로이드 스튜디오에서 다운받은 licenses 폴더를/Applications/Unity/Hub/Editor/2021.1.16f1/PlaybackEngines/AndroidPlayer/SDK 에 복사한다.


만약 AndroidPlayer 접근 불가능으로 복사가 진행되지 않을경우 파일의 접근 권한을 모두주고 하면 된다.

📌NDK 버전 불일치 error 발생

> Task :unityLibrary:BuildIl2CppTask FAILED
57 actionable tasks: 6 executed, 51 up-to-date
Note: /Users/kjw/Desktop/Project/unity/unity-master/android/app/src/debug/java/com/unity/ReactNativeFlipper.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.

FAILURE: Build failed with an exception.

* Where:
Build file '/Users/kjw/Desktop/Project/unity/unity-master/unity/builds/android/unityLibrary/build.gradle' line: 66

* What went wrong:
Execution failed for task ':unityLibrary:BuildIl2CppTask'.
> NDK from ndk.dir at /Applications/Unity/Hub/Editor/2021.1.16f1/PlaybackEngines/AndroidPlayer/NDK had version [21.3.6528147] which disagrees with android.ndkVersion [22.1.7171670]

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 3s

error Failed to install the app. Make sure you have the Android development environment set up: https://reactnative.dev/docs/environment-setup.
Error: Command failed: ./gradlew app:installDebug -PreactNativeDevServerPort=8081
Note: /Users/kjw/Desktop/Project/unity/unity-master/android/app/src/debug/java/com/unity/ReactNativeFlipper.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.

FAILURE: Build failed with an exception.

* Where:
Build file '/Users/kjw/Desktop/Project/unity/unity-master/unity/builds/android/unityLibrary/build.gradle' line: 66

* What went wrong:
Execution failed for task ':unityLibrary:BuildIl2CppTask'.
> NDK from ndk.dir at /Applications/Unity/Hub/Editor/2021.1.16f1/PlaybackEngines/AndroidPlayer/NDK had version [21.3.6528147] which disagrees with android.ndkVersion [22.1.7171670]

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 3s

    at makeError (/Users/kjw/Desktop/Project/unity/unity-master/node_modules/execa/index.js:174:9)
    at /Users/kjw/Desktop/Project/unity/unity-master/node_modules/execa/index.js:278:16
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at async runOnAllDevices (/Users/kjw/Desktop/Project/unity/unity-master/node_modules/@react-native-community/cli-platform-android/build/commands/runAndroid/runOnAllDevices.js:94:5)
    at async Command.handleAction (/Users/kjw/Desktop/Project/unity/unity-master/node_modules/react-native/node_modules/@react-native-community/cli/build/index.js:186:9)
info Run CLI with --verbose flag for more details.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! unity@0.0.1 android: `react-native run-android`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the unity@0.0.1 android script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:

android/build.gradle 에서 ndkVersion을 수정한다. 20.1.5948944 → 21.3.6528147

project root 디렉터리에 있는 App.js를 수정한다.

App.js

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React from 'react';
import type {Node} from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
} from 'react-native';

import {
  Colors,
  DebugInstructions,
  Header,
  LearnMoreLinks,
  ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

import Unity from './Unity';

const Section = ({children, title}): Node => {
  const isDarkMode = useColorScheme() === 'dark';
  return (
    <View style={styles.sectionContainer}>
      <Text
        style={[
          styles.sectionTitle,
          {
            color: isDarkMode ? Colors.white : Colors.black,
          },
        ]}>
        {title}
      </Text>
      <Text
        style={[
          styles.sectionDescription,
          {
            color: isDarkMode ? Colors.light : Colors.dark,
          },
        ]}>
        {children}
      </Text>
    </View>
  );
};

const App: () => Node = () => {
  const isDarkMode = useColorScheme() === 'dark';

  const backgroundStyle = {
    backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
  };

  return (
    <SafeAreaView style={backgroundStyle}>
      <StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />
      <Unity />
      <ScrollView
        contentInsetAdjustmentBehavior="automatic"
        style={backgroundStyle}>
        <Header />
        <View
          style={{
            backgroundColor: isDarkMode ? Colors.black : Colors.white,
          }}>
          <Section title="Step One">
            Edit <Text style={styles.highlight}>App.js</Text> to change this
            screen and then come back to see your edits.
          </Section>
          <Section title="See Your Changes">
            <ReloadInstructions />
          </Section>
          <Section title="Debug">
            <DebugInstructions />
          </Section>
          <Section title="Learn More">
            Read the docs to discover what to do next:
          </Section>
          <LearnMoreLinks />
        </View>
      </ScrollView>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  sectionContainer: {
    marginTop: 32,
    paddingHorizontal: 24,
  },
  sectionTitle: {
    fontSize: 24,
    fontWeight: '600',
  },
  sectionDescription: {
    marginTop: 8,
    fontSize: 18,
    fontWeight: '400',
  },
  highlight: {
    fontWeight: '700',
  },
});

export default App;

project root 디렉터리에 Unity.js 파일을 추가하여 내용을 입력

Unity.js

import React from 'react';
import {Button, Dimensions, Platform, View} from 'react-native';
import UnityView, {
  UnityModule,
  UnityResponderView,
} from 'react-native-unity-play';

const {width, height} = Dimensions.get('window');

class Unity extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      isVisible: false,
    };

    this.initComponent = () => {
      if (Platform.OS === 'android') {
        UnityModule.resume();
      }
    };
  }

  componentDidMount() {
    this.initComponent();
  }

  render() {
    const {isVisible} = this.state;
    let unityElement;

    if (Platform.OS === 'android') {
      unityElement = (
        <UnityView style={{width: width, height: height, zIndex: 2}} />
      );
    } else {
      unityElement = (
        <UnityResponderView
          fullScreen={true}
          style={{width: width, height: height}}
        />
      );
    }

    return (
      <View>
        {!isVisible && (
          <Button
            title={'Press Start Unity Project'}
            onPress={() => {
              this.setState({isVisible: true});
            }}
          />
        )}
        {isVisible && (
          <>
            {unityElement}
            <View
              style={{
                position: 'absolute',
                top: 45,
                left: 20,
                zIndex: 20,
              }}>
              <Button
                title={'Close'}
                onPress={() => {
                  if (Platform.OS === 'android') {
                    UnityModule.quit();
                  }
                  this.setState({isVisible: false});
                }}
                style={{color: '#fff'}}
              />
            </View>
          </>
        )}
      </View>
    );
  }
}

export default Unity;

빌드 실행

npm run android

react-native 화면에서 "PRESS START UNITY PROJECT" 클릭

unity project 화면


완성!!!

느낌 및 보완

꼼꼼함이 더 필요할것 같고 기록을 계속 해 가면서 삽질을 중복으로 하지 않도록 하는것이 시간을 절약하는데 큰 도움이 될것 같다.
이번 주제에서 unity, 안드로이드의 SDK, NDK, gradle에 대한 지식이 없다보니 초반부터 접근이 쉽지 않았다.
나중에 추가적으로 더 공부가 필요해 보인다.
보안점으로는 reac-native project를 빌드하는 pc의 환경이 바뀔경우 빌드를 실패 할 수 있다. 원인으로는 안드로이드 SDK 경로가 절대 path로 설정되어 있기 때문이다. 이 부분은 차후에 유연하게 다른 pc에서도 빌드 할 수 있도록 수정이 필요하다.

이번 프로젝트는 절반의 성공이다.. 아직 IOS가 나를 기다리고있...ㄷ..ㅏ

빌드 오류

window에서 빌드시 아래 오류가 발생할 수 있음 해당 SDK의 접근권한을 모두 주고 다시진행하면 됩니다.

Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.1.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\build-tools\30.0.2\package.xml. Proba
bly the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.1.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platform-tools\package.xml. Probably
the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.1.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-29\package.xml. Pro
bably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.1.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\tools\package.xml. Probably the SDK i
s read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.1.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\build-tools\30.0.2\package.xml. Proba
bly the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.1.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platform-tools\package.xml. Probably
the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.1.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-29\package.xml. Pro
bably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.1.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\tools\package.xml. Probably the SDK i
s read-only
Checking the license for package Android SDK Build-Tools 29.0.2 in C:\Program Files\Unity\Hub\Editor\2020.1.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SD
K\licenses
Warning: License for package Android SDK Build-Tools 29.0.2 not accepted.
profile
개발로그

1개의 댓글

comment-user-thumbnail
2023년 2월 3일

안녕하세요 다름이아니라 저도 Unity를 react-native의 임베딩 해야하는데 라이브러리 설치하면 노드모듈 오류로 app 이 안켜지는 상태인데 혹시 작업하실때 rn 버전을 여쭤봐두될까요?

답글 달기