LoginSignup
15
14

More than 5 years have passed since last update.

突然KotlinでUnity向けのSDKやPluginを作ることになった人向け資料

Last updated at Posted at 2018-02-22

はじめに

この記事は突然仕事でUnity向けのSDKやPluginを作ることになった人向け資料<Android実践編>の続編です。
最近、Unityはほぼほぼやっていないのですが
受託開発でも自社開発でもKotlinを使っており、
UnityPlugin開発に使えそうな気づきがあったのでまとめます。

環境は以下です

  • Unity2017.2
  • Android Studio 3.0.1 (Kotlin 1.2.21)

1 開発方法について

aarの作り方、UnityのPlugin仕様は前回記事でJavaで行った方法と同じなので省略。
New Module > Android Library でPlugin用Moduleを作成します。

2 Android Studio3/KotlinのPlugin開発で変わったこと

以下、サンプル開発に使用したPlugin ModuleのGradleファイルです。

nantokaplugin.gradle
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 26

    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

}

dependencies {

    //コメントアウト
    //implementation fileTree(dir: 'libs', include: ['*.jar'])
    //implementation 'com.android.support:appcompat-v7:26.1.0'

    implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"

    //追加
    compileOnly fileTree(dir: 'libs', include: ['unity-classes.jar'])

    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}

repositories {
    mavenCentral()
}

2.1 Gradleファイルの変更点: Kotlin

Kotlinを有効にしたので以下が増えています。

nantokaplugin.gradle
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

:

implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"

プロジェクトのGradleにはKotlinのバージョンが追加されます。

スクリーンショット 2018-02-23 1.00.03.png

2.2 Gradleファイルの変更点: Android Studio 3

unityのjarをコンパイル時のみ使用して、ビルドしたaarに含まない必要があります。
以下のAかBを行います。

A. libsフォルダ以下のjarを全部いれてunityのjarだけ引っこ抜く

nantokaplugin.gradle
:
    implementation fileTree(dir: 'libs', include: ['*.jar'])
}

android.libraryVariants.all { variant ->
    variant.outputs.each { output ->
        output.packageLibrary.exclude('libs/unity-classes.jar')
    }
}

B. unityのjar以外にjarがなければコンパイル時のみ参照するcompileOnlyを使用

nantokaplugin.gradle
:
    //コメントアウト
    //implementation fileTree(dir: 'libs', include: ['*.jar'])

    compileOnly fileTree(dir: 'libs', include: ['unity-classes.jar'])
:

3. KotlinでUnityPluginを書く

サンプルとしてKotlin側(Plugin側)をざっくり書くと以下のようになります。

UnityBridge.kt
package red.torch.nantokaplugin

import android.app.Activity
import com.unity3d.player.UnityPlayer
import com.unity3d.player.UnityPlayer.UnitySendMessage

@Suppress("unused")
class UnityBridge {

    //3.1 通常のメソッド呼び出し
    fun callUnityCode() {
        UnitySendMessage("ReceivedGameObject", "callbackMethod", "hogehoge")
    }

    //Javaと同じくUI操作はメインスレッドで
    fun someUIAction() {
        val activity = UnityPlayer.currentActivity
        activity.runOnUiThread {
            //UI操作の処理
        }
    }

    companion object {

        //3.2 companion objectメソッド呼び出し
        fun companionMethod(a: Int, b:Int) {
            UnitySendMessage("ReceivedGameObject", "callbackMethod", (a + b).toString())
        }

        //3.3 @Jvmstaticのcompanion objectメソッド呼び出し
        @JvmStatic fun jvmCompanionMethod(a: Int, b: Int) {
            UnitySendMessage("ReceivedGameObject", "callbackMethod", (a * b).toString())
        }
    }
}

Unity側のサンプルコードは以下のようになります

NewBehaviourScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class NewBehaviourScript : MonoBehaviour {

    //確認用
    [SerializeField]
    private Text text;

    public void onButton1()
    {
        //3.1 通常のメソッド呼び出し
        using (AndroidJavaObject jo = new AndroidJavaObject("red.torch.nantokaplugin.UnityBridge"))
        {
            jo.Call("callUnityCode");
        }
    }

    public void onButton2()
    {
        //3.2 companion objectメソッド呼び出し
        using (AndroidJavaClass jc = new AndroidJavaClass("red.torch.nantokaplugin.UnityBridge"))
        {
            jc.GetStatic<AndroidJavaObject>("Companion").Call("companionMethod", 2, 3);
        }
    }

    public void onButton3()
    {
        //3.3 @Jvmstaticのcompanion objectメソッド呼び出し
        using (AndroidJavaObject jo = new AndroidJavaObject("red.torch.nantokaplugin.UnityBridge"))
        {
            jo.CallStatic("jvmCompanionMethod", 2, 4);
        }
    }

    //確認用: UnitySendMessageの第2引数にメソッド名を合わせる
    void callbackMethod(string str) {
        text.text = str;
    }
}

3.1 通常のメソッド呼び出し

Javaとあまり変わりませんがKotlin側のメソッドはpublic省略可、void省略可より以下のようになります。
Javaと同じくUnitySendMessageをゲームオブジェクト名, メソッド名, 引数文字列で呼び出します

Plugin.kt
    fun callUnityCode() {
        UnitySendMessage("ReceivedGameObject", "callbackMethod", "hogehoge")
    }

Unity側ではAndroidJavaObject/AndroidJavaClassがそのまま使えます。
aar化したKotlinのコードJavaとして動作します。

Unity.cs
        using (AndroidJavaObject jo = new AndroidJavaObject("red.torch.nantokaplugin.UnityBridge"))
        {
            jo.Call("callUnityCode");
        }
:
    void callbackMethod(string str) {
        text.text = str;
    }

3.2 companion objectメソッド呼び出し

Kotlinにはstatic methodがなくcompanion objectで代用します。
Kotlin上では下記メソッドはUnityBridge.Companion.companionMethodとして
あたかもstatic methodのように呼び出すことが出来ます。

Plugin.kt
     companion object {
:
        fun companionMethod(a: Int, b:Int) {
            UnitySendMessage("ReceivedGameObject", "callbackMethod", (a + b).toString())
        }

ただし、Unity側から呼び出す場合は..

Unity.cs
        using (AndroidJavaClass jc = new AndroidJavaClass("red.torch.nantokaplugin.UnityBridge"))
        {
            jc.GetStatic<AndroidJavaObject>("Companion").Call("companionMethod", 2, 3);
        }

上記のように面倒になります。companionはあくまでオブジェクトなので

  1. 対象クラスをAndroidJavaClassとして取得
  2. 1からstaticのobjectであるCompanionを取得
  3. 2から非staticのメソッドcompanionMethod呼び出し

となります。
# 上記危ういのですが、このパターンで実際に動作しました

3.3 Jvmstaticのcompanion objectメソッド呼び出し

Kotlinでstatic method実現は難しい..!
のですが@JvmstaticをつけるとCompanionを経由せず
UnityBridge.jvmCompanionMethodとして呼び出すことが出来ます。

Plugin.kt
     companion object {
:
        @JvmStatic fun jvmCompanionMethod(a: Int, b: Int) {
            UnitySendMessage("ReceivedGameObject", "callbackMethod", (a * b).toString())
        }

Unity側でもJavaのstaticのように呼び出すことが出来ます。楽!

Unity.cs
        using (AndroidJavaObject jo = new AndroidJavaObject("red.torch.nantokaplugin.UnityBridge"))
        {
            jo.CallStatic("jvmCompanionMethod", 2, 4);
        }

4. 動作確認

実際にKotlinで作ったaarを組み込んで動作確認を行いました。3.1, 3.2, 3.3が正常に動作することを確認済みです。

  • 3.1で"hogehoge"の文字列がUnitySendMessageで返ってくる

  • 3.2 companion objectへのアクセスで2+3の答えが返ってくる

  • 3.3 jvmstaticのcompanion objectへのアクセスで2*4の答えが返ってくる

まとめ

  • KotlinでUnity Pluginは普通に作れる。
  • AndroidJavaObjectも普通に使える。
  • static methodはcompanion objectに@JvmStaticをつけると良い
15
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
14