U3D中Android和C#之间的调用

Unity与Andorid之间的调用

在Unity3D开发中,可能会遇到需要在Android中进行一些操作的情况,那么我们如何做呢?

比如开发Android的jaraar给Unity调用,这其中很多坑是Unity开发和Android 开发没有接触过的

Unity调用Android

首先添加一个GameObject(Button)

然后在Hierarchy目录下找到Canvas中添加的Button,增加些好的C#脚本

在C#中的新建一个脚本,继承与MonoBehaviour然后在Update当中写入点击事件的捕获

  • 点击事件方法一

    使用这种方法注意,首先要在Canvas中添加这个脚本

1
2
3
4
5
6
7
8
void Update () {
//左键
if (Input.GetMouseButtonDown(0)) disFlag = true;
//右键
if (Input.GetMouseButtonDown(1)) disFlag = true;
//中键
if (Input.GetMouseButtonDown(2)) disFlag = true;
}
  • 点击事件方法二
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using UnityEngine.UI;
using UnityEngine.Events;
public class ClickObject : MonoBehaviour
{
void Start ()
{
//获取按钮游戏对象
GameObject btnObj = GameObject.Find ("Canvas/Button");
//获取按钮脚本组件
Button btn = (Button) btnObj.GetComponent<Button>();
//添加点击侦听
btn.onClick.AddListener (onClick);
}

void onClick ()
{
Debug.Log ("click!");
}
}
  • 点击事件添加方法三
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using UnityEngine.UI;//Button的包
using UnityEngine.Events;//
public class ClickObject2 : MonoBehaviour
{
void Start ()
{
//获取按钮游戏对象
GameObject btnObj = GameObject.Find ("Canvas/Button");
//获取按钮脚本组件
Button btn = (Button) btnObj.GetComponent<Button>();
//添加点击侦听
btn.onClick.AddListener (delegate() {
onClick(btnObj);
});
}

void onClick (GameObject obj)
{
Debug.Log ("click: " + obj.name);
}
}

如果没有执行start中的

1
2
3
4
//获取按钮游戏对象
GameObject btnObj = GameObject.Find ("Canvas/Button");
//获取按钮脚本组件
Button btn = (Button) btnObj.GetComponent<Button>();

Unity 调用android的一些tips

androidJavaClass和AndroidJavaObject的区别

  • androidJavaClass 只调用Activity的实例
  • AndroidJavaObject会创建一个对象

Unity在UI线程中调用andorid

1
2
3
activity.Call("runOnUiThread", new AndroidJavaRunnable(() => {
plugin.Call("testToast");
}));

高级功能

最初的使用是讲Unity导出android工程后,自带了class.jar文件

我们不依赖于Unity来做一些事情的话需要使用Unity的扩展功能,如拿UnityPlayerActivity

首先我们需要拿到Unity的java类资源class.jar,在Unity中的*/Applications/Unity* (on Mac)) in a sub-folder called *PlaybackEngines/AndroidPlayer/Variations/mono or il2cpp/Development or Release/Classes/*.

如果引入了class.jar,通常你的aar在打包的时候会将class.jar带上,这样的话unity编译会有两个class.jar,我们可以在Android中这样做,新建一个modle然后,modle中添加class.jar,再创建依赖

1
2
3
4
dependencies {
compile project(':unitylibrary')
...
}

从一个报错中可以看出来Unity调用Android是通过JNI调用的,签名符为(Ljava/lang/String;)Ljava/lang/String;

1
2
E/Unity: AndroidJavaException: java.lang.NoSuchMethodError: no non-static method with name='test1' signature='(Ljava/lang/String;)Ljava/lang/String;' in class Ljava.lang.Object;
java.lang.NoSuchMethodError: no non-static method with name='test1' signature='(Ljava/lang/String;)Ljava/lang/String;' in class Ljava.lang.Object;

获取android的类并且调用方法

1
2
3
4
5
6
7
8
9
10
11
12
AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject activity = unityPlayer.GetStatic("currentActivity");
activity.CallStatic("testMethod");
//or
activity.Call("testMethod", "testString");
//or
activity.Call("runOnUiThread", new AndroidJavaRunnable(() =>
{
activity.Call("testMethod", "testString");
}));
//or
myClass.Call("testMethod", new object[] { "testString" } );

上面的真个流程是

  1. 首先new AndroidJavaClass拿到类UnityPlayer
  2. 然后获取静态或者动态对象unityPlayer.GetStatic
  3. 用拿到的方法执行CallStatic或者Call来调用
  4. 可以传递多个参数,可以是对象可以是字符创

从这里可以看出来,是拿到了UnityPlayercurrentActivity,Unity的导出工程有class.jar中有这么一个包,这个是unity的api,如果要自己开发Unity的aar的话,这部分相当于调用UnityPlayer.currentActivity中拿到了当前activity

Android调用Unity

在android原生中

1
UnityPlayer.UnitySendMessage(objectname, methodName, message);
  • callbackName传递的是GameObject的名字

  • methodName传递的是方法名

  • message传递的是String参数

这里调用Unity方法的参数貌似只能是String.

Unity中开发Android时发现的一些东西

  • 开发aar的时候如何拿到一个Activity

一开始不知道怎么拿Activity?后开想了一下,其实不就是Unity调用android的时候调用的过程吗?

1
UnityPlayer.currentActivity()

这样在aar开发的过程中就不需要调用activity了,但是注意,这个UnityPlayer是Unity架包中的,因此需要先将Unity的架包class.jar引入

  • Android打aar怎么包含aar或者jar

出现一种情况,要将代码打成aar,发现libs下的另一个aar,不出现在打包后的aar中

这种情况解决的很诡异,我在libs中加了一个jar并在gradle中配置后打包后,另一个aar 就打进去了

  • 打aar的时候怎么不包含jar

一般出现这种情况是因为需要获取一个Activity从而引入了Unity架包class.jar,有两种解决方案

  1. 从libs目录下将这个jar移除,然后再进行关联

  2. 将aar解压,删除文件后再压缩,记得用命令 unzipjar

依赖配置

依次点击Project Settings->Player->Publish Setting->Custom Gradle Template

会在Asset/Plugin/Android/目录下生成mainTemplate.gradle文件

然后就可以直接自己写gradle就可以啦

aar打包问题

aar中是否包含aar或者jar用什么来表示呢?

1
implementation fileTree(include: ['*.jar'], dir: 'libs')

关键在include: ['*.jar']中,如果是include: ['*.jar','*.aar']就会将aar也打进去

FAQ

1
2
2019-01-09 20:59:37.602 17807-17837/com.crush.gogo E/Unity: NullReferenceException: Object reference not set to an instance of an object
at GooglePayUnity.Start () [0x00054] in <b0bcfc76f7c5481a906ea15afbb434af>:0

问题,UNity测试的时候出现错误,最后发现是改了GameObject后Untiy报错的

  • 那么得出结论E/Unity报错是Unity中的代码有问题,不是Android代码问题

参考

http://leoncvlt.com/blog/a-primer-on-android-plugin-development-in-unity/

谢谢您的鼓励~