# C# スクリプトから Java や Kotlin のプラグインコードを呼び出す

> Interact with Java and Kotlin plug-in code from your C# scripts.

C# スクリプトから Java コードを呼び出すために、Unity は C++ を通じて Android [Java Native Interface](https://developer.android.com/training/articles/perf-jni) と通信する C# API を提供します。JNI を使用して Java コードと相互作用するために使用できる低レベルの API と 高レベルの API の両方を利用できます。

## 低レベル API

低レベルの [AndroidJNI](/engine/6000.0/script-reference/unity-engine/android-jni.md) クラスは、JNI 呼び出しをラップして、JNI メソッドに直接マップする静的メソッドを提供します。[AndroidJNIHelper](/engine/6000.0/script-reference/unity-engine/android-jni-helper.md) API は、主に高レベルの API で使用されるヘルパー機能を提供しますが、特定の状況で役に立つことがあります。

## 高レベル API

高レベルの [AndroidJavaObject](/engine/6000.0/script-reference/unity-engine/android-java-object.md)、[AndroidJavaClass](/engine/6000.0/script-reference/unity-engine/android-java-class.md)、[AndroidJavaProxy](/engine/6000.0/script-reference/unity-engine/android-java-proxy.md) の API は、JNI 呼び出しに必要な多くのタスクを自動化します。また、キャッシュを利用して Java への呼び出しを高速化します。`AndroidJavaObject` と `AndroidJavaClass` の組み合わせは、`AndroidJNI` と `AndroidJNIHelper` の上に構築されていますが、Java クラスの静的メンバーにアクセスするために使える静的メソッドなどの追加機能が含まれています。

`AndroidJavaObject` と `AndroidJavaClass` のインスタンスは、それぞれ [java.lang.Object](https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html) と [java.lang.Class](https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html) のインスタンスに 1 対 1 のマッピングを持っていますこれらは、Java/Kotlin のコードとの 3 種類のインタラクションが可能です。

* メソッドを呼び出します [(Call)](/engine/6000.0/script-reference/unity-engine/android-java-object/call.md)。
* フィールドの値を取得します [(Get)](/engine/6000.0/script-reference/unity-engine/android-java-object/get.md)。
* フィールドの値を設定します [(Set)](/engine/6000.0/script-reference/unity-engine/android-java-object/set.md)。

各インタラクションには静的バージョンもあります。

* 静的メソッドを呼び出します [(CallStatic)](/engine/6000.0/script-reference/unity-engine/android-java-object/call-static.md)。
* 静的フィールドの値を取得します [(GetStatic)](/engine/6000.0/script-reference/unity-engine/android-java-object/get-static.md)。
* 静的フィールドの値を設定します [(SetStatic)](/engine/6000.0/script-reference/unity-engine/android-java-object/set-static.md)。

フィールドの値を取得するとき、または値を返すメソッドを呼び出すときは、[ジェネリック](https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/types/generics) を使用して戻り値の型を指定します。フィールドの値を設定する場合も、ジェネリックを使用して設定するフィールドの型を指定します。値を返さないメソッドについては、通常の非ジェネリックバージョンの [Call](/engine/6000.0/script-reference/unity-engine/android-java-object/call.md) があります。

