1.背景
这里的实现是在Android studio 2.2和Unity 5.4上。本人是Android开发者,因为公司的业务需求需要与unity进行对接。那么暴露出来最需要解决的问题就是android上实现的方法和unity脚本上实现的方法如何进行相互的调用。在解决该问题的过程中,找了很多的教程以及google了很多其中问题的解决方法。下面就是我整理出来的一些操作步骤和问题的解决方式。
2 Android上的操作
2.1 新建Android项目
首先新建一个android项目,file-->new-->new project,这里新建项目的名称为UnityAndroid,包名为cn.unity.android,一直点击next到finish就ok了。

然后将项目切换成project的格式,打开app目录下的build.gradle文件,将
apply plugin: 'com.android.application'
,改成apply plugin: 'com.android.library'
,因为android studio只有在这种格式下才可以导出unity需要使用的aar或者jar文件。然后删除defaultConfig下的applicationId,去掉默认的dependencies下的compile 'com.android.support:appcompat-v7:25.0.0'
的引入,因为这里不需要用到它,而且这个包包含了很多的资源文件我们是用不到的,最后格式为。

接下来我们需要修改AndroidManifest文件和res文件,首先删除values下的style.xml文件,因为这里面默认包含的是之前删除的
com.android.support:appcompat-v7:25.0.0
包里面的主题。然后修改AndroidManifest文件中application下的theme为android自带的主题。同时将<activity android:name=".MainActivity">
修改为<activity android:name="cn.unity.android.MainActivity">
,防止在unity中导出的app与AndroidManifest中的包名不一致产生的问题。然后添加<meta-data>信息,否则在 Unity 导出 APK 时会报找不到manifest 文件的错误信息
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
最后得到的AndroidManifest和res的格式如下


2.2 引入unity的 classes.jar包
找到unity的classes.jar包。windows下和mac下包的路径分别为
C:\ProgramFiles\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\classes.jar
/Applications/Unity/PlaybackEngines/AndroidPlayer/Variations/mono/Release/Classes\classes.jar
将其拷贝到UnityAndroid项目app目录下的libs目录下,然后进行导入,导入之后可以发现在build.gradle中就有他的引入了。


2.3 为unity写android方法
首先需要让MainActivity继承UnityPlayerActivity,因为unity导出的app的视图展示需要在UnityPlayerActivity下。假如MainActivity继承的是Activity,那么显示的就是Android自己的界面。在这里我们写两个方法,一个是弹出Toast通知,一个是获取当前时间,具体代码如下。
package cn.unity.android;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.widget.Toast;
import com.unity3d.player.UnityPlayerActivity;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class MainActivity extends UnityPlayerActivity {
private Toast mToast;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void showToast(final String text) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
public void run() {
if (mToast == null) {
mToast = Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT);
} else {
mToast.setText(text);
}
mToast.show();
}
});
}
public String getNowTime() {
long time = System.currentTimeMillis();
return new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss", Locale.CHINESE).format(new Date(time));
}
}
接下来需要导出aar包和jar包,为接下来unity调用提供方法。点击build-->build apk,然后在app-->build-->outputs-->aar目录下的到app-debug.aar文件

将app-debug.aar文件解压,得到根目录下的classes.jar文件,请注意这个classes.jar文件并不是最开始从unity中导入到android的classes.jar文件,而且你写的android代码的class文件的压缩包(可以解压看看里面实际的内容)。之后unity所需要使用的是res文件夹下的文件,classes.jar(android的)和AndroidManifest文件。

(ps:理论上来说现在版本的unity是直接可以使用android的aar包的,但是博主在实际使用过程中一直会有问题,所以这边所使用的还是jar包和res文件的形式,如果有小伙伴使用aar成功的话请告知博主)
3 Unity上的操作
3.1 创建Unity项目
打开unity,创建项目名称为UnityDemo,layout的格式改为2by3,project下修改为One column layout(纯粹是个人喜欢这种布局的方法,当然你也可以用其他的)。


往unity添加一个canvas(画布),设置render mode为screen space camera(跟随相机的模式),然后设置ui scale mode 为scale with screen camera 并设置x,y为600和400。

往canvas中添加一个text和一个button,并调整他们的大小和位置,用于之后的事件操作和显示。


然后将我们之前导出的jar和res文件拷贝到Plugins/Android文件夹下。

