Unity3D Android Jar Lib 만들어 연동하기

 올해 초까지 cocos2d-x 관련 작업과 포스팅을 하면서 간간히? 들었던 말들이 있었습니다. 유니티3D는 안드로이드 빌드 쉬운데 왜 cocos2d-x로 개발하는지 모르겠다는 이런 뉘양스의 말들이죠. 요즘은 유니티3D를 R&D하는 입장에서 보면 뭐 틀린말은 아니지만 딱 맞는말도 아닙니다.

 무슨말인고 하니 순수 게임만 만들어 빌드할 때는 유니티3D가 다 해주지만, 역시나 안드로이드 프로젝트를 진행하게 되면 이클립스와 연관된 다른 외부 SDK등을 연동하거나 안드로이드 네이티브 기능을 쓸때는 별수 없이 cocos2d-x로 할 때보다는 이슈가 적지만 그래도 아예 없지는 않네요.

  해서 이번 포스팅은 안드로이드 JAR 프로젝트를 만들어 유니티3D 프로젝트에서 연동하는 것을 정리해봅니다. 이것을 유니티3D 안드로이드 플러그인 작업이라고 하네요.

 크게 2가지 방식이 있는 듯합니다. 첫번째로 이클립스 안드로이드 jar 프로젝트를 만들어 유니티3D에서 사용하는 방식과 유니티를 빌드후 이클립스 안드로이드 프로젝트용 jar로 만들어 이클립스에서 최종 빌드하는 방식이 있네요. 즉, 유니티3D가 주가 되느냐 이클립스가 주가 되느냐 인거죠. 이번 포스팅에서 첫번째 방식인 유니티3D가 주인 방식으로 진행합니다.

 작년에 cocos2d-x 맨 처음 작업할 때 했던 이클립스 설치부터 프로젝트 생성까지 다 정리하려면 지저분?하고 내용이 길어지니 기존에 포스팅 했던 것들은 링크로 대체합니다. 그리고 오해의 소지가 있을 듯한데요, cocos2d-x기반 안드로이드 프로젝트 + 유니티가 아닙니다. 그냥 안드로이드 JAR 프로젝트 + 유니티입니다.


1. 유니티3D 프로젝트 생성 및 플러그인 준비 작업

 유니티3D 프로젝트를 생성한 후 Assets 폴더에 Plugins\Android 폴더를 만들어줍니다. 이곳에 밑에서 만든 안드로이드 JAR lib를 넣어줘야합니다.


2. 유니티3D에서 안드로이드 자바로의 통신

using UnityEngine;
using System.Collections;

public class AndroidManager : MonoBehaviour
{
private AndroidJavaObject curActivity;
public string strLog = "No Java Log";
static AndroidManager _instance;
public static AndroidManager GetInstance()
{
if( _instance == null )
{
_instance = new GameObject("AndroidManager").AddComponent<AndroidManager>();  
}
return _instance;
}
void Awake()
{
///&lt; 현재 활성화된 액티비티 얻어와서 저장
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
curActivity = jc.GetStatic<AndroidJavaObject>("currentActivity");
}
void Start ()
{
}
public void CallJavaFunc( string strFuncName, string strTemp )
{
if( curActivity == null )
return;
///&lt; 액티비티안의 자바 메소드 호출
curActivity.Call( strFuncName, strTemp );
}
void SetJavaLog(string strJavaLog)
{
strLog = strJavaLog;
}
}
 안드로이드 자바와의 통신을 담당할 AndroidManager라는 싱글톤 클래스입니다. 기존에 정리했던 싱글톤보다는 다소 간소화된 녀석이죠. 자바와 통신을 할때는 유니티 게임오브젝트로 등록된 객체가 있어야만 그 객체를 찾아 메세지를 주고 받을 수 있습니다.


 유니티에서 만들어놓은 com.uniti3d.player.UnityPlayer 안드로이드 자바 클래스를 통해서 현재 활성화된 액티비티를 AndroidJavaObject 형으로 얻어와야 합니다.

 그리고 cocos2d-x에서 jni를 가지고 native code인 c++과 java 양방향 통신을 했던 것처럼 C#에서 자바로 메세지를 보낼때는 AndroidJavaObject형 액티비티의 Call 메서드를 활용합니다. 자바 메소드가 static이라면 CallStatic를 사용합니다. 간단히 메소드의 이름과 스트링 파라메터 한개를 보내게 해놨습니다. 파라메터는 몇개든 추가할 수 있는 것 같습니다. 자바와 인터페이스만 맞추면요.

 그외에도 AndroidJNI, AndroidJNIHelper 라는 것도 보이네요. 이것으로도 가능해 보이지만 이번 포스팅에서는 패스합니다.

 마지막 SetJavaLog는 자바에서 보낸 메세지 테스트용입니다. 단순히 스트링만 하나 받아서 로그 출력용 멤버변수에 저장을 합니다.


