unity 调用 java 接口

网上关于 unity 调用 java 接口的文章很多,只要去找,大概率都能解决自己的问题。我根据项目中 unity 调用 java 接口的经验,记录一下实践过程中遇到的问题,以备后续查询,若是能够帮到有需要的人,那就是额外收益了。

首先,描述一下遇到的问题:

  • java 插件包含哪些内容?怎么组织目录结构?
  • unity 如何获取android应用的 context?
  • unity 和 java 数据类型的映射?
  • unity 如何调用 java 的 API?
  • java 如何回调 unity 方法?

插件目录结构

刚开始想通过unity调用android插件时,不知道必须按照固定的目录结构组织文件,导致打出的android apk在运行时崩溃,提示找不到so文件,解压apk文件一看,果然没有相应的so文件。
unity 调用 java 接口_第1张图片下面列出几篇参考文档:
Unity3D项目Plugins目录组织
特殊文件夹名称

unity获取context

一些java方法需要传入 context 参数,unity 提供了专门的方法获取应用的 context,具体代码如下:

private static AndroidJavaObject m_context = null;
private static AndroidJavaObject Context
 {
     get
     {
         if( m_context == null )
         {
             using( AndroidJavaObject unityClass = new AndroidJavaClass( "com.unity3d.player.UnityPlayer" ) )
             {
                 m_context = unityClass.GetStatic( "currentActivity" );
             }
         }
         return m_context;
     }
 }

官方参考文档:
JAR 插件
Building Plugins for Android

数据类型映射

C# 和 java 之间的基础类型可以直接转换,包括 string 类型,但是复杂类型必须通过 AndroidJavaObject 实现。
unity 调用 java 接口_第2张图片
结构体
java 接口中需要传入结构体参数,该怎么办呢?

// java 类型
public class Student {
    public String name;
    public int age;
    public  Sex sex;

    public enum Sex {
        MAN(0),
        WOMEN(1);

        private int value = 0;
        Sex(int value) {
            this.value = value;
        }
        public int value() {
            return this.value;
        }
    }
}

unity C# 结构体

// C# 类型
public struct Student {
	public string name;
	public int age;
	public Sex sex;
}
public enum Sex {
	Man = 0,
	Woman = 1
}

unity 中首先需要获取类型,根据类型创建 AndroidJavaObject,然后对其成员进行赋值。

Student st;
st.name = "test";
st.age = 28;
st.sex = Sex.Man;

// C# 对象转换为 java 对象
AndroidJavaObject student_object = new AndroidJavaObject("com.ss.example.Student");
student_object.Set("name", st.name);
student_object.Set("age", st.age);
student_object.Set("sex", ConvertType(st.sex));

// C#枚举类型转 java 枚举类型
private static AndroidJavaObject ConvertType(Sex type)
{
    AndroidJavaClass typeClass = new AndroidJavaClass("com.ss.example.Student$Sex");
    switch (type)
    {
        case Sex.Man:
        {
            return typeClass.GetStatic("MAN");
            break;
        }
        case Sex.Woman:
        {
            return typeClass.GetStatic("WOMEN");
            break;
        }
        default:
        {
            return typeClass.GetStatic("MAN");
        }
    }
}

当从 unity 环境调用 java 接口时,如果接口需要传入一个java Student 对象,此时传入 student_object 就可以正常运行了。

unity调用java API

unity 调用 java API 有专门的方法,通过 AndroidJavaClass
和 AndroiJavaObject 实现。
unity 调用 java 接口_第3张图片

调用一个类的静态方法,首先必须能够拿到这个类,然后调用对应的方法即可。
java 接口:

public abstract class Writer
	public static synchronized Writer create(Context context, Student st);
	public int  write(String msg);
}

C# 调用静态方法

// 获取 java 类型
AndroidJavaClass writerClass = new AndroidJavaClass( "com.example.Writer" );
// 调用静态方法
AndroidJavaObject object = writerClass.CallStatic("create", Context, student_object);

CallStatic 方法至少有一个参数,那就是被调静态方法的名字,必须和 java 名字保持一致,返回值通过 CallStatic 尖括号里的类型来指定,如果没有指定就表示不返回任何值。
此处的 context 即为前面获取的android 应用的 context。

C# 调用成员方法
成员方法必须基于对象来调用,因此我们可以基于上面通过调用 “create” 方法创建的对象,来调用其成员方法。

int words = object.Call("write", "story");

java 触发 unity 的回调

unity 使用 java 插件,一方面有 API,另一方面肯定有回调方法,需要在特定事件发生时,通知 unity 更新 UI。回调通过 AndroidJavaProxy 实现。
使用方法如下,java 接口定义:

public interface IEventHandler {
	void onWriteDone(Student st);
	void onClose(String test);
}

C# 层实现回调方法:

public class PluginCallback : AndroidJavaProxy
{
     public PluginCallback() : base("com.example.IEventHandler")
     {
     }

	// 注意:回调中的非基础类型,在 C# 层必须用 AndroidJavaObject 来承接
	void onWriteDone(AndroidJavaObject st) {
		string name = st.Get("name");
		int age = st.Get("age");
	}

	void onClose(String test) {
		
	}
}

IEventHandler 必须是 Interface 类型,不能是 abstract class 类型。

回调线程更新 unity UI 线程

推荐使用 Loom 插件,可以参考 Unity使用Loom实现多线程
在 unity UI 线程中初始化时,调用 Loom 的初始化方法:

Loom.Initialize();

在需要转线程的地方如下调用即可:

[MonoPInvokeCallback(typeof(OnCloseEventHandler))]
public static void onClose(string test) {
	if (_instance.OnCloseEvent != null) {
		Loom.QueueOnMainThread(() =>
	    {
	        _instance.OnCloseEvent(test);
	    });
	}
}

结语

到这里 unity 调用 java 接口的记录就写完了,后续有更新再补充吧。

参考
官方网站
Unity 插件开发 - Android与iOS
Unity中C#与Android中Java的互相调用遇到的一些问题
Wrapping a native SDK for Unity: our challenges and choices

你可能感兴趣的:(unity,java)