3.2 编写unity脚本
新建一个AndroidControl的C#脚本,并将其挂载到Canvas对象上。(直接通过鼠标左键拖动到Canvas上)。打开脚本,在OnStart()方法中获取android的MainActivity对象。
private AndroidJavaObject jo;
void Start ()
{
//获取Android的Java接口
AndroidJavaClass jc = new AndroidJavaClass ("com.unity3d.player.UnityPlayer");
jo = jc.GetStatic<AndroidJavaObject> ("currentActivity");
}
首先获取unityPlayer实例,每个unity app在启动的时候都会有一个unityPlayer实例。通过获取该实例里面currentActivity对象,其实就是我们的MainActivity实例。我们可以在android studio中查看源码的方式知道为什么是获取这个currentActivity。

创建方法ShowAndroidTime来获取系统时间并进行显示。
public void ShowAndroidTime ()
{
string time = jo.Call<string> ("getNowTime");
jo.Call ("showToast", new object[]{ time });
}
首先调用MainActivity中的getNowTime方法得到时间,然后在调用showToast方法让时间Toast出来。接下来是要对button设置点击事件去调用这个ShowAndroidTime方法。选中button,然后砸onclick点击+。由于我们的脚本是挂在到Canvas上的,所以需要选择canvas对面里面的AndroidControl脚本的ShowAndroidTime方法。

3.3 导出Android app
将scene保存,然后点击file-->build settings,选择platform为android,然后点击switch platform,同时将要导出的scene add进来。

点击player settings进行一些android 导出的设置。在这里我们设置apk的名称为UnityDemo,显示为横屏,设置包名为cn.unity.demo,要注意的是把install location设置为Automatic,否则apk会安装失败,同时需要指定apk的签名。




最后点击build导出apk,如果已经连接上android设备的话,可以直接build and run进行导出和启动。

看下我们最终实现的效果

4 Android上调用Unity的方法
以上我们实现了unity上调用android的方法,那么android上如何调用unity的方法呢,我们先回到unity的AndroidControl脚本。添加方法OnTimeResult,注意在这里需要导入UnityEngine.UI包usingUnityEngine.UI;
public void OnTimeResult (string result)
{
Text text = GameObject.Find ("TimeShow").GetComponent<Text> ();
text.text = result;
}
上面代码的意思是获取名称为TimeShow的对象,然后将该对象上的Text脚本的文本改为得到的result。所以我们需要将之前的Text对象名称改为TimeShow

回到android的MainActivity,修改方法showToast,让Toast时间的时候同时调用OnTimeResult方法修改text的文本。
public void showToast(final String text) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
public void run() {
if (mToast == null) {
mToast = Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT);
} else {
mToast.setText(text);
}
mToast.show();
UnityPlayer.UnitySendMessage("Canvas","OnTimeResult",text);
}
});
}
UnityPlayer.UnitySendMessage("Canvas","OnTimeResult",text);
方法的意思是调用名称为Canvas对象上的OnTimeResult方法,传入的参数为text。这样我们的操作就完成了,重复上面的操作,我们来看下效果。

5 使用adb logcat查看日志
上述的过程已经完成了unity和android之间的方法的相互调用,但是问题来了。这样没有出错还好,一旦出错,如何查看日志呢。这个时候我们可以使用android的adb工具了。(使用之前我们需要配置环境变量,至于如何配置adb的环境,这里就不多阐述了)。
在unity的脚本代码中,增加日志的输出。并导出apk
public void OnTimeResult (string result)
{
Text text = GameObject.Find ("TimeShow").GetComponent<Text> ();
text.text = result;
Debug.Log ("UnityTime-->"+result);
}
打开控制台,输入adb logcat -s Unity,然后打开apk,点击button,这个时候就可以看到刚刚的日志输出了。(ps:更多的adb logcat的语法可以自己百度google查看)


6 后续:
至此,一个比较完整的unity和android交互的步骤和如何查看日志就已经完成了。如果大家在学习使用的过程有什么问题或者有什么更好的方法方式欢迎一起交流。
网友评论
结果报错 “cn.unity.andrion.test:layout_constraintBottom_toBottomOf' not found.”
1.引入unity的 classes.jar包,我的mac系统unity中这个包是不可用的,复制过去导入后build会报错,unity3d未导入成功,解决方案是从别处重新找了个classes.jar替换;
2.在unity项目中Plugins/Android文件夹下可直接粘贴解压出来的app-debug文件夹(要删掉内部libs中的class文件),把app-debug文件夹中的全部文件拖入会报错,但是直接放app-debug文件就没问题。。本人亲测
希望能帮到后面看的小伙伴