티스토리 뷰

Programming/Unity3D

Unity3D - Android 연동

파란크리스마스 2013. 9. 6. 10:22
728x90

출처 : 안드로이드(Android) 유니티(Unity3D) 연동 ,값전달, Toast, Dialog 등...
[android] 메시지 핸들러(Handler) 사용하기
[안드로이드] 유니티 C# 클래스와 자바 클래스간의 연동
Trying to create a simple AlertDialog plugin, crash occurs
Platform Dependent Compilation
20. 카드 짝찾기 게임(7) - 안드로이드용으로 변환 (Keystore 사용 빌드)

Unity에서 Android Activity와 연동하기 위해 Unity C# 소스 작성

Unity의 AndroidJavaObject 객체를 이용해서 Android에 호출하고 호출한 결과값은 바로 받을 수 없어 로직이 끝나고 다시 Android Activity에서 Unity C# 함수를 호출해서 결과 값을 받을 수 있습니다.

아래 예제는 Cs_CubeManager을 싱글톤 객체로 만들어서 AndroidJavaObject 객체를 Unity 전체에서 사용하도록 했으며, Cs_AndroidManager에서 AndroidJavaObject 객체를 할당 받도록 했습니다.

Android호출시 다른 Activity를 생성하거나 Toast 메시지 출력시 아래와 같이 오류가 발생하므로 Handle 사용해야 합니다.

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

개발시나 iOS에서는 동작하지 않도록 preprocessor로 UNITY_ANDROID를 사용하여, Android에서만 동작할 수 있도록 소스작성 합니다.

#if UNITY_ANDROID 
    // 유니티가 동작하는 액티비티를 저장하는 변수.
    public AndroidJavaObject activity = null;
#endif	

Android Activity와 연동하기 위해서 C# AndroidJavaObject 객체를 아래와 같이 할당 받아야 합니다.

AndroidJavaObject activity = null;

AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
cubeMng.activity = jc.GetStatic<AndroidJavaObject>("currentActivity");

AndroidJavaObject 객체의 Call 메소드를 호출 하여 Android Activity의 메소드를 호출합니다.

	public void NativeAlert(string message) {
#if UNITY_ANDROID 
    // 유니티가 동작하는 액티비티를 저장하는 변수.
    	activity.Call("AlertMessage", message);
#endif			
	}

Cs_AndroidManager.cs

using UnityEngine;

public class Cs_AndroidManager : MonoBehaviour {
	
    //private static Cs_AndroidManager _instance = null;
	
	private Cs_CubeManager cubeMng;

    public string androidLog = "No Log";
	
    void Start() {				
		cubeMng = Cs_CubeManager.getInstance();
		cubeMng.device_model = "test";		
#if UNITY_ANDROID
		AndroidCall();
#endif		
	}
	
#if UNITY_ANDROID 
    // 유니티가 동작하는 액티비티를 저장하는 변수.
    //public AndroidJavaObject activity = null;

    void AndroidCall()
    {
        // 현재 실행 중인 유니티 액티비티를 가져와서 변수에 저장.
        //AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
		AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        cubeMng.activity = jc.GetStatic<AndroidJavaObject>("currentActivity");
		cubeMng.activity.Call("initActivity", "Cs_AndroidManager");
    }
#endif	

    // 자바 클래스로부터 전달받은 로그를 보여줍니다.
    public void AndroidLog(string newAndroidLog) {
        androidLog = newAndroidLog;
    }
	
	public void SetCountryCode(string code) {
		cubeMng.country_code = code;
	}
	
	public void SetDeviceID(string did) {
		cubeMng.device_id = did;
	}
	
	public void SetDeviceModel(string dModel) {
		cubeMng.device_model = dModel;
	}	
	
	/*
    public static Cs_AndroidManager Instance
    {
        get
        {
            if (_instance == null)
            {
				
				Debug.Log("------------- _instance.0 = " + _instance);
				
                _instance = FindObjectOfType(typeof(Cs_AndroidManager)) as Cs_AndroidManager;
				
				Debug.Log("------------- _instance.1 = " + _instance);
				
                if (_instance == null)
                {
                    _instance = new GameObject("Cs_AndroidManager").AddComponent<Cs_AndroidManager>();
                }
				
				Debug.Log("------------- _instance.2 = " + _instance);
            }

            return _instance;
        }
    }
    */
}