**重要**: [非プリミティブ型](http://developer.android.com/reference/java/lang/Class.html) には、`AndroidJavaObject` としてアクセスする必要があります。唯一の例外は文字列で、Java ではプリミティブ型を表さないにもかかわらず、直接アクセスすることができます。

### 例

このセクションでは、高レベルの `AndroidJavaObject` と `AndroidJavaClass` API の使用方法を示すコードサンプルを掲載しています。

#### Java 文字列のハッシュコードを取得

以下のコードサンプルは、[文字列](http://developer.android.com/reference/java/lang/String.html#String\(java.lang.StringBuilder\)) で初期化された [java.lang.String](http://developer.android.com/reference/java/lang/String.html) のインスタンスを作成し、その文字列の [ハッシュ値](http://developer.android.com/reference/java/lang/String.html#hashCode\(\)) を取得します。

```c#
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. `AndroidJavaObject` を作成し、[java.lang.String](http://developer.android.com/reference/java/lang/String.html) を表現します。`AndroidJavaObject` コンストラクターは、少なくとも 1 つのパラメーター (インスタンスを構築するクラスの名前) を取ります。クラス名の後のパラメーターは、オブジェクトのコンストラクター呼び出し用です。この場合は、`GetJavaStringHashCode` の `text` パラメーターです。
2. [hashCode()](https://developer.android.com/reference/java/lang/String.html#hashCode\(\)) を呼び出し、文字列のハッシュコードを取得します。この呼び出しでは、`Call` の `int` ジェネリック型パラメーターを使用します。`hashCode()` はハッシュコードを整数で返すからです。

**ノート**: ネスト状の Java クラスのインスタンス化にはドット付き表記を使用できません。内部クラスをインスタンス化するには、`$` セパレーターを使用する必要があります。例えば、`LayoutParams` クラスが `ViewGroup` クラスにネストされている場合、`android.view.ViewGroup$LayoutParams` または `android/view/ViewGroup$LayoutParams` を使用します。

#### キャッシュディレクトリを取得

以下のコードサンプルは、プラグインを使用せずに、C# で現在のアプリケーションのキャッシュディレクトリを取得する方法を示しています。

```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. `AndroidJavaClass` を作成し、`com.unity3d.player.UnityPlayer` を表現します。静的メンバーにアクセスするには、`AndroidJavaObject` の代わりに `AndroidJavaClass` を使用するのが最も効率的です。
2. `AndroidJavaObject`を作成し、現在の [Activity](http://developer.android.com/reference/android/app/Activity.html) を表します。これは、`com.unity3d.player.UnityPlayer` の静的メンバーです。
3. Activity オブジェクトに対して [getCacheDir()](http://developer.android.com/reference/android/content/Context.html#getCacheDir\(\)) を呼び出します。これは、キャッシュディレクトリを表す [File](https://developer.android.com/reference/java/io/File.html) オブジェクトを返します。
4. File オブジェクトに対して [getCanonicalPath()](http://developer.android.com/reference/java/io/File.html#getCanonicalPath\(\)) を呼び出します。これは、キャッシュディレクトリを文字列として取得できます。

**ノート**: この例は参考用です。代わりに、アプリケーションのキャッシュとファイルディレクトリにアクセスするには、[Application.temporaryCachePath](/engine/6000.0/script-reference/unity-engine/application/temporary-cache-path.md) と [Application.persistentDataPath](/engine/6000.0/script-reference/unity-engine/application/persistent-data-path.md) API を使用してください。

#### Java から Unity にデータを渡す

以下のコードサンプルは、`UnitySendMessage` を使用して Java から Unity にデータを渡す方法を示しています。

```c#
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. `AndroidJavaClass` を作成し、`com.unity3d.player.UnityPlayer` を表現します。
2. `com.unity3d.player.UnityPlayer` のメンバーである静的な `UnitySendMessage` メソッドを呼び出します。

`UnitySendMessage` は Unity 内から呼び出されますが、Java を使ってメッセージをリレーします。それから Java がネイティブあるいは Unity のコードにコールバックしてオブジェクト (この例では、"My GameObject" という名前のゲームオブジェクト) にメッセージを伝えます。このオブジェクトには `JavaMessage` というメソッドを含むスクリプトが添付されています。

## ベストプラクティス

ここでは、C# スクリプトから Java や Kotlin のプラグインコードを呼び出す際に知っておくとよい効果的な方法を説明します。

### JNI 呼び出しの最小化

Java Native Interface (JNI) を、高レベルまたは低レベルの C# API を介して使用すると、リソースを消費し、速度が低下する可能性があります。パフォーマンスを向上させ、またコードを明確にするために、JNI 呼び出しの数を少なくすることが効率的です。

不必要な JNI 呼び出しを避けるため、高レベルの C# API は、呼び出した各 Java メソッドの [ID](/engine/6000.0/script-reference/unity-engine/android-jni/get-method-id.md) をキャッシュします。これは、同じメソッドへの後続の呼び出しが、最初の呼び出しほどリソースを消費しないことを意味します。この呼び出しは同じフレーム内である必要はなく、同じ AndroidJavaObject/AndroidJavaClass インスタンスからでなくてもかまいません。低レベル API を使用していて、このパフォーマンス上の利点を求める場合は、自分でメソッド ID をキャッシュする必要があります。そうでない場合は、高レベルの API を使用するのがより効率的です。

**ノート**: Unity はアプリケーションを [閉じる](https://support.google.com/android/answer/9079646?hl=en-GB) までキャッシュを維持します。これには、アプリケーションがバックグラウンドで動作している間も含まれます。

### ガベージコレクション

`AndroidJavaObject` または `AndroidJavaClass` のインスタンスを `using` ステートメントでラップして、Unity ができるだけ早くそれらを破棄するようにする必要があります。`using` を使用しない場合でも、Unity の [ガベージコレクター](/engine/6000.0/manual/analysis/performance-memory-overview/managed-memory/garbage-collector.md) は作成されたインスタンスをすべてリリースするはずですが、そのタイミングを制御することはできません。

以下のコードサンプルは、`using` ステートメントを使って、最適な方法でシステム言語を取得する方法を示しています。

```c#
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 Logcat](https://docs.unity3d.com/Packages/com.unity.mobile.android-logcat@latest/index.html) でガベージコレクターのアクティビティーの記録を表示するには、 [AndroidJNIHelper.debug](/engine/6000.0/script-reference/unity-engine/android-jni-helper/debug.md) を `true` に設定します。
