C# 스크립트에서 Java 코드를 호출하기 위해 Unity는 C++를 통해 Android Java Native Interface (JNI)와 통신하는 C# API를 제공합니다.Unity는 JNI를 사용하여 Java 코드와 상호 작용하는 데 사용할 수 있는 저수준 및 고수준 API를 모두 제공합니다.
저수준 AndroidJNI 클래스는 JNI 호출을 래핑하고 JNI 메서드에 직접 매핑되는 정적 메서드를 제공합니다.AndroidJNIHelper API는 주로 고수준 API에서 사용되는 헬퍼 함수를 제공하지만 특정 상황에서 유용할 수 있습니다.
고수준 AndroidJavaObject, AndroidJavaClass 및 AndroidJavaProxy API는 JNI 호출에 필요한 많은 작업을 자동화합니다.또한 캐싱을 사용하여 Java를 더 빠르게 호출할 수 있습니다.AndroidJavaObject
와 AndroidJavaClass
의 조합은 AndroidJNI
와 AndroidJNIHelper
를 기반으로 구축되지만 Java 클래스의 정적 멤버에 액세스하는 데 사용할 수 있는 정적 메서드와 같은 추가 기능도 포함하고 있습니다.
AndroidJavaObject
및 AndroidJavaClass
의 인스턴스는 각각 java.lang.Object 및 java.lang.Class의 인스턴스에 대한 일대일 매핑을 갖습니다.Java/Kotlin 코드와 세 가지 타입의 상호 작용을 제공합니다.
각 상호 작용에는 정적 버전도 있습니다.
필드 값을 가져오거나 값을 반환하는 메서드를 호출하는 경우 제네릭을 사용하여 반환 타입을 지정하십시오.필드 값을 설정할 때 제네릭을 사용하여 설정하려는 필드의 타입도 지정할 수 있습니다.값을 반환하지 않는 메서드의 경우 일반, 비제네릭 호출 버전이 있습니다.
중요:비기본형에 AndroidJavaObject
로 액세스해야 합니다.유일한 예외는 Java에서 기본형을 나타내지 않더라도 사용자가 직접 액세스하는 문자열입니다.
이 섹션에는 고수준의 AndroidJavaObject
및 AndroidJavaClass
API를 사용하는 방법을 보여주는 코드 샘플이 포함되어 있습니다.
다음 코드 샘플은 [스트링](http://developer.android.com/reference/java/lang/String.html#String(java.lang.StringBuilder)으로 초기화된 java.lang.String 인스턴스를 생성하고 이 문자열에 대해 해시 값을 검색해서 가져옵니다.
using UnityEngine;
public class JavaExamples
{
public static int GetJavaStringHashCode(string text)
{
using (AndroidJavaObject jo = new AndroidJavaObject("java.lang.String", text))
{
int hash = jo.Call<int>("hashCode");
return hash;
}
}
}
예시는 다음과 같습니다.
AndroidJavaObject
를 생성합니다.AndroidJavaObject
생성자는 다음 인스턴스를 구성할 클래스의 이름인 파라미터를 하나 이상 받습니다.클래스 이름 뒤에 오는 모든 파라미터는 오브젝트의 생성자 호출을 위한 것으로, 이 경우 GetJavaStringHashCode
의 text
파라미터입니다.hashCode()
가 해시 코드를 정수로 반환하기 때문에 Call
에 int
일반 타입 파라미터를 사용합니다.참고:점 표기법을 사용하여 중첩된 Java 클래스를 인스턴스화할 수 없습니다.내부 클래스를 인스턴스화하려면 $
구분자를 사용해야 합니다.예를 들어, android.view.ViewGroup$LayoutParams
또는 android/view/ViewGroup$LayoutParams
을 사용하십시오. LayoutParams
클래스는 ViewGroup
클래스에 중첩됩니다.
다음 코드 샘플은 플러그인을 사용하지 않고 C#에서 현재 애플리케이션의 캐시 디렉토리를 가져오는 방법을 보여줍니다.
using UnityEngine;
public class JavaExamples
{
public static string GetApplicationCacheDirectory()
{
using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
using (AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
using (AndroidJavaObject javaFile = currentActivity.Call<AndroidJavaObject>("getCacheDir"))
{
string cacheDirectory = javaFile.Call<string>("getCanonicalPath");
return cacheDirectory;
}
}
}
예시는 다음과 같습니다.
com.unity3d.player.UnityPlayer
를 나타내는 AndroidJavaClass
를 생성합니다.정적 멤버에 액세스하려면 AndroidJavaObject
대신 AndroidJavaClass
를 사용하는 것이 가장 좋습니다.AndroidJavaObject
를 생성합니다. 이것은 com.unity3d.player.UnityPlayer
의 정적 멤버입니다.참고:이 예는 참고용입니다.대신 애플리케이션의 캐시 및 파일 디렉토리에 액세스하려면 Application.temporaryCachePath 및 Application.persistentDataPath API를 사용하십시오.
다음 코드 샘플은 UnitySendMessage
를 사용하여 Java에서 Unity로 데이터를 전달하는 방법을 보여줍니다.
using UnityEngine;
public class JavaExamples :MonoBehaviour
{
private void Start()
{
AndroidJNIHelper.debug = true;
using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
jc.CallStatic("UnitySendMessage", "My GameObject", "JavaMessage", "NewMessage");
}
}
private void JavaMessage(string message)
{
Debug.Log("message from java:" + message);
}
}
예시는 다음과 같습니다.
com.unity3d.player.UnityPlayer
를 나타내는 AndroidJavaClass
를 생성합니다.com.unity3d.player.UnityPlayer
의 멤버인 정적UnitySendMessage
메서드를 호출합니다.Unity 내에서 UnitySendMessage
를 호출하면 Java를 사용하여 메시지를 릴레이하고, Java는 네이티브/Unity 코드를 다시 호출하여 오브젝트에 메시지를 전달합니다. 이 예제에서는 JavaMessage
라는 메서드가 포함된 스크립트가 첨부된 "My GameObject"라는 게임 오브젝트입니다.
이 섹션에서는 C# 스크립트에서 Java 및 Kotlin 플러그인 코드를 호출할 때 주의해야 할 베스트 프랙티스에 대해 설명합니다.
고수준 또는 저수준 C# API를 통해 Java Native Interface(JNI)를 사용하는 것은 리소스가 많이 소요되며 속도가 느릴 수 있습니다.성능과 코드 명확성을 개선하려면 JNI 호출 수를 낮게 유지하는 것이 가장 좋습니다.
불필요한 JNI 호출을 피하기 위해 고수준의 C# API는 사용자가 호출하는 각 Java 메서드의 ID를 캐시합니다.즉, 동일한 메서드에 대한 후속 호출은 첫 번째 호출만큼 리소스가 많이 소요되지 않습니다.호출이 같은 프레임이나 동일한 AndroidJavaObject/AndroidJavaClass 인스턴스에서 이루어질 필요는 없습니다.저수준 API를 사용하면서 이 성능 이점을 얻으려면 메서드 ID를 직접 캐시해야 합니다.그렇지 않은 경우 고수준 API를 사용하는 것이 가장 좋습니다.
참고:Unity는 애플리케이션이 종료될 때까지 캐시를 유지합니다.여기에는 애플리케이션이 백그라운드에 있는 상태도 포함됩니다.
AndroidJavaObject
또는 AndroidJavaClass
인스턴스를 using
문으로 래핑하여 Unity에서 가능한 한 빨리 삭제하도록 해야 합니다.using
을 사용하지 않는 경우, Unity의 가비지 컬렉터는 생성된 모든 인스턴스를 해제해야 하지만 언제 해제될지 제어할 수 없습니다.
다음 코드 샘플은 using
문을 사용하여 최적의 방식으로 시스템 언어를 가져오는 방법을 보여줍니다.
using UnityEngine;
public class LocaleExample :MonoBehaviour
{
void Start()
{
using (AndroidJavaClass cls = new AndroidJavaClass("java.util.Locale"))
using (AndroidJavaObject locale = cls.CallStatic<AndroidJavaObject>("getDefault"))
{
if (locale != null)
{
Debug.Log("current lang = " + locale.Call<string>("getDisplayLanguage"));
}
}
}
}
참고:Android 로그캣에서 가비지 컬렉터의 활동 기록을 보려면 AndroidJNIHelper.debug를 true
로 설정하십시오.