Cs_CubeManager.cs

using UnityEngine;
using System;

public class Cs_CubeManager {
	
	// 싱글톤 인스턴스 
	private static Cs_CubeManager instance = null;
	
	public string country_code = "KOR";
	
	public string device_id = "";
	
	public string device_model = "";	
	
#if UNITY_ANDROID 
    // 유니티가 동작하는 액티비티를 저장하는 변수.
    public AndroidJavaObject activity = null;
#endif	

	private Cs_CubeManager() {
/*
		if (Camera.mainCamera != null && Camera.mainCamera.GetComponent("WWWWiki") != null)
			wWWWiki = Camera.mainCamera.GetComponent("WWWWiki") as WWWWiki;
*/
	}
	
	public static Cs_CubeManager getInstance() {
		if (instance == null) {
			instance = new Cs_CubeManager();
		}
		return instance;
	}
		
	public void NativeAlert(string message) {
#if UNITY_ANDROID 
    // 유니티가 동작하는 액티비티를 저장하는 변수.
    	activity.Call("AlertMessage", message);
#endif			
	}	
}

Unity3D 에서 Android 소스로 Export 하기

1. 메뉴 [Build Settings...] 선택합니다.

2. [Build Settings] 화면에서 Platform 목록에서 Android 항목을 선택합니다.

3. Bundle Identifier에 Android에서 사용할 Package 명을 입력합니다.

4. 다시 [Build Settings] 화면에서 Create Eclipse project 체크 박스를 선택하고, 버튼 [Export]을 선택합니다.

5. Export 받을 경로를 선택하고, 버튼 [폴더 선택]을 선택합니다.

6. 탐색기로 아래와 같이 Export 받은 파일 목록을 확인 합니다.

파일 목록에서 classes.jar 파일을 확인 할 수 있는데,
C:\Program Files (x86)\Unity\Editor\Data\PlaybackEngines\androidplayer\bin 폴더의 classes.jar 파일과 동일한 파일로
Unity에서 Export 받으면 자동으로 classes.jar 파일을 복사해서 빌드 라이브러리에 자동으로 추가 됩니다.

7. [Package Explorer] 에서 오른쪽 버튼을 선택해서, 팝업 메뉴에서 메뉴 [Import...]를 선택합니다.

8. 메뉴 [Existing Projects into Workspace]를 선택합니다.

9. 버튼 [Browse...]을 선택합니다.

10. Unity에서 Export 받은 폴더를 선택합니다.

11. 버튼 [Finish]을 선택합니다.

12. Import 된 파일 목록을 확인합니다.

Android 소스 작성

Unity에서 Export 받은 소스에는 UnityPlayerActivity 를 상속 받지 않아서,
UnityPlayerActivity 겍체를 상속 받아 CubeMainActivity 소스를 작성하고, AndroidManifest.xml에서 Main Activity를 CubeMainActivity 수정했습니다.

Unity에서 호출 받은 로직을 처리하기 위해서 Handler 상속 받아서 Unity3DHandler.java 소스를 작성합니다.

CubeMainActivity.java

package com.azanghs.cube;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Message;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;
import android.util.Log;

import com.example.android.trivialdrivesample.util.IabHelper;
import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;

public class CubeMainActivity extends UnityPlayerActivity {
	
	private static String TAG = CubeMainActivity.class.getSimpleName();
	
	private TelephonyManager m_telephonyManager;
	
	String androidId = "KOR";	
	
    // The helper object
    IabHelper mHelper;
    
    private Unity3DHandler handler = null;
    
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       handler = new Unity3DHandler(this);

       m_telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
     
