찾기
내용으로 건너뛰기
추적
문서의 이전 판을 선택했습니다!
저장하면 이 자료로 새 판을 만듭니다.
미디어 파일
======안드로이드를 위한 플러그인 만들기 Building Plugins for Android====== 이 페이지는 안드로이드를 위한 [[Plugins|네이티브 코드 플러그인 Native Code Plugins]]들을 설명합니다. =====안드로이드 플러그인 빌드하기 Building a plugin for Android===== 안드로이드 플러그인을 시작하려면 [[http://developer.android.com/sdk/ndk|Android NDK]]가 필요합니다. 어떻게 공유 라이브러리를 만드는지에 익숙해 지세요. 플러그인을 만드는데 C++ (.cpp)를 사용한다면 [[http://en.wikipedia.org/wiki/Name_mangling|name mangling issues]]를 피하기 위해 함수가 C linkage와 선언되야 합니다. <file csharp>extern "C" { float FooPluginFunction (); } </file> =====C#에서 플러그인 사용하기===== 일단 공유 라이브러리를 만들면 그것을 **Assets->Plugins->Android** 폴더에 복사합니다. 유니티는 아래와 같은 함수를 정의할때 이름으로 그것을 찾을 것입니다: <file csharp>[DllImport ("PluginName")] private static extern float FooPluginFunction (); </file> //PluginName//은 ‘lib’로 시작하거나 ‘.so’ 로 끝이나면 안되는 것을 명심하세요. 모든 기본 코드 함수를 추가적인 C#코드 레이어로 감싸기를 권합니다. 이 코드는 [[ScriptRef:Application-platform.html| Application.platform]] 를 체크할 수 있고 실제 장치에서 실행될 때만 기본 함수를 부르며 에이터에서 실행될 때는 모의 값을 리턴합니다. 사용자는 플랫폼에 의존하는 코드 컴파일을 제어하기 위해 [[http://docwiki.unity3d.com/index.php?n=KrMain.PlatformDependentCompilation|platform defines]] 를 사용할 수 있습니다. =====배치===== 크로스 플랫폼 플러그인을 위해서는 플러그인 폴더가 몇가지 다른 플랫폼(즉libPlugin.so 는Android, Plugin.bundle 는 Mac 그리고 Plugin.dll 는 Windows)을 위한 플러그인을 포함합니다. 유니티가 자동으로 개발 플랫폼에 맞는 플러그인을 선택하고 플레이어에 포함합니다. =====자바 플러그인 사용하기===== 안드로이드 플러그인 메카니즘은 또한 안드로이드 OS와 상호작용을 가능하게 하는데 자바가 사용되는 것을 허용합니다. 자바 코드는 C#에서 직접 불릴 수 없으으로 사용자가 C#와 자바사이에서 그 콜을 해석하기 위해 기본 플러그인을 작성 합니다. ====안드로이드에서 자바 플러그인 빌드하기==== 자바 플러그인을 만드는 것에는 몇가지 방법이 있습니다. 공통점은 필러그인에 필요한 .class 파일들을 포함하는 .jar파일로 끝난다는 것입니다. 한가지 방법은 [[ http://www.oracle.com/technetwork/java/javase/downloads/index.html|JDK ]]를 받는 것으로 시작해서 사용자 .java파일을 명령 라인에서 javac로 .class파일을 만들기 위해 컴파일 하고 그들을 jar 명령어 라인 툴을 이용해 .jar로 패기지화합니다. 다른 방법은 [[ http://www.eclipse.org|Eclipse ]] IDE를 [[ http://developer.android.com/sdk/eclipse-adt.html|ADT ]]와 함께 사용하는 것입니다. ====기본 코드에서 자바 플러그인 사용하기==== 일단 자바 플러그인(.jar)을 만들었으면 **Assets->Plugins->Android** 폴더로 복사해야 합니다. 유니티는 .class파일과 나머지 자바 코드를 패키지화하고 [[ http://en.wikipedia.org/wiki/Java_Native_Interface|Java Native Interface (JNI) ]]라는 것으로 그것을 부릅니다. JNI는 두가지 방법으로 동작하는데; 자바에서 기본 코드 부르기 그리고 기본 코드에서 자바(또는 JavaVM)와 상호작용하기. 기본 코드에서 사용자 자바 코드를 찾기 위해서는 자바 VM에 액세스 해야합니다. 다행히 그것은 매우 쉬운데 사용자의 C(++)코드에 다음과 같은 함수를 추가합니다: <file csharp>jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* jni_env = 0; vm->AttachCurrentThread(&jni_env, 0); } </file> 이것이 C(++)에서 자바를 이용하기 전부 입니다. JNI에 대한 완전히 설명하는 것은 이 문서의 내용을 넘어선 것이지만 클래스 정의 찾기, 생성자 (<init>) 함수 해결하기 그리고 아래와 같이 새로운 객체 인스턴스 만들기 등을 포함합니다: <file csharp>jobject createJavaObject(JNIEnv* jni_env) { jclass cls_JavaClass = jni_env->FindClass("com/your/java/Class"); // find class definition jmethodID mid_JavaClass = jni_env->GetMethodID (cls_JavaClass, "<init>", "()V"); // find constructor method jobject obj_JavaClass = jni_env->NewObject(cls_JavaClass, mid_JavaClass); // create object instance return jni_env->NewGlobalRef(obj_JavaClass); // return object with a global reference } </file> ====헬퍼 클래스와 사용자 자바 플러그인 만들기==== ''AndroidJNIHelper''와 ''AndroidJNI'' 는 JNI사용을 쉽게해 줍니다. ''AndroidJavaObject''와 ''AndroidJavaClass'' 는 많은 것을 자동화해주고 캐쉬를 사용해서 자바 콜을 빠르게 해줍니다. ''AndroidJavaObject''와 ''AndroidJavaClass'' 조합은 ''AndroidJNI'' 와 ''AndroidJNIHelper'' 위에서 만들어 지고 그 안에 많은 로직이 있습니다(자동화를 다루는). 이런 클래스틀은 자바 클래스의 정적 멤버를 다루기 위해 ‘static’ 버전으로도 있습니다. 사용자가 원하는 어떤 방법을 사용해도 되지만JNI 와 ''AndroidJNI'' 클래스 멤버 또는 ''AndroidJNIHelper'' 와 ''AndroidJNI'' 그리고 결국 최대 자동화와 편의를 위해 ''AndroidJavaObject/AndroidJavaClass'' 를 이용하세요. * [[ScriptRef:AndroidJNI.html|UnityEngine.AndroidJNI]]는 C에 있는 JNI콜을 위한 wrapper입니다. 이 클래스의 모든 멤버는 static이며 Java Native Interface와 일대일 관계를 갖습니다. * [[ScriptRef:AndroidJNIHelper.html|UnityEngine.AndroidJNIHelper]]는 다음 레벨에서 사용 되는 헬퍼 기능을 제공하지만 아마 어떤 특별한 이유로 유용할 수 있기 때문에 public 함수로 사용 됩니다. * [[ScriptRef:AndroidJavaObject.html|UnityEngine.AndroidJavaObject]] 와 [[ScriptRef:AndroidJavaClass.html|UnityEngine.AndroidJavaClass]] 의 인스턴스는 각각 java.lang.Object 와java.lang.Class (또는 서브클래스)의 인스턴스와 일대일 매핑이 됩니다. 그들은 자바와 3가지 타입의 상호작용을 제공합니다: * 함수 콜하기 * 필드 값 얻기 * 필드 값 지정하기 ''Call''은 두가지 타입이 있습니다: 'void' ''Call'' 타입과 non-void return ''Call'' 타입이 있습니다. void타입이 아닌 콜은 리턴 타입으로 generic 타입이 사용됩니다. ''Get/Set'' 은 항상generic 타입만을 취합니다. ====Example 1==== <file csharp> //The comments is what you would need to do if you use raw JNI AndroidJavaObject jo = new AndroidJavaObject("java.lang.String", "some_string"); // jni.FindClass("java.lang.String"); // jni.GetMethodID(classID, "<init>", "(Ljava/lang/String;)V"); // jni.NewStringUTF("some_string"); // jni.NewObject(classID, methodID, javaString); int hash = jo.Call<int>("hashCode"); // jni.GetMethodID(classID, "hashCode", "()I"); // jni.CallIntMethod(objectID, methodID); </file> 여기서는 [[http://developer.android.com/reference/java/lang/String.html|java.lang.String]]의 인스턴스를 만들고 있으며 [[hhttp://developer.android.com/reference/java/lang/String.html#String(java.lang.StringBuilder)string]] 초기화하고 그 스트링을 위해 [[http://developer.android.com/reference/java/lang/String.html#hashCode()|hash value]]를 되찾습니다. ''AndroidJavaObject'' 생성자는 적어도 하나의 파라미터를 취합니다: 인스턴스를 생성하고자 하는 클래스의 이름. 클래스 이름 뒤에 있는 것은 모두 객체의 생성자 콜을 위한 파라미터이며 이 경우 스트링은 "some_string". 그러면 ''Call'' 함수에서 왜 generic타입을 파라미터로 사용하는 지에 대한 이유인 int를 리턴하는 hashCode()를 사용합니다. _주의:_ dotted notation 를 사용해서 중첩 자바 클래스를 인스턴스화 할 수 없습니다. 내부 클래스는 $ 분별자를 사용해야하며 이것은 점과 슬래스 형식에서 모두 작동할 것입니다. 그래서 ''LayoutParams'' 클래스가ViewGroup 클래스가 중첩되었을 때$$android.view.ViewGroup$LayoutParams'' 또는''android/view/ViewGroup$LayoutParams'' 가 사용될 수 있습니다. ====Example 2==== 위 샘플 플러그인중 하나는 어떻게 현 프로그램을 위한 캐쉬 디렉토리를 얻을 수 있는지를 보여줍니다: <file csharp> AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); // jni.FindClass("com.unity3d.player.UnityPlayer"); AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity"); // jni.GetStaticFieldID(classID, "Ljava/lang/Object;"); // jni.GetStaticObjectField(classID, fieldID); // jni.FindClass("java.lang.Object"); Debug.Log(jo.Call<AndroidJavaObject>("getCacheDir").Call<string>("getCanonicalPath")); // jni.GetMethodID(classID, "getCacheDir", "()Ljava/io/File;"); // or any baseclass thereof! // jni.CallObjectMethod(objectID, methodID); // jni.FindClass("java.io.File"); // jni.GetMethodID(classID, "getCanonicalPath", "()Ljava/lang/String;"); // jni.CallObjectMethod(objectID, methodID); // jni.GetStringUTFChars(javaString); </file> 여기서는 of ''AndroidJavaObject'' 대신 ''AndroidJavaClass'' 로 시작하는데 왜냐하면 사용자가 ''com.unity3d.player.UnityPlayer''의 static멤버의 액세스를 원하며 새로운 객체 생성을 윈치 않습니다(이미 ''Android UnityPlayer''에 하나가 만들어져 있습니다). 그러면 static필드인 “currentActivity”에 액세스하지만 이번에는 generic파라미터로 ''AndroidJavaObject'' 를 사용합니다. 왜냐하면 실제 필드 타입 ([[http://developer.android.com/reference/android/app/Activity.html| android.app.Activity]])이 [[http://developer.android.com/reference/java/lang/Object.html|java.lang.Object]] 위 하위 클래스이기 때문이고 어떤 [[http://developer.android.com/reference/java/lang/Class.html|non-primitive type]]도 ''AndroidJavaObject'' (이 룰에 스트링은 예외인데 자바에서 primitive타입이 아니라도 스트링이 직접 액세스 될수 있습니다)로 액세스 되어야 하기 때문입니다. 그런 후 캐쉬 디렉토리를 대표하는 File객체를 얻기위해 이제 [[http://developer.android.com/reference/android/content/Context.html#getCacheDir()| getCacheDir()]]를 통해 간단히 ''Activity''를 이동하고 스트링 표현을 얻기위해 [[http://developer.android.com/reference/java/io/File.html#getCanonicalPath()| getCanonicalPath()]]를 부르세요. 물론 요즘엔 캐쉬 디렉토리를 얻기위해 그럴 필요가 없습니다; 저희는 [[ScriptRef:Application-temporaryCachePath.html|Application.temporaryCachePath]], [[ScriptRef:Application-persistentDataPath.html| Application.persistentDataPath]]를 통해 프로그램의 캐쉬와 파일 디렉토리 액세스를 제공합니다. ====Example 3==== 마지막으로 ''UnitySendMessage''를 사용해 어떻게 데이타를 자바에서 스크립트 코드로 보내는지에 대한 작은 트릭입닌다. <file csharp> using UnityEngine; public class NewBehaviourScript : MonoBehaviour { void Start () { JNIHelper.debug = true; using (JavaClass jc = new JavaClass("com.unity3d.player.UnityPlayer")) { jc.CallStatic("UnitySendMessage", "Main Camera", "JavaMessage", "whoowhoo"); } } void JavaMessage(string message) { Debug.Log("message from java: " + message); } } </file> 자바 클래스인 ''com.unity3d.player.UnityPlayer''은 이제 static 함수인 UnitySendMessage를 가지며 이것은 iOS의 [[KrMain.Plugins#iPhonePlugins| UnitySendMessage]] 와 같고 자바에서 스크립트 코드로 데이터를 보낼 때 쓸수 있습니다. 그러나 여기서 우리는 그것을 스크립트 코드에서 직접 부릅니다. 그것은 결국 자바쪽으로 메세지를 전달하며 자바쪽에서는 “JavaMessage”라는 함수가 있는 “Main Camera”이라는 이름의 객체에 메세지 전달을 위해 유니티에서 콜백 합니다. ====유니티에서 자바 플러그인을 사용하는 가장 좋은 방법들==== 이 섹션은 주로JNI, Java, 안드로이드 경험이 많지 않은 사람을 목표로 했기에 우리는AndroidJavaObject/AndroidJavaClass 접근이 유니티 자바 코드와 상호작용 한다고 가정합니다. 첫번째로 알아야 할것은 AndroidJavaObject / AndroidJavaClass에서의 모든작업은 비싸다는 것입니다(JNI접근 처럼). managed와 native/java사이의 변환을 최소화 하기를 권합니다. 이것은 성능과 복잡도 모두를 위한 것입니다. 기본적으로 자바 함수가 실제 모든 작업을 하게하고 AndroidJavaObject / AndroidJavaClass를 이용해 그 함수와의 대화를 통해 결과를 얻을 수 있습니다. JNI헬퍼 클래스로 가능한 많은 양을 캐쉬하려 한다는 것을 아는 것은 도움이 될 것입니다. <file csharp> //The first time you call a Java function like AndroidJavaObject jo = new AndroidJavaObject("java.lang.String", "some_string"); // somewhat expensive int hash = jo.Call<int>("hashCode"); // first time - expensive int hash = jo.Call<int>("hashCode"); // second time - not as expensive as we already know the java method and can call it straight </file> 이것은 JIT와 같은 방법입니다: 그것을 처음에 콜할 때는 코드가 존재하지 않아 느릴 것입니다. 다음에는 빨라집니다. 다시 말해 모든 객체의 ''.Call /.Get / .Set''마다 대가를 치뤄야하지만 처음으로 콜한 다음에는 대가가 적다는 말입니다. ''AndroidJavaClass / AndroidJavaObject''를 생성하는 데도 대가가 따릅니다. Mono garbage collector는 ''AndroiJavaObject / AndroidJavaClass''의 생성된 모든 인스턴스를 해제해야 하는데 그것을 ''using(){} '' 문에 두고 가능한 빨리 지워지도록 하기를 권합니다. 그렇지 않으면 그들이 언제 지워질지 장담할 수 없습니다. ''AndroidJNIHelper.debug = true;'' 를 설정하면 디버그 출력문이Garbage Collector의 행동도 보여줄 것입니다. <file csharp> //Getting the system language with the safe approach void Start () { using (AndroidJavaClass cls = new AndroidJavaClass("java.util.Locale")) { using(AndroidJavaObject locale = cls.CallStatic<AndroidJavaObject>("getDefault")) { Debug.Log("current lang = " + locale.Call<string>("getDisplayLanguage")); } } } </file> 사용자는 또한 자바 객체lingering을 없게 하기위해 ''.Dispose()$$ 함수를 직접 부를수 있습니다. 실제 C# 객체는 좀더 오래 존재할 수있는데 mono에 의해 결국 가비지 콜렉트될 것입니다. =====UnityPlayerActivity 자바 코드 확장하기===== 유니티 안드로이드는UnityPlayerActivity(안드로이드 유니티 플레이어 주요 자바 클래스, 유니티 iOS의AppController.mm와 비슷함)의 확장이 가능합니다. UnityPlayerActivity (UnityPlayerActivity.java는 맥의 **/Applications/Unity/Unity.app/Contents/PlaybackEngines/AndroidPlayer/src/com/unity3d/player** 그리고 보통 C:\Program Files\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\src\com\unity3d\player에서 찾을 수 있습니다)에서 유도된 새로운[[ http://developer.android.com/reference/android/app/Activity.html|Activity ]] 를 생성 함으로써 프로그램은 안드로이드 OS와 유니티 안드로이드의 어떤 또는 모든 기본 상호작용을 오버라이드할 수 있습니다. 그렇게 하기 위해서는 유니티 안드로이드에 있는 **classes.jar**를 찾습니다. 이것은 **PlaybackEngines/AndroidPlayer/bin**라고 불리는 설치 폴더(윈도우즈에서는 보통**/Applications/Unity** 그리고 맥에서는**/Applications/Unity**)에서 찾을 수 있습니다. 그러면 **classes.jar** 파일을 새로운 활동을 컴파일하는 classpath에 추가합니다. manifest이 어떤 활동이 시작되어야 하는지 나타내듯이 새로운 [[ http://developer.android.com/guide/topics/manifest/manifest-intro.html|AndroidManifest.xml ]]의 생성 또한 필요합니다. 그 AndroidManifest.xml 또한**Assets->Plugins->Android**에 위치하여야 합니다. 그 새로운 활동은 _OverrideExample.java_처럼 보일 수 있습니다: <file csharp>package com.company.product; import com.unity3d.player.UnityPlayerActivity; import android.os.Bundle; import android.util.Log; public class OverrideExample extends UnityPlayerActivity { protected void onCreate(Bundle savedInstanceState) { // call UnityPlayerActivity.onCreate() super.onCreate(savedInstanceState); // print debug message to logcat Log.d("OverrideActivity", "onCreate called!"); } public void onBackPressed() { // instead of calling UnityPlayerActivity.onBackPressed() we just ignore the back button event // super.onBackPressed(); } } </file> 그리고 이것은 매치하는 _AndroidManifest.xml_ 을 보여줍니다: <file csharp><?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.company.product"> <application android:icon="@drawable/app_icon" android:label="@string/app_name"> <activity android:name=".OverrideExample" 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> </manifest> </file> ====유니티 플레이어 네이티브 활동 UnityPlayerNativeActivity==== 물론 사용자만의 ''UnityPlayerNativeActivity''의 서브클래스를 만드는 것도 가능합니다. 이것은 UnityPlayerNativeActivity 를 서브클래스화하는 것과 비슷한 효과를 가질 것이나 더 개선된 인풋 대기 시간을 보여줄 것입니다. 다만 NativeActivity는 Gingerbread에서 도입되었기 때문에 다른 이전 기기들에서는 작동하지 않습니다. 터치/모션 이벤트들이 네이티브 코드에서 처리되기 때문에, 자바 뷰는 일반적으로 그 이벤트들을 보지 못할 것입니다. 하지만 유니티에는 forwarding 하는 기능이 잇어 이벤트들이 DalvikVM으로 보급 (propagate) 될 수 있게 해줍니다. 이 메카니즘을 사용하려면, manifest 파일을 다음과 같이 수정해야 합니다:- <file csharp><?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.company.product"> <application android:icon="@drawable/app_icon" android:label="@string/app_name"> <activity android:name=".OverrideExampleNative" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen"> <meta-data android:name="android.app.lib_name" android:value="unity" /> <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="false" /> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> </file> Activity 요소와 두개의 추가적인 메타-데이타 요소안의 ".OverrideExampleNative" 속성을 눈여겨 보세요. 처음의 메타데이타는 유니티 라이브러리 _libunity.so_를 사용하기 위한 지시 사항이고 두번째는 이벤트들이 UnityPlayerNativeActivity의 사용자화된 서브클래스로 보내지는걸 가능하게 해줍니다. =====예제===== ====네이티브 플러그인 샘플 Native Plugin Sample==== 네이티브 코드 플러그인 사용의 간단한 예제는 [[Attach:AndroidNativePlugin.zip|여기]]서 찾을 수 있습니다. 이 샘플은 어떻게 C 코드가 유니티 안드로이드 어플리케이션에서 호출될 수 있는지 보여줍니다. 이 팩키지는 네이티브 플러그인이 계산한 두 값의 합을 보여주는 씬을 포함합니다. 한가지 알아두실 것은 플러그인 컴파일하려면 [[http://developer.android.com/sdk/ndk/index.html|Android NDK]]가 필요합니다. ====자바 플러그인 샘플 Java Plugin Sample==== 자바 코드의 예제는 [[Attach:AndroidJavaPlugin.zip|여기]]서 찾을 수 있습니다. 이 샘플은 어떻게 자바 코드가 안드로이드 OS와 상호작용하기 위해 사용되고 C++ 이 어떻게 C#과 Java 를 연결하기 위하여 사용되는지 보여줍니다. 이 팩키지 안에 씬은 눌렀을때 안드로이드 OS가 정의한 어플리케이션 캐시 디렉토리를 잡는 버튼을 보여줍니다. 이 플러그인을 컴파일하려면 JDK 와[[http://developer.android.com/sdk/ndk/index.html|Android NDK]]가 둘 다 필요합니다. [[Attach:AndroidJavaPluginProject.zip|여기]]에 비슷하지만 네이티브 코드를 C#으로 Wrap 하기 위하여 미리 만들어진 JNI 라이브러리에 기반한 예제가 있습니다. {{tag>유니티 unity}} * 출처: [[http://unitykoreawiki.com/index.php?n=KrMain.PluginsForAndroid|유니티코리아위키]] (CC BY-NC-SA 2.0)
2+1?
이 필드는 비어 있도록 유지하세요:
저장
미리 보기
취소
편집 요약
참고: 이 문서를 편집하면 내용은 다음 라이선스에 따라 배포하는 데 동의하는 것으로 간주합니다:
CC Attribution-Noncommercial-Share Alike 4.0 International
연결문서
유니티3D ( Unity3D )
플러그인 (프로/모바일만 지원) Plugins (Pro/Mobile-only feature)
문서 도구
문서 보기
이전 판
연결문서
맨 위로
다크 모드로 보기
☀️
Toggle Menu
유니티3D ( Unity3D )
너두 고쳐두 됩니다.
사이트 도구
최근 바뀜
미디어 관리자
사이트맵
사용자 도구
등록
로긴
최근 수정된 문서
misuse_topical5
노박
unique_items
dinner_bell
deputy_beagle
ratslayer
one_for_my_baby
alerio
power_fist
제거됨
fixer
climb_ev_ry_mountain
companion
[장비 분실]
crashed_vertibird
brotherhood_t-51b_power_armor
marco
i_forgot_to_remember_to_forget
cateye