Version: 2023.1
언어: 한국어
Java 및 Kotlin 소스 플러그인
Unity를 Android 애플리케이션에 통합

C# 스크립트에서 Java 및 Kotlin 플러그인 코드 호출

C# 스크립트에서 Java 코드를 호출하기 위해 Unity는 C++를 통해 Android Java Native Interface (JNI)와 통신하는 C# API를 제공합니다.Unity는 JNI를 사용하여 Java 코드와 상호 작용하는 데 사용할 수 있는 저수준 및 고수준 API를 모두 제공합니다.

저수준 API

저수준 AndroidJNI 클래스는 JNI 호출을 래핑하고 JNI 메서드에 직접 매핑되는 정적 메서드를 제공합니다.AndroidJNIHelper API는 주로 고수준 API에서 사용되는 헬퍼 함수를 제공하지만 특정 상황에서 유용할 수 있습니다.

고수준 API

고수준 AndroidJavaObject, AndroidJavaClassAndroidJavaProxy API는 JNI 호출에 필요한 많은 작업을 자동화합니다.또한 캐싱을 사용하여 Java를 더 빠르게 호출할 수 있습니다.AndroidJavaObjectAndroidJavaClass의 조합은 AndroidJNIAndroidJNIHelper를 기반으로 구축되지만 Java 클래스의 정적 멤버에 액세스하는 데 사용할 수 있는 정적 메서드와 같은 추가 기능도 포함하고 있습니다.

AndroidJavaObjectAndroidJavaClass의 인스턴스는 각각 java.lang.Objectjava.lang.Class의 인스턴스에 대한 일대일 매핑을 갖습니다.Java/Kotlin 코드와 세 가지 타입의 상호 작용을 제공합니다.

각 상호 작용에는 정적 버전도 있습니다.

필드 값을 가져오거나 값을 반환하는 메서드를 호출하는 경우 제네릭을 사용하여 반환 타입을 지정하십시오.필드 값을 설정할 때 제네릭을 사용하여 설정하려는 필드의 타입도 지정할 수 있습니다.값을 반환하지 않는 메서드의 경우 일반, 비제네릭 호출 버전이 있습니다.

중요:비기본형AndroidJavaObject로 액세스해야 합니다.유일한 예외는 Java에서 기본형을 나타내지 않더라도 사용자가 직접 액세스하는 문자열입니다.

예제

이 섹션에는 고수준의 AndroidJavaObjectAndroidJavaClass API를 사용하는 방법을 보여주는 코드 샘플이 포함되어 있습니다.

Java 문자열의 해시 코드 가져오기

다음 코드 샘플은 [스트링](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;
        }
    }
}

예시는 다음과 같습니다.

  1. java.lang.String을 나타내는 AndroidJavaObject를 생성합니다.AndroidJavaObject 생성자는 다음 인스턴스를 구성할 클래스의 이름인 파라미터를 하나 이상 받습니다.클래스 이름 뒤에 오는 모든 파라미터는 오브젝트의 생성자 호출을 위한 것으로, 이 경우 GetJavaStringHashCodetext 파라미터입니다.
  2. hashCode()를 호출하여 문자열의 해시 코드를 가져옵니다.이 호출은 hashCode()가 해시 코드를 정수로 반환하기 때문에 Callint 일반 타입 파라미터를 사용합니다.

참고:점 표기법을 사용하여 중첩된 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;
        }
    }
}

예시는 다음과 같습니다.

  1. com.unity3d.player.UnityPlayer를 나타내는 AndroidJavaClass를 생성합니다.정적 멤버에 액세스하려면 AndroidJavaObject 대신 AndroidJavaClass를 사용하는 것이 가장 좋습니다.
  2. 현재 활동을 나타내는 AndroidJavaObject를 생성합니다. 이것은 com.unity3d.player.UnityPlayer의 정적 멤버입니다.
  3. 액티비티 오브젝트에서 getCacheDir()를 호출하여, 해당 캐시 디렉토리를 나타내는 파일 오브젝트를 반환합니다.
  4. 파일 오브젝트에서 getCanonicalPath()를 호출하면 캐시 디렉터리를 문자열로 가져올 수 있습니다.

참고:이 예는 참고용입니다.대신 애플리케이션의 캐시 및 파일 디렉토리에 액세스하려면 Application.temporaryCachePathApplication.persistentDataPath API를 사용하십시오.

Java에서 Unity로 데이터 전달

다음 코드 샘플은 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);
    }
}

예시는 다음과 같습니다.

  1. com.unity3d.player.UnityPlayer를 나타내는 AndroidJavaClass를 생성합니다.
  2. com.unity3d.player.UnityPlayer의 멤버인 정적UnitySendMessage 메서드를 호출합니다.

Unity 내에서 UnitySendMessage를 호출하면 Java를 사용하여 메시지를 릴레이하고, Java는 네이티브/Unity 코드를 다시 호출하여 오브젝트에 메시지를 전달합니다. 이 예제에서는 JavaMessage라는 메서드가 포함된 스크립트가 첨부된 "My GameObject"라는 게임 오브젝트입니다.

베스트 프랙티스

이 섹션에서는 C# 스크립트에서 Java 및 Kotlin 플러그인 코드를 호출할 때 주의해야 할 베스트 프랙티스에 대해 설명합니다.

JNI 호출 최소화

고수준 또는 저수준 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.debugtrue로 설정하십시오.

Java 및 Kotlin 소스 플러그인
Unity를 Android 애플리케이션에 통합