JAR(Java Archive) 플러그인은 주로 Android OS와의 상호 작용을 활성화하거나 C# 스크립트에서 Java로 작성된 메서드를 호출하는 데 사용됩니다.
JAR 플러그인은 Java 코드만 포함할 수 있기 때문에(Android 리소스를 포함할 수 없기 때문에) 사용이 매우 제한적입니다. JAR 플러그인을 프로젝트에 추가하려면 .jar 파일을 프로젝트 폴더 중 하나에 복사합니다. 그리고 Unity의 인스펙터 창에서 임포트 설정을 열고 선택합니다. Android 체크박스를 선택하여 이 .jar 파일을 Unity와 호환 가능으로 표시합니다.
Unity는 Java에서 코드를 호출할 때와 네이티브나 C# 스크립트에서 Java 나 Java VM(Virtual Machine)과 상호 작용할 때 모두 Java Native Interface (JNI)를 사용합니다.
Gradle 빌드 시스템을 사용하는 경우 다음 단계를 따르면 JAR 파일을 만들지 않을 수 있습니다.
Unity가 java 파일을 Gradle 프로젝트에 복사한 후 빌드하는 데 사용합니다.
참고: 본 섹션에서 이 정보는 JNI(Android Java Native Interface)에 대한 고급 지식이 필요합니다.
C 또는 C++ 플러그인에서 Java 코드에 액세스하려면 Java VM에 액세스해야합니다. C/C++ 코드에 다음 메서드를 추가하여 Java VM에 액세스합니다.
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* jni_env = 0;
vm->AttachCurrentThread(&jni_env, 0);
return JNI_VERSION_1_6;
}
본 문서에서 JNI를 자세히 설명할 수는 없으나 해당 메서드는 아래 예제와 같이 클래스 정의 찾기, 생성자(<init>) 메서드 실행 및 새로운 오브젝트 인스턴스 생성 등을 포함합니다.
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
}
JNI에 대한 자세한 내용은 JNI에 대한 Android 개발자 문서를 참조하십시오.
참고: 본 섹션에서 이 정보는 JNI(Android Java Native Interface)에 대한 고급 지식이 필요합니다.
AndroidJNIHelper
와 AndroidJNI
Unity API 클래스는 “원시” JNI 인터페이스를 감싸는 래퍼로 사용합니다.
AndroidJavaObject 및 AndroidJavaClass Unity API 클래스는 JNI 호출을 사용할 때 많은 작업을 자동화하며 캐싱을 사용하여 Java 호출을 더 빠르게 만듭니다. AndroidJavaObject
와 AndroidJavaClass
의 조합은 AndroidJNI
와 AndroidJNIHelper
를 기반으로 하지만, 몇 가지 추가적인 기능도 가지고 있습니다. 이러한 클래스에는 Java 클래스의 정적 멤버에 액세스하는 데 사용되는 정적 메서드도 있습니다.
C# 스크립트에서 Java JNI 호출을 작성하는 세 가지 방법이 있습니다.
AndroidJNI
메서드를 통한 원시 JNIAndroidJNI
를 수반한 AndroidJNIHelper
클래스AndroidJavaObject
와 AndroidJavaClass
클래스는 가장 편리한 고수준 API입니다.UnityEngine.AndroidJNI는 위에서 설명한대로 C에서 사용할 수 있는 JNI 호출에 대한 래퍼입니다. 클래스의 모든 메서드는 정적이며 Java Native Interface에 1:1로 매핑합니다.
UnityEngine.AndroidJNIHelper는 다음 단계에서 사용되는 헬퍼 함수를 제공합니다. 이 기능은 공용 메서드로 제공되며 특별한 경우 유용할 수 있습니다.
UnityEngine.AndroidJavaObject와 UnityEngine.AndroidJavaClass의 인스턴스는 Java 측의 java.lang.Object 및 java.lang.Class(또는 그 서브클래스)의 인스턴스에 1:1로 매핑합니다. 기본적으로 Java 측과 3가지 타입의 상호 작용을 제공합니다.
메서드 호출
필드 값 획득
필드 값 설정
호출은 ‘void’ 메서드에 대한 호출과 void가 아닌 반환 타입이 있는 메서드에 대한 호출의 두 가지 범주로 구분됩니다. 일반 타입은 void가 아닌 타입을 반환하는 메서드의 반환 형식을 나타내는 데 사용됩니다. Get 또는 Set은 항상 필드 타입을 나타내는 일반 타입을 사용합니다.
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);
이 예제는 스트링으로 초기화된 java.lang.String 인스턴스를 생성하고 이 문자열에 대해 해시 값을 검색해서 가져옵니다.
AndroidJavaObject
생성자는 최소한 하나의 파라미터, 즉 인스턴스를 생성할 클래스의 이름을 취합니다. 클래스 이름 뒤의 모든 파라미터는 오브젝트의 생성자 호출을 위한 파라미터이며, 이 경우에는 “some_string” 문자열입니다. 이후의 hashCode() 호출은 ’int’를 반환합니다. 이 예제에서는 해당 호출 메서드의 일반 타입 파라미터로 사용됩니다.
참고: 점으로 구분된 표기법을 사용하여 중첩된 Java 클래스를 인스턴스화할 수 없습니다. 내부 클래스는 $ 구분자를 사용해야 합니다. LayoutParams 클래스가 ViewGroup 클래스에 중첩되어 있는android.view.ViewGroup$LayoutParams
또는 android/view/ViewGroup$LayoutParams
를 사용합니다.
이 예제는 플러그인을 사용하지 않고 C#에서 현재 애플리케이션의 캐시 디렉토리를 가져오는 방법을 보여줍니다.
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);
이 예제는 새로운 오브젝트를 생성하기보다는com.unity3d.player.UnityPlayer
의 정적 멤버에 접근하기 위해 AndroidJavaObject
대신 AndroidJavaClass
로 시작합니다. 그런 다음 정적 필드인 “currentActivity”에 액세스하지만 이번에는 AndroidJavaObject
가 일반 파라미터로 사용됩니다. 실제 필드 타입 android.app.Activity는 java.lang.Object
의 서브 클래스이고, 비기본형은 AndroidJavaObject
로 액세스할 수 있어야 하기 때문입니다. 이 규칙에서 제외되는 것은 Java에서 기본형을 나타내지는 않지만 직접 액세스되는 문자열입니다.
액티비티 오브젝트에 대해 getCacheDir()
를 호출한 다음 캐시 디렉토리를 나타내는 파일 오브젝트를 가져올 수 있으며, getCanonicalPath()
를 호출하여 문자열 표현을 가져올 수 있습니다.
Unity는 Application.temporaryCachePath
및 Application.persistentDataPath
API를 사용하여 애플리케이션의 캐시 및 파일 디렉토리에 대한 액세스를 제공합니다.
이 예제는 UnitySendMessage
를 사용하여 Java에서 Unity로 데이터를 전달하는 방법을 보여줍니다.
using UnityEngine;
public class NewBehaviourScript : MonoBehaviour {
void Start () {
AndroidJNIHelper.debug = true;
using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) {
jc.CallStatic("UnitySendMessage", "Main Camera", "JavaMessage", "NewMessage");
}
}
void JavaMessage(string message) {
Debug.Log("message from java: " + message);
}
}
com.unity3d.player.UnityPlayer
Java 클래스는 UnitySendMessage
iOS 메서드와 동등한 정적인 메서드 UnitySendMessage
를 가지고 있습니다. 이것은 Unity에서 데이터를 전달하기 위해 Java에서 사용됩니다.
Unity 내부에서 UnitySendMessage
가 호출되었지만 Java를 사용하여 메시지를 중계하면 Java는 네이티브/Unity 코드를 다시 호출하여 “Main Camera”라는 객체에 메시지를 전달합니다. 이 객체에는 JavaMessage
라는 메서드가 포함된 스크립트가 첨부되어 있습니다.
AndroidJavaObject
와 AndroidJavaClass
는 계산상의 비용이 많이 드는 메서드입니다(원시 JNI를 사용하는 메서드도 마찬가지). 더 나은 성능과 코드 명확성을 위해 관리되는 코드와 네이티브/Java 코드 사이의 전환수를 최소한으로 유지하십시오.
//The first time you call a Java method 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 directly
Mono 가비지 컬렉터는 사용 후 생성된 모든 AndroidJavaObject
와 AndroidJavaClass
인스턴스를 릴리스해야 하지만 가능한 빨리 삭제되도록 using(){}
상태에 보관하는 것이 좋습니다. 이것이 없으면 언제 폐기될지 확신할 수 없습니다. AndroidJNIHelper.debug
를 true로 설정하면 가비지 컬렉터의 활동에 대한 기록이 디버그 출력에 표시됩니다.
//Getting the system language safely
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"));
}
}
}
2018–03–20 페이지 게시됨
Unity 5.5에서 업데이트된 기능
2018.2에서 Java 소스 파일 플러그인에 대한 지원이 Android 플레이어에 추가됨 NewIn20182
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.