Unity3d_android交互
Unity3D 与 Android 的交互具有一定特殊性。在打包方面,Unity for iOS 会将 Xcode 工程直接交付给开发者,开发者能够在该工程基础上添加新视图,最后自行打包生成 IPA 包来发布程序。而 Unity for Android 则直接生成 APK 包,开发者无法看到源代码。由于 Unity 自身存在一些局限性,针对 Android 平台,我们需要学习如何在 Unity 中调用 Android 的 Java 代码。本章的目标是使用 Unity 的脚本打开 Activity。
1. 创建 Android 工程
首先,我们要创建一个普通的 Android 工程。因为项目需要使用 Unity 提供的接口,所以要将接口 classes.jar 引入到当前工程中。接口包的位置获取方式如下:打开 Finder -> 应用程序 -> Unity -> 点击 Unity 图标,鼠标右键选择“显示包内容” -> Contents -> PlaybackEngines -> AndroidPlayer -> bin -> classes.jar 。引入接口包后,开始编写 Java 代码。
1.1 UnityTestActivity.java
package com.xys;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import com.unity3d.player.UnityPlayerActivity;
public class UnityTestActivity extends UnityPlayerActivity {
/** Called when the activity is first created. */
Context mContext = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
}
public void StartActivity0(String name) {
Intent intent = new Intent(mContext, TestActivity0.class);
intent.putExtra("name", name);
this.startActivity(intent);
}
public void StartActivity1(String name) {
Intent intent = new Intent(mContext, TestActivity1.class);
intent.putExtra("name", name);
this.startActivity(intent);
}
}
UnityTestActivity 是主 Activity,Unity 程序启动时会调用该 Activity,它在 AndroidManifest.xml 中进行配置。该类需要继承 UnityPlayerActivity,此接口类由刚刚引入的 classes.jar 包提供。UnityTestActivity 对外提供了两个方法接口:StartActivity0(String name) 和 StartActivity1(String name),这两个方法将在 Unity 中使用 C# 脚本调用,调用后程序会打开一个新的 Activity,参数 name 由 C# 脚本传递,并继续传递给新打开的 Activity。
1.2 TestActivity0.java
package com.xys;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class TestActivity0 extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView text = (TextView) this.findViewById(R.id.textView1);
text.setText(this.getIntent().getStringExtra("name"));
Button close = (Button) this.findViewById(R.id.button0);
close.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
TestActivity0.this.finish();
}
});
}
}
1.3 TestActivity1.java
package com.xys;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class TestActivity1 extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView text = (TextView) this.findViewById(R.id.textView1);
text.setText(this.getIntent().getStringExtra("name"));
Button close = (Button) this.findViewById(R.id.button0);
close.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
TestActivity1.this.finish();
}
});
}
public void Start() {
}
}
TestActivity0 和 TestActivity1 是两个新打开的 Activity,它们属于 Unity 程序的子 Activity,因此不需要继承 UnityPlayerActivity,直接继承 Activity 即可。在代码中监听了一个按钮,点击按钮后会关闭当前的 Activity。通过 this.getIntent().getStringExtra("name") 方法,可以获取上个界面传递过来的字符串,并显示在屏幕上,用于区分新打开的 Activity。
1.4 main.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/screen"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical">
<ImageView
android:src="@drawable/jay"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
<TextView android:id="@+id/textView0"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#000000"
android:textSize="18dip"
android:background="#00FF00"
android:text="带你走进Unity for Android的世界"
android:gravity="center_vertical|center_horizontal"
/>
<TextView android:id="@+id/textView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#FFFFFF"
android:textSize="18dip"
android:background="#0000FF"
android:text="Unity与Android之间的交互"
android:gravity="center_vertical|center_horizontal"
/>
<Button android:id="@+id/button0"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:text="关闭这个Activity"/>
</LinearLayout>
</ScrollView>
此布局文件学过 Android 开发的朋友应该比较容易理解,这里不再详细解释。
1.5 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xys"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="7" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:name=".UnityTestActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".TestActivity0"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
>
</activity>
<activity
android:name=".TestActivity1"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
>
</activity>
</application>
</manifest>
这里配置了代码中的三个 Activity,并将 UnityTestActivity 标志为主 Activity。需要注意的是,继承了 UnityPlayerActivity 后在 Eclipse 中无法运行,必须在 Unity 真机环境下才能运行。
2. 打包 Android 代码
构建当前的 Eclipse 工程后,所有的 .class 文件会生成在 Android 工程的 bin 文件夹中,当前工程的路径为 UnityTestActivity->bin->classes->com->xys->你的.class 文件。接下来需要对这些 .class 文件进行打包。在苹果系统中,打开电脑的终端,使用 cd 命令进入 classes 文件夹的目录下,然后执行以下代码:
jar -cvf class.jar *
这行代码的作用是将当前目录下的所有 .class 文件打包成一个名为 class.jar 的文件。打包完成后,class.jar 文件会生成在 bin->classes-> 目录中。请确保解开的包与你的 Android 对应的包名一致,例如,我的包名是 com.xys,那么文件夹结构应该是 class->com->xys->.class 代码。
3. 创建 Unity 工程
3.1 文件夹结构设置
Unity 工程中文件夹的结构如下:Plugins->Android 的名称不能修改,必须保持一致。将 Eclipse 中 Android 工程除 src 文件夹外的其他文件夹全部拷贝至 Plugins->Android 文件夹中。最后在 Plugins->Android 文件夹中创建 bin 文件夹,并将刚刚生成的 .jar 文件拷贝进来,.jar 文件的名称可以随意修改,但包内必须是 com->xys->你的 class 文件,否则运行程序时会提示找不到类文件。
3.2 创建 C# 脚本
在 Unity 工程中创建一个 C# 脚本 Test.cs,并将其绑定在摄像机上,该脚本用于通知界面打开 Activity。利用 GUI 在屏幕中创建两个按钮,点击按钮可以打开不同的 Activity。
using UnityEngine;
using System.Collections;
public class Test : MonoBehaviour
{
// Update is called once per frame
void Update()
{
// 当用户按下手机的返回键或 home 键退出游戏
if (Input.GetKeyDown(KeyCode.Escape) || Input.GetKeyDown(KeyCode.Home))
{
Application.Quit();
}
}
void OnGUI()
{
if (GUILayout.Button("OPEN Activity01", GUILayout.Height(100)))
{
// 注释 1
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
jo.Call("StartActivity0", "第一个Activity");
}
if (GUILayout.Button("OPEN Activity02", GUILayout.Height(100)))
{
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
jo.Call("StartActivity1", "第二个Activity");
}
}
}
注释 1:先获取 AndroidJavaClass,然后获取 AndroidJavaObject,该对象表示当前 Activity,即之前创建的 UnityTestActivity.java。获取对象后,使用 jo.Call() 方法调用 UnityTestActivity.java 类中的方法,第一个参数为方法名称,第二个参数为传递给该方法的参数。例如,“第一个 Activity” 和 “第二个 Activity” 就是在 C# 中传递的字符串。
在打开的 Activity 中点击“关闭这个 Activity 按钮”,程序将回到原来的界面。最后要注意,Unity 中的包名必须和 Android 工程保持一致,否则无法调用。例如,Bundle Identifier 当前项目为 com.xys 。
希望大家继续认真阅读本篇博文,深入理解 Unity3D 与 Android 的交互过程。