Unity 与 Android (Android Studio)的交互问题研究 (一)
来源:互联网 发布:linux git 配置文件 编辑:程序博客网 时间:2024/05/16 11:56
Unity 与 Android (Android Studio)的交互问题研究 (一)
之前公司有个AR相关的项目,里面用到的3D模型是用Unity搭建的。
由于Unity程序在手机端独立运行于自己的虚拟机中(mono/il2cpp),因此具备了强大的跨平台能力,我们可以用它直接编译生成能够运行在IOS与Android两大平台的程序。
事实上整个项目绝大部分都是由Unity的C#编写的,这样好处很多,主要是不用针对不同平台做移植,节省了很大的资源。
不过事情也没有绝对,Andorid版后期需要开发一个录屏功能,可能是因为涉及到底层C/C++的库,所以必须要用原生的代码(Java)来写一个方法实现,然后由Unity来调用,操纵摄像头。
在网上查了很多资料,自己也踩了很多的坑,不过磕磕绊绊总算是有点头绪,所以决定趁这次机会总结归纳一下。
关键在于Unity与Android之间的交互机制
我们知道,Android程序都是运行在dalvik/art虚拟机上的,而Unity程序是在(mono/il2cpp)上。当一个Unity应用想要用到Andorid的方法的话,毫无疑问,这个应用就需要两套虚拟机同时运行,即两个虚拟机运行在同一个进程中。
那么,Unity与Android之间的交互问题,其实就是两个VM之间的相互调用:如下图
如上图所示,Unity通过UnityEngine提供的API调用Android的方法;Android借助com.unity.player包提供的API调用Unity的方法。
此次我们主要讨论Unity调用Android,Android调用Unity不过多深入。
Android部分
Unity调用Android,需要在Android项目中封装一系列方法,然后打成Jar包供Unity使用。
由于AS没有直接导出Jar包的方法,所以这次我们利用了AS的Module Build会生成Jar包的原理。
打开AndroidStudio,New一个Project,我们这里命名为AndroidPlugin。之后我们再New一个Module出来,类型为Android Library,命名为android2u3d。
在此Module里,New一个Activity,并勾选上Launcher Activity选项。
接下来,我们会编写这个Activity,主要是在里面写一些方法供Unity调用。
在此之前,我们还要用到一个Unity提供给Android的包,这个包提供了支持该平台的Player。根据Unity版本的不同,包的位置会略有不同。笔者用的是5.3.4,位置在Unity安装目录\Editor\Data\PlaybackEngines\Androidplayer\Variations\il2cpp\Release\Classes\classes.jar(注意到Variations下有两个目录:il2cpp和mono,这是Unity项目脚本执行器的类型,有mono和il2cpp两种,与Unity项目的”Script Backend”一致)。接着将其放置到Module下的libs目录,右键点击Add As Library,将其置为Module的File Dependency。
开始编写Activity:
package com.example.yaoobs.android2u3d;import android.app.AlertDialog;import android.content.Context;import android.content.Intent;import android.os.Bundle;import android.os.Vibrator;import android.widget.Toast;/* 引入Unity的包,在之前Unity的classes.jar里 */import com.unity3d.player.UnityPlayer;import com.unity3d.player.UnityPlayerActivity;/* 如果需要Activity与Unity对接,可以通过继承UnityPlayerActivity来实现 */public class MainActivity extends UnityPlayerActivity { private Context mContext = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mContext = this; } /* 定义一个调用Unity方法的方法 ,基于UnitySendMessage实现 。 * 由于没有布局文件,我们在这里通过Unity调用这个方法*/ public void InvokeUnity(String mStr) { UnityPlayer.UnitySendMessage("Unity2Android", "SetCameraColor", ""); } // 定义一个显示对话框的方法,在Unity中调用此方法 public void ShowDialog(final String mTitle, final String mContent) { // 在UI线程下执行 runOnUiThread(new Runnable() { @Override public void run() { AlertDialog.Builder mBuilder = new AlertDialog.Builder(MainActivity.this); mBuilder.setTitle(mTitle).setMessage(mContent).setPositiveButton("OK", null); mBuilder.show(); } }); } // 定义一个显示Toast的方法,在Unity中调用此方法 public void ShowToast(final String mStr2Show) { // 同样需要在UI线程下执行 runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), mStr2Show, Toast.LENGTH_LONG).show(); } }); } // 定义一个手机振动的方法,在Unity中调用此方法 public void SetVibrator(final long[] mTime) { Vibrator mVibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE); mVibrator.vibrate(mTime, -1); //-1:表示不重复 0:循环的震动 }}
如上所示,我们删掉了布局文件,然后定义了4个方法,显示Dialog跟Toast,手机振动,还有一个调用Unity方法的。别忘了在AndroidManifest.xml添加权限:
<uses-permission android:name="android.permission.VIBRATE"></uses-permission>
为了导出Jar包,我们需要在Module下的build.gradle里添加一个task,如下:
task makeJar(type: Copy) { delete 'build/libs/android2u3d.jar' from('build/intermediates/bundles/release/') into('build/libs/') include('classes.jar') rename('classes.jar', 'android2u3d.jar')}makeJar.dependsOn(build)
上面的命令无非就是拷贝删除重命名而已,就不多说了。
打开AS的Terminal,输入:gradlew makeJar
等待出现BUILD SUCCESSFUL字样,就可以在Module/build/libs下找到android2u3.jar
如果出现lint检查错误,在Module下的build.gradle里添加:
android{...lintOptions{ abortOnError false }...}
就没事了。
最好把src下的androidTest和test,即UI测试与单元测试相关的目录删掉,再把没有用到的譬如
testCompile ‘junit:junit:4.12’ compile ‘com.android.support:appcompat-v7:23.1.0’
的Dependency删掉。
Unity部分
打开Unity,New一个Project,命名为Unity2Android,在Project/Assets/Plugins/Android/bin(标黑的是需要自己Create的目录)下放入之前的android2u3d.jar。Android下放入Module的AndroidManifest.xml文件。
接着在Plugins的同级目录下Create一个Script目录,在其下Create一个C# Script,我们将其命名为:AndroidAPI.cs,编写代码如下:
using UnityEngine;using System.Collections;public class AndroidAPI : MonoBehaviour { //在Android中我们将使用这个名字 void Start () { this.name="Unity2Android"; } void SetCameraColor() { //设置摄像头背景颜色 Camera.main.backgroundColor=new Color(1.0F,0.5F,0.5F); } void Update () { // 返回键退出 if(Input.GetKey(KeyCode.Escape)) Application.Quit(); } void OnGUI () { // 通过API调用对话框 if(GUILayout.Button("调用安卓Jar中的方法ShowDialog",GUILayout.Height(50))) { //获取Android的Java接口 AndroidJavaClass jc=new AndroidJavaClass("com.unity3d.player.UnityPlayer"); AndroidJavaObject jo=jc.GetStatic<AndroidJavaObject>("currentActivity"); //构造参数 string[] mString=new string[2]; mString[0]="Unity2Android"; mString[1]="Talk is cheap,Show me the code!"; //调用方法 jo.Call("ShowDialog",mString); } // 通过API调用Toast if(GUILayout.Button("调用安卓Jar中的方法ShowToast",GUILayout.Height(50))) { AndroidJavaClass jc=new AndroidJavaClass("com.unity3d.player.UnityPlayer"); AndroidJavaObject jo=jc.GetStatic<AndroidJavaObject>("currentActivity"); jo.Call("ShowToast","HELLO WORLD!"); } // 通过API调用手机震动的方法 if(GUILayout.Button("调用安卓Jar中的方法SetVibrator",GUILayout.Height(50))) { long[] mTime = new long[]{ 200, 2000, 2000, 200, 200, 200 }; AndroidJavaClass jc=new AndroidJavaClass("com.unity3d.player.UnityPlayer"); AndroidJavaObject jo=jc.GetStatic<AndroidJavaObject>("currentActivity"); jo.Call("SetVibrator",mTime); } //通过API调用Toast if(GUILayout.Button("通过SendMessage调用Unity中的方法",GUILayout.Height(50))) { //获取Android的Java接口 AndroidJavaClass jc=new AndroidJavaClass("com.unity3d.player.UnityPlayer"); AndroidJavaObject jo=jc.GetStatic<AndroidJavaObject>("currentActivity"); jo.Call("InvokeUnity",""); } } }
可以看到,在Unity里调用Android的方法是通过AndroidJavaObject与AndroidJavaClass这两个类来实现的。首先获取到MainActivity,接着调用指定方法(关于具体原理可以去看UnityPlayer与UnityPlayerActivity的源码,我们将放在之后讲解)。值得注意的是Android的InvokeUnity这个方法,Unity调用它后,它又去调用Unity的SetCameraColor这个方法。通过UnitySendMessage这个方法,可以调用Unity中指定GameObject所挂载的脚本的方法,而GameObject的名字,就是这里
void Start () { this.name="Unity2Android"; }
指定的名字,必须与Android代码中的
public void InvokeUnity(String mStr) { UnityPlayer.UnitySendMessage("Unity2Android", "SetCameraColor", ""); }
第一个参数保持统一,第二个参数是方法名,第三个参数应该是传参,没有验证。
之后将这个 AndroidAPI.cs 拖动到 Main Camera 上进行绑定。
如果是第一次使用,还需配置AndroidSDK的Location。在菜单栏 ->Edit -> Preferences -> External Tools里设置。
之后是BuildSettings设置,切换到Android平台,勾选Development build和Autoconnect profiler,Texture Compression选择 ETC(default),Player Settings设置BundleID和最小APIlevel,最后Create New Keystore,最后连接设备,BuildAndRun。
项目已上传GitHub,地址:https://github.com/Yaoobs/UnityAndroidPluginDemo
参考文章:
http://mp.weixin.qq.com/s?__biz=MzI1NjEwMTM4OA==&mid=2651231917&idx=1&sn=ce2e0f7251e26f7b5a9b2fddadf96bcc&scene=23&srcid=0705qPTKw0LXSdy8hRQfBegv#rd
http://blog.csdn.net/kuerjinjin/article/details/50177633
http://blog.csdn.net/qinyuanpei/article/details/39348677
- Unity 与 Android (Android Studio)的交互问题研究 (一)
- Unity 与 Android (Android Studio)的交互
- Unity 与 Android (Android Studio)的交互
- Android与Unity交互研究
- Android与Unity交互研究
- Android与Unity交互研究
- Android 与 Unity 交互一
- unity-与Android交互(unity5、android studio)
- unity-与Android交互(unity5、android studio)
- Unity与Android交互调用研究
- Android Studio与Unity的交互出现的错误
- [Android交互]Android与Unity的交互
- Unity与Android的交互,使用Android Studio导出各Unity工程通用的Android插件包
- unity android 交互的问题
- unity与Android的交互
- Unity与Android的交互
- 从零开始实现Unity与Android的交互(一)
- unity与android交互
- HDOJ/HDU 1982 Kaitou Kid - The Phantom Thief (1)(字符串处理)
- (Macbook Air)BCM4360网卡Linux(Ubuntu/Fedora)驱动安装总结
- 几种相册图片布局方式
- 实例讲解设计模式中的命令模式在iOS App开发中的运用
- BUG:eclipse中添加V7包ERROR: In <declare-styleable> MenuView, unable to find attribute android:pre
- Unity 与 Android (Android Studio)的交互问题研究 (一)
- 基于用户协同过滤与基于物品协同过滤的比较
- 静态顺序表实现简单的通讯录
- 电脑Windows使用中遇到的那些问题
- Java常用排序算法之希尔排序
- jQuery和Prototype的兼容性和冲突的五种解决方法
- css3 绘图 (跳动的心 和太极图)
- 一致性hash算法与java实现
- HTML5