Unity 和 Android 交互流程总结
- 将 Unity 安装目录下的 classes.jar 复制到 Android 项目的 libs 文件夹下
- Android 编写代码实现
- Android 导出 jar/aar
- unity 导入 jar/aar
- 利用
AndroidJavaClass
和AndroidJavaObject
调用相应的方法,实现功能
API 详解
-
AndroidJavaClass
public AndroidJavaClass(string className); // className:指定类名
- 是 java.lang.Class 的一个通用实例的统一表示,是 java 里的类,适用于返回类型为“void”的静态方法。
-
AndroidJavaObject
- 会生成一个对象,就和 java 里 new 一个对象一样,可以通过对象去调用里面的方法以及属性。
// 加载 com.td.sdktest.GameHelper 类
AndroidJavaClass jc = new AndroidJavaClass("com.td.sdktest.GameHelper");
// 实例化 com.td.sdktest.GameHelper 对象
AndroidJavaObject jo = new AndroidJavaObject("com.td.sdktest.GameHelper");
// 调用 com.td.sdktest.GameHelper 类中的 Test 静态方法
jc.CallStatic("Test");
jc.CallStatic("Test","Hello"); // 带参数的静态方法
int sum = jc.CallStatic<int>("Sum", 1, 2); // 带参数和返回值的静态方法
//调用 com.td.sdktest.GameHelper 类中的 Test 实例方法
jo.Call("Test");
jo.Call("Test","Hello");
int sum = jo.Call<int>("Sum", 1, 2);
概述
Unity 发布 Android 的基础概念
关于 classes.jar
Unity 发布 Android 的 APK 时,会使用 Android 的 SDK 进行构建,发布出来的 APK 只包含一个 Activity,俗称MainAcitivity,在发布过程中,Unity 会引入内置的 Jar 库(classes.jar),里面包含了 Unity 需要的库类,关键类 UnityPlayerActivity 就是 Android 程序的主要入口类,也就是 MainActivity。
aar 和 jar 的区别
jar:只包含了class文件与清单文件,不包含资源文件,如图片等所有 res 中的文件。
aar:包含所有资源,class 以及 res 资源文件全部包含。
关于 AndroidManifest
Unity 发布 Android 的 APK 时,如果在 Plugins/Android( Unity特殊目录 ),不存在 AndroidManifest 文件,会使用 Unity 默认的 AndroidManifest 文件。
默认的 AndroidManifest 文件目录在:Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Apk
如果存在 AndroidManifest 文件,那么 Unity 会使用它代替默认的 AndroidManifest 文件,这个AndroidManifest,必须带有活动以及标签。
关于 AndroidManifest 的合并
Unity 发布 Android 的 APK 时,关于 AndroidManifest 的合并,分为两种情况
-
不合并,导出 Jar 包时,Unity 只会识别 Plugins/Android 里的 AndroidManifest 作为描述清单或者使用默认的 AndrodManifest 文件,这时需要在描述清单需要添加权限,或其他服务,需要创建自定义的AndroidManifest,就是 Plugins/Android 目录下的 AndroidManifest 添加。
-
合并,导出 Arr 包时,Arr 包里面会带有 AndroidManifest 文件,打开查看,里面的目录结构如下:
- 在导出 APK 时,Unity 会解析 Arr 包的资源,并把它们的 AndroidManifest 文件合并到 Plugins/Android目录下的 AndroidManifest 文件或者 Unity 默认的 AndroidManifest 文件中,这样每个 Arr 包 的AndroidManifest 请求的权限或者服务最后会合并到一个 AndroidManifest 中。
- 在导出 APK 时,Unity 会解析 Arr 包的资源,并把它们的 AndroidManifest 文件合并到 Plugins/Android目录下的 AndroidManifest 文件或者 Unity 默认的 AndroidManifest 文件中,这样每个 Arr 包 的AndroidManifest 请求的权限或者服务最后会合并到一个 AndroidManifest 中。
发布 APK 的两种方式
- Internal 不需要签名,仅需 Android SDK 支持,不能导出工程 ,适用于仅适用到 Unity 开发的项目
- Gradle 需要签名(2017.3.x 之前的版本都需要), 需要 Android SDK 与 Gradle 支持,可以导出 Android Studio 工程,适用于需要与 Android 功能交互的的项目
Unity 接入 SDK 两种方法
Unity 接入 SDK 常用的方法有两种:
-
将 Unity 在安卓平台选择 Gradle 打包出来,然后在放在 AndroidStudio ,再导入需要的 SDK 进行操作。
-
将 Unity 的 classes.jar 包和需要的 SDK 导入 AndroidStudio 新建的 Library 中,然后在导出 jar 或 aar 放到Unity 中去调用。(常用)
重要的是要学会 android 怎么调用 Unity 里的方法,Unity 怎么调用 android 里的方法。
如何在 Unity 中调用 Android 的 java 代码
需要先把 android 代码打包成 jar 包(或 arr 包),然后将该 jar 包引入到 Unity 工程。
然后通过 AndroidJavaClass
和 AndroidJavaObject
进行调用。
如何在 Android 调用 Unity 的代码
在场景中创建一个游戏物体并挂载一个用于交互的脚本,Android 调用 GameObject 交互脚本上的方法,来实现相应的功能。
SDK 接入的框架搭建
Android 需要的具体步骤
在 Android 端编写代码,利用 SDK 实现具体的功能,将这些功能封装成方法,最后导出 jar 或 arr 包,将包导入 Unity,最后在 Unity 里实现调用。
可以直接新建一个 Android 项目进行编写,也可以创建一个 Libray 模块进行编写,任选其一即可。
新建 Android 项目
利用 Android Libray Module
File -> New -> New Module -> Android Libray
复制 unity 的 classes 到 android
Unity 和 Android 做交互,他们两个之间不认识肯定,没法直接通信,因此需要一个中间的搭桥牵线的人,Classes.jar 就起到了这个作用。Classes.jar 是由 Unity 提供给我们的,我们需要找到它并且引入到我们的Android 项目中。
将 Unity 安装目录下的 classes.jar 复制到 Android 项目的 libs 文件夹下(建议改名后复制,方便辨认和管理),并添加依赖。
D:\Unity\2018.4.2f1\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes
该目录可能不同,可以直接在安装目录下搜索 Classes.jar
。
新建 MainActivity
编写一个静态函数,和一个普通函数,供 Unity 调用
package com.td.sdkaccess;
import android.os.Bundle;
import com.unity3d.player.*; // 复制过来的 unity_classes.jar
public class MainActivity extends UnityPlayerActivity { // 注意是 UnityPlayerActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
/**
* 供 Unity 调用的求和函数(静态)
*/
public static int Sum(int x, int y) {
return x + y;
}
/**
* 供 Unity 调用的显示吐司的函数
*/
public void MakeToast(String str) {
Toast.makeText(this, str, Toast.LENGTH_LONG).show();
}
}
导出 jar 或 arr
-
如果是之前是直接使用 app 项目,导出 jar,需要做如下配置,如果使用的是 Libray Module 则不需要。
-
app 项目:修改 app 下的 build.gradle 文件
//apply plugin: 'com.android.application' apply plugin: 'com.android.library' // 不生成 apk,生成 jar/aar 包 android { defaultConfig { // applicationId "com.td.sdktest" 注释这一行 ... } ... // 方便操作,复制 jar 到指定位置,在 Termanil 窗口使用输入命令 gradlew makejar task makeJar(type:Copy){ delete 'build/libs/sdk.jar' from('build/intermediates/bundles/release/') into('build/libs/') include('classes.jar') rename('classes.jar','sdk.jar') }
-
-
Build -> Rebuild Project
-
到相应目录查看 jar/aar,(android studio 版本不同,输出目录可能不一样)
Unity 需要的具体步骤
导入 jar/aar
将 Android 导出的 jar 或 aar 复制到项目 Plugins/Android 目录下
如果导入的是 aar,有以下几点需要注意:
- 删除 unity_classes.jar 冲突文件,在 aar 的 lib 里
- 删除包根目录下面的 Android 配置文件(先复制一份出来)
- 删除 aar 跟目下的 classes.jar 里面的 BuildConfig.class 文件
其实不清楚这 3 步是否是必须的,但是因为各种花式报错,最后经验证通过这三步可以解决。
AndroidManifest 文件
这里可以使用 Unity 导出,然后使用里面的 AndroidManifest 文件进行修改。
根据自己的项目,修改 AndroidManifest 文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.td.sdkbase"
android:versionCode="1"
android:versionName="1.0" > <!-- 包名 -->
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="29" />
<application
android:allowBackup="true"
android:icon="@drawable/app_icon"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@android:style/Theme.Light.NoTitleBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" /><!-- 注意 -->
</activity>
</application>
</manifest>
编写界面和交互脚本
在场景中创建物体用于挂载与 Android 交互的脚本。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MainPanel : MonoBehaviour {
private AndroidJavaClass _jc;
private AndroidJavaObject _jo;
public Text resultLabel;
void Start() {
// 获取 Unity 导出的 Activity 对象,固定写法,UnityPlayerActivity 里面对其进行了处理
_jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); // Unity 要导出的 MainActivity 类
_jo = _jc.GetStatic<AndroidJavaObject>("currentActivity"); // 获取 MainActivity 的实例对象
}
public void Sum() {
AndroidJavaClass jc = new AndroidJavaClass("com.td.sdkbase.MainActivity"); // 加载自己的类,指定实现了需要调用相应方法的类
resultLabel.text = "Sum:" + jc.CallStatic<int>("Sum", 1, 5); // 调用 Java 类中的静态方法 Sum,返回值为 int 型,参数 1,5
}
public void Toast() {
_jo.Call("MakeToast", "Unity 调用 Android,显示 Toast"); // 调用 Java 类中的普通方法
}
}
Build APK
注意修改包名
真机测试运行
参考文章
Unity与Android——Androidmanifest.xml文件的介绍