using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class TestGUI : MonoBehaviour
{
// Update is called once per frame
void Update ()
{
if (Application.platform == RuntimePlatform.Android)
        {

            if (Input.GetKey(KeyCode.Escape))
            {
                Application.Quit();
                return;
            }
}
}

void OnGUI()
{
GUI.Label(new Rect(0, 0, 100, 100), AndroidManager.GetInstance().strLog);

if (GUI.Button (new Rect(0, 100, 100, 100), "TestButton") == true)
{
AndroidManager.GetInstance().CallJavaFunc( "javaTestFunc", "UnityJavaJarTest" );
}
}

자바와 통신이 잘 되고 있는지 확인하기 위한 TestGUI.cs 파일입니다. TestButton을 누를 때 AndroidManager 내부 함수에 의해 javaTestFunc 라는 메소드를 호출합니다. 인자로 UnityJavaJarTest 라는 스트링을 넘기구요.

 OnGUI에서는 통신 확인을 위해 AndroidManager의 로그 스트링을 가져와 라벨로 출력만 해줍니다.


3. 이클립스 JAR 프로젝트 생성


 유니티3D와 연동할 안드로이드 프로젝트를 생성해야합니다. 이클립스로 안드로이드 JAR lib 프로젝트를 하나 생성합니다. 저는 UnityAndroidJarTest, 패키지명은 com.Test.unityandroidjartest, Activity는 MainActivity 라고 만들었습니다.

4. classes.jar 파일 임포트
 Android용 UnityPlayer관련 된 기능을 자바에서 사용하기 위해 classes.jar 파일임포트해줍니다.

5. 안드로이드 자바에서 유니티3D로의 통신

package com.Test.unityandroidjartest;

import android.os.Bundle;

import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;

public class MainActivity extends UnityPlayerActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  //setContentView(R.layout.activity_main);
 }

 public void javaTestFunc(String strFromUnity) {
  UnityPlayer.UnitySendMessage("AndroidManager", "SetJavaLog", strFromUnity + "HelloWorld");
 }
}

 기본적으로 Activity를 상속받게 되어있는데 위와 같이 UnityPlayerActivity를 상속받게 수정합니다. 그와 관련된 것들도 import 해주고요. 마지막으로 setContentView는 삭제하시기 바랍니다.

 유니티3D에서는 UnitiPlayer.UnitySendMessage를 통해서 자바에서 c#으로 메세지를 보낼 수 있습니다. 첫 인자로 유니티3D 게임오브젝트명, 2번째는 호출할 함수명, 3번째는 보낼 스트링 매개변수입니다. 유니티3D에서 자바로 보낼때와는 다르게 파라미터의 갯수는 제한되어 있습니다. 게임오브젝트명, 함수명을 빼면 스트링으로 한개만 보낼 수 있는거죠.

 간단히 javaTestFunc는 C#에서 날라온 strFromUnity 문자열에 HelloWorld를 더 붙여서 다시 유니티3D에 문자열을 보내주는 간단한 기능입니다.


6. 안드로이드 플러그인 익스포트 및 복사

 작업중인 안드로이드 플러그인 프로젝트를 JAR로 Export해야합니다. 익스포트시 필요한 부분은 src 폴더입니다. 지금은 심플해서 저것만 필요한 것인지는 잘 모르겠으나 일단 최상단 체크박스를 한분 클릭해서 풀어주고 src만 체크하고 익스포트해줍니다. 여러번 테스트해봤는데 src만 일단 있으면 되더군요.

 그리고 제일 처음에 만들었던 유니티3D 프로젝트의 Assets\Plugins\Android 폴더에 생성된 jar파일을 복사해줍니다. 또는 아예 Export할 때 위치를 이곳으로 지정해도 좋구요.

 그리고 안드로이드 프로젝트의 AndroidManifest.xml을 역시 같은 폴더에 복사해줍니다.


7. AndroidManifest.xml 수정

<application
        android:allowBackup="true"
        android:icon="@drawable/app_icon"
        android:label="@string/app_name" >
        <activity
            android:name="com.Test.unityandroidjartest.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

 복사한 AndroidManifest.xml을 수정해줘야합니다. icon이 기본적으로 drawable/ic_launcher 로 되어있을 것입니다. 위와같이 drawable/app_icon 으로 해줘야 유니티3D에서 인식합니다. 그리고 android:theme="@style/AppTheme" 라는게 있다면 삭제하시면 됩니다.


8. 빌드 및 실행

 Build Settings -> Android 플랫폼의 Player Settings에서 Bundle Identifier를 이클립스 안드로이드 프로젝트의 패키지 이름과 왠만하면 같게해주시고 빌드합니다. 다르게 해도 빌드 후 실행하는데는 문제가 없더군요. 여러 앱이 생성될 뿐.

 유니티에서 빌드하고 apk를 폰에 설치해서 스샷을 찍어봤습니다. 유니티에서 "UnitiJavaJarTest"를 보내고 자바에서 받아 "HelloWorld"를 붙여서 다시 유니티로 보내서 찍힌 상황인거죠.

 마지막으로, 이클립스딴 안드로이드 소스가 수정이 되면 다시 jar파일로 익스포트해주고 유니티에서 빌드해서 apk를 생성해줘야합니다. 그리고 만든 안드로이드 플러그인 프로젝트에 외부 SDK라도 연동하실때 AndroidMenifest.xml도 수정이 가해질텐데 이때도 또 유니티쪽에 복사해주셔야합니다.

 이렇게 간단하게 자바와 C#간에 통신을 정리했습니다. cocos2d-x에서 제가 따로 프레임워크를 jar로 만들거나 외부 sdk를 연동했던 것과 작업 스타일이 비슷해 보이기도 하네요. 단지 엔진이 조금 다르고 그에따른 api 사용이 다를뿐이죠. cocos2d-x때도 JNI처리하는데 있어 GLThread쪽에 이슈가 있었듯이 유니티3D도 아마 추가적으로 처리해야지 싶네요. 이건 나중에 이슈 발생시 정리해보도록 하겠습니다.

이 블로그의 인기 게시물

Unity3D Prime31 처럼 자신만의 안드로이드 플러그인을 만들어보자

CMake Windows에 설치하기

Unity3D iOS Plugin 만들어 연동하기