       Log.i(TAG, "Build.MODEL = " + Build.MODEL);
       Log.i(TAG, "Build.DEVICE = " + Build.DEVICE);
       Log.i(TAG, "Build.PRODUCT = " + Build.PRODUCT);
   }
   
	@Override
	public void onBackPressed() {
		this.finishMessage();
	}
	
	public void QuitApplication() {
		handler.sendEmptyMessage(0);
	}
	
	public void AlertMessage(final String message) {
		Message msg = handler.obtainMessage(1);
		msg.obj = message;
		handler.sendMessage(msg);
	}
	
	public void finishMessage() {
		new AlertDialog.Builder(this).setMessage("프로그램을 종료하시겠습니까?")
		.setPositiveButton("확인", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int whichButton) {
				//System.exit(0);
				UnityPlayer.UnitySendMessage("GameObject", "FinishApp", "");
			}
		}).setNegativeButton("취소", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int whichButton) {
			}
		}).show();	
	}

   //요 부분입니다. 이걸... Thread가 불필요하다면 
   public void initActivity(final String messageFromUnity)
   {
	   
	   Log.i(TAG, "여기 호출 Build.MODEL = " + Build.MODEL);
	   
       UnityPlayer.UnitySendMessage("GameObject", "SetCountryCode", getResources().getConfiguration().locale.getISO3Country());
       UnityPlayer.UnitySendMessage("GameObject", "SetDeviceModel", Build.MODEL);       

       // 디바이스 ID
       String androidId = Secure.getString(getContentResolver(), Secure.ANDROID_ID);       
       UnityPlayer.UnitySendMessage("GameObject", "SetDeviceID", androidId);
	   
       //
       //UnityPlayer.UnitySendMessage("Cs_AndroidManager", "AndroidLog", "4/[" + tagFromUnity + "]" + messageFromUnity);
   }

   public void alert(String message) {
       AlertDialog.Builder bld = new AlertDialog.Builder(this);
       bld.setMessage(message);
       bld.setNeutralButton("OK", null);
       Log.d(TAG, "Showing alert dialog: " + message);
       bld.create().show();
   }  
}

Unity3DHandler.java

package com.azanghs.cube;

import android.os.Handler;
import android.os.Message;

public class Unity3DHandler extends Handler {
	
	private CubeMainActivity mainActivity = null;
	
	public Unity3DHandler(CubeMainActivity mainActivity) {
		this.mainActivity = mainActivity;
	}
	
	public void handleMessage(Message msg) {
		switch (msg.what) {
		case 0:
			mainActivity.finishMessage();
			break;
		case 1:
			mainActivity.alert((String)msg.obj);
			break;			
		default:
			break;
		}		
	}
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="preferExternal" android:theme="@android:style/Theme.NoTitleBar" package="com.azanghs.cube" android:versionName="1.0" android:versionCode="1">
  <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:anyDensity="true" />
  <application android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="false">
    <activity android:name=".CubeMainActivity" android:launchMode="singleTask" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|uiMode|touchscreen" android:screenOrientation="portrait">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>       
    <!--       
    <activity android:name="com.azanghs.cube.CubeProxyActivity" android:launchMode="singleTask" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:screenOrientation="portrait">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    <activity android:name="com.azanghs.cube.CubeActivity" android:launchMode="singleTask" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:screenOrientation="portrait">
    </activity>
    <activity android:name="com.azanghs.cube.CubeNativeActivity" android:launchMode="singleTask" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:screenOrientation="portrait">
      <meta-data android:name="android.app.lib_name" android:value="unity" />
      <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="false" />
    </activity>
    -->
  </application>
  <uses-feature android:glEsVersion="0x00020000" />
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-feature android:name="android.hardware.touchscreen" />
  <uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="false" />
  <uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" android:required="false" />
  <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="17" />
</manifest>

Android 프로젝트를 Unity Plugin Jar로 Export 하기

1. 해당 프로젝트를 선택하고 메뉴 [Export...] 선택합니다.

2. 메뉴 [JAR file] 선택합니다.

3. 아래와 같이 선택합니다.
Jar 파일이 생성되는 파일 경로 Unity 소스 폴더의 %소스경로%\Assets\Plugins\Android 로 합니다. (변경불가)

4. 버튼 [Next >] 버튼 선택합니다.

5. 버튼 [Finish] 버튼 선택합니다.

6. Unity에서 Build 하면 Android 폰에 실행된 결과를 확인 할 수 있습니다.

- 설명 작성하려니 귀찬니즘이 발생해서 나중에 시간이 나면 다시 작성하도록 하겠음

댓글
300x250
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/03   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함