【Unity3D】Unity与Android交互
1 前言
本文主要介绍 Unity 打包发布 Android apk 流程、基于 AndroidJavaObject(或 AndroidJavaClass)实现 Unity 调用 Java 代码、基于 UnityPlayer 实现 Java 调用 Unity 代码,官方介绍见→Android。
Unity 项目 C# 中获取平台的代码如下,需要引入 UnityEngine 命名空间。
RuntimePlatform platform = Application.platform;
RuntimePlatform 是枚举类型,主要平台如下。
public enum RuntimePlatform {
OSXEditor = 0, // editor on macOS.
OSXPlayer = 1, // player on macOS.
WindowsPlayer = 2, // player on Windows.
OSXWebPlayer = 3, // web player on macOS.
...
WindowsWebPlayer = 5, // web player on Windows.
WindowsEditor = 7, // editor on Windows.
IPhonePlayer = 8, // player on the iPhone.
Android = 11, // player on Android.
...
WebGLPlayer = 17, // player on WebGL
...
LinuxPlayer = 13, // player on Linux.
LinuxEditor = 16, // editor on Linux.
...
}
2 Unity 发布 apk
2.1 安装 Android Build Support
在 Unity Hub 中打开添加模块窗口,操作如下。

选择 Android Build Support 安装,如下(笔者这里已安装过)。

创建一个 Unity 项目,依次点击【File→Build Settings→Android→Switch Platform】,配置如下。

依次点击【Edit→Preferences→External Tools】打开 JDK、SDK、NDK、Gradle 配置页面,勾选默认配置,如下。

Unity Editor 不同版本默认下载的 Gradle 版本如下,官方介绍见→Gradle for Android。

用户也可以选择已安装的 JDK、SDK、NDK、Gradle 路径,如下。

笔者的具体环境配置如下:
Unity Editor: 2021.3.11f1c2
JDK: 1.8.0_391
SDK Platforms: 29
SDK Build-Tools: 30.0.3
SDK Command-line Tools: 11.0
SDK Platform-Tools: 34.0.5
NDK: 21.3.6528147
Gradle: 6.1.1
Gradle Plugin: 4.0.1
2.2 配置密钥
依次点击【Edit→Project Settings→Player→Keystore Manager】(也可以从【File→Build Settings→Player Settings→Keystore Manager】中进入),操作如下。

打开 Keystore Manager 后, 依次点击【Create New→Anywhere】,选择一个目录保存密钥库文件,笔者保存在项目目录下面的【Keystore/user.keystore】中。

接着设置密码和别名,其他选项不是必设项。

Add Key 后,会弹出 “是否将创建的密钥库作为项目的密钥库” 弹窗,点击 yes 确认。

设置密钥后,回到 Project Settings 页面,显示如下。

创建密钥时,也可以通过以下命令创建。
keytool -genkey -keyalg RSA -alias key_name -keystore keystore_name -validity day_time
keytool -genkey -keyalg RSA -alias first -keystore user -validity 36500

2.3 打包 apk
依次点击【File→Build Settings→Player Settings】,配置公司名、项目名、版本号等信息,如下。

在 Other Settings 中配置包名、Android SDK 的最小 API 版本、目标 API 版本等信息,如下。

关闭 Player Settings,在 Build Settings 页面点击底部的 Build,构建 apk。
2.4 案例
新建一个 Unity 项目,修改 Game 页面的屏幕尺寸,如下。

搭建页面如下。

给 Button 按钮添加脚本,如下。
Test.cs
using UnityEngine;
using UnityEngine.UI;
public class Test : MonoBehaviour {
private Button button;
private void Start() {
button = GetComponent<Button>();
button.onClick.AddListener(OnClick);
}
private void OnClick() {
Debug.Log("Test-OnClick");
}
}
编译 apk 后,打开命令行窗口,输入以下命令,将 apk 安装到手机上。
adb instll -r -t -d Test.apk
运行 apk 后,在命令行窗口中通过以下命令查看日志。
adb logcat | findstr "Test-OnClick"
点击 Button 按钮,打印日志如下。

3 Unity 调 Android 的逻辑
3.1 Unity 项目中部署 Android 代码
1)拷贝 Java 源码到 Unity 项目
可以将 Android 项目中 Java 代码拷贝到 Unity 项目中 Assets 子目录下,如下,接着就可以通过 AndroidJavaClass 或 AndroidJavaObject 访问 Java 代码了。

2)打包 Jar 到 Unity 项目
可以将 Android 项目打包为 Jar,再将 Jar 拷贝到 Unity 项目中 Assets 子目录下,接着就可以通过 AndroidJavaClass 或 AndroidJavaObject 访问 Java 代码了。
修改 Android 项目中 Module 的 build.gradle 文件,如下,主要将 id 由 'com.android.application' 修改为 'com.android.library',删除 android { } 模块中的 defaultConfig、buildTypes、compileOptions 等子模块。
build.gradle
apply plugin: 'com.android.library'
android {
compileSdkVersion 29
buildToolsVersion '30.0.3'
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}
修改 build.gradle 文件后,需要点击右上角的 Sync Now 同步,接着按以下步骤编译项目。

编译结束后,在 Module 的【build\intermediates\aar_main_jar\debug】目录下生成打包的 classes.jar。

预览 classes.jar 文件如下。

3.2 AndroidJavaObject 和 AndroidJavaClass
AndroidJavaObject 和 AndroidJavaClass 是 Unity 提供的调用 Java 代码的 2 个类,AndroidJavaClass 继承 AndroidJavaObject,它们只有构造方法有一点差异,没有其他的差异,因此,本节只介绍 AndroidJavaObject。
1)Set 和 Get 属性
JavaTest.java
package com.zhyan8.test;
public class JavaTest {
public static int intVal = 0;
private String strVal = "abc";
}
说明:对于 JavaTest 的 private 属性,AndroidJavaObject 也可以访问到。
UnityTest.cs
using UnityEngine;
public class UnityTest : MonoBehaviour {
private void Start() {
AndroidJavaObject javaObject = new AndroidJavaObject("com.zhyan8.test.JavaTest");
// 静态属性Set/Get
javaObject.SetStatic<int>("intVal", 123);
int intVal = javaObject.GetStatic<int>("intVal");
Debug.Log("UnityTest, intVal=" + intVal); // 打印: UnityTest, intVal=123
// 非静态属性Set/Get
javaObject.Set<string>("strVal", "xyz");
string strVal = javaObject.Get<string>("strVal");
Debug.Log("UnityTest, strVal=" + strVal); // 打印: UnityTest, strVal=xyz
}
}
2)调用方法
JavaTest.java
package com.zhyan8.test;
import android.util.Log;
public class JavaTest {
public static void fun1() {
Log.d("JavaTest", "fun1"); // 打印: JavaTest: fun1
}
private int fun2() {
Log.d("JavaTest", "fun2"); // 打印: JavaTest: fun2
return 123;
}
public String fun3(int value) {
Log.d("JavaTest", "fun3, value=" + value); // 打印: JavaTest: fun3, value=235
return "Call fun3";
}
public String fun4(String value1, int value2) {
Log.d("JavaTest", "fun4, value1=" + value1 + ", value2=" + value2); // 打印: JavaTest: fun4, value1=abc, value2=123
return value1 + value2;
}
}
说明:对于 JavaTest 的 private 方法,AndroidJavaObject 也可以访问到。
UnityTest.cs
using UnityEngine;
public class UnityTest : MonoBehaviour {
private void Start() {
AndroidJavaObject javaObject = new AndroidJavaObject("com.zhyan8.test.JavaTest");
// 静态方法
javaObject.CallStatic("fun1");
// 非静态无参方法
int val2 = javaObject.Call<int>("fun2");
Debug.Log("UnityTest, val2=" + val2); // 打印: UnityTest, val2=123
// 非静单参方法
string val3 = javaObject.Call<string>("fun3", 235);
Debug.Log("UnityTest, val3=" + val3); // 打印: UnityTest, val3=Call fun3
// 非静双参方法
string val4 = javaObject.Call<string>("fun4", "abc", 123);
Debug.Log("UnityTest, val4=" + val4); // 打印: UnityTest, val4=abc123
}
}
运行程序后,打印日志如下。

3.3 Unity 调用 Android 的 Toast
UnityTest.cs
using UnityEngine;
using UnityEngine.UI;
public class UnityTest : MonoBehaviour {
private void Start() {
GetComponent<Button>().onClick.AddListener(() => {
Toast("Clicked", 1);
});
}
// 调用Android的代码: Toast.makeText(context, msg, durationFlag).show();
private void Toast(string msg, int durationFlag) { // durationFlag: Toast.LENGTH_SHORT=0, Toast.LENGTH_LONG=1
AndroidJavaClass toastClass = new AndroidJavaClass("android.widget.Toast");
AndroidJavaClass unityPlayerClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = unityPlayerClass.GetStatic<AndroidJavaObject>("currentActivity");
AndroidJavaObject toast = toastClass.CallStatic<AndroidJavaObject>("makeText", currentActivity, msg, durationFlag);
toast.Call("show");
}
}
UnityPlayer 是 Unity 引擎提供的 Java 类,在 Unity Editor 目录下的【Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes\classes.jar】 中。
运行效果如下。

4 Android 调 Unity 的逻辑
4.1 Unity 打包为 Android 项目
在 Build Settings 页面勾选 Export Project 后,点击 Export 按钮,如下。

构建成功后,Unity 项目将会被打包成一个 Android 项目,我们可以使用 Android Studio 打开生成的 Android 项目,如下。

其中,UnityPlayerActivity 是启动的 Main Activity,unity-classes.jar 是 Unity Editor 中的 Jar 包,位置见【Unity Hub\Unity\Editor\2021.3.11f1c2\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes\classes.jar】,我们常用的 UnityPlayer 类就在该 Jar 文件中。
如果用户想将 Android 项目打包到 Unity 项目中,但是 Android 项目中又要引用 Unity 的接口,用户可以将 Unity Editor 中的 classes.jar 拷贝到 Android 项目中,如下。

右键 classes.jar,在弹出菜单中选择 Add As Library。
4.2 UnityPlayer
UnityPlayer 继承 FrameLayout,主要用于 Java 调用 Unity 代码,其主要属性和方法如下。
// 在UnityPlayer的构造方法中初始化, currentActivity = this.mActivity
public static Activity currentActivity = null;
// java调用Unity中的方法, gameObject: 游戏对象名, method: 游戏对象上挂载脚本中的方法名, params: 方法参数
public static void UnitySendMessage(String gameObject, String method, String params)
说明:UnitySendMessage 可以调用 private 方法,只能调用无参和单参数方法,不能调用 static 方法,无法获取方法返回值。
4.3 案例
UseUnity.cs
using UnityEngine;
public class UseUnity : MonoBehaviour {
private void Start() {
AndroidJavaObject javaObject = new AndroidJavaObject("com.zhyan8.test.JavaTest");
javaObject.Call("start");
}
public void Fun1() {
Debug.Log("UseUnity-Fun1"); // 打印: UseUnity-Fun1
}
private void Fun2(string value) {
Debug.Log("UseUnity-Fun2, value=" + value); // 打印: UseUnity-Fun2, value=xyz
}
}
说明:UseUnity 脚本组件挂在 TestObj 对象上。
JavaTest.java
package com.zhyan8.test;
import android.util.Log;
import com.unity3d.player.UnityPlayer;
public class JavaTest {
public void start() {
fun1();
fun2();
}
private void fun1() {
Log.d("JavaTest", "fun1"); // 打印: JavaTest: fun1
UnityPlayer.UnitySendMessage("TestObj", "Fun1", "");
}
private void fun2() {
Log.d("JavaTest", "fun2"); // 打印: JavaTest: fun2
UnityPlayer.UnitySendMessage("TestObj", "Fun2", "xyz");
}
}
打印日志如下:

声明:本文转自【Unity3D】Unity与Android交互。
【Unity3D】Unity与Android交互的更多相关文章
- [Unity3D]Unity3D游戏开发之Unity与Android交互调用研究
各位朋友,大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei.在前一篇文章中,我们研究了Android平台上Unity3D的手势操作并在之前的基础 ...
- Unity3D游戏开发之Unity与Android交互调用研究
各位朋友,大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei.在前一篇文章中,我们研究了Android平台上Unity3D的手势操作并在之前的基础 ...
- Unity与Android交互实现
主要参考了这篇文章: Unity与Android交互方案优化版 链接:https://www.jianshu.com/p/86b275da600e 自己的实现(unity获取内存和温度): andro ...
- Unity与Android交互-Unity接入高德地图实现定位以及搜索周边的功能(使用Android Studio)详细操作
刚进公司给安排的任务就是Unity接入高德地图,算是踩了不少坑总算做出来了,抽点时间写个博客记录一下 废话不多说 先上效果图 获取定位并根据手机朝向显示周边信息 使用的Unity ...
- Unity和Android交互学习
这段时间学习Unity和Android互调,从基础开始. 网上的教程有很多,浏览了一圈教程,发现目前有两种方式:一种是直接把 .aar文件导入Unity/Plugins/Android文件夹,另一种是 ...
- unity与Android交互
unity打包成安卓工程中的JAVA代码 public class UnityPlayerActivity extends Activity { //Unity中调用此函数 public int Ma ...
- 最新Unity 与Android 交互通信(基于Unity 2019.4 和 Android Studio 4.1.1)
原文章链接:https://blog.csdn.net/woshihaizeiwang/article/details/115395519 CLSays:网上找了一圈,真的是很多都不能用,要么太老,要 ...
- Unity 和android 交互 记录
参考文章 http://www.jianshu.com/p/c06063a403c6 趟坑如下 icon 冲突问题: 设置不了unity icon,显示的是默认的 android 小人 解决方法: 在 ...
- unity与android交互总结
http://www.jianshu.com/p/4739ce2f4cd1 http://www.cnblogs.com/suoluo/p/5443889.html http://www.th7.cn ...
- 推荐两篇Unity与Android交互的文章
http://www.xuanyusong.com/archives/676 里面18,19介绍
随机推荐
- pycharm设置保存时自动格式化代码(Auto Reformat Code)
原文:https://blog.csdn.net/qq_41906934/article/details/124631826 1.手动格式化代码 Code -> Reformat Code 格式 ...
- 【收集】C & C++
序 链接 备注 1 C语言0长度数组(可变数组/柔性数组)详解_CHENG Jian的博客-CSDN博客_0数组 2 C 语言参考 | Microsoft Learn 3 C++ 语言参考 | ...
- [转帖]Rust在windows下安装以后cargo build Error: linker `link.exe` not found
D:\rust\runoob-greeting\greeting>cargo build error: linker `link.exe` not found | = note: 系统找不到指定 ...
- [转帖]Centos7 nginx访问日志文件割接
一.yum安装nginx 二.各文件路径( /etc/nginx/nginx.conf) 1.访问日志路径:access_log /var/log/nginx/access.log main; 2.p ...
- CentOS7 RPM离线安装PG12的办法
1. 先需要下载相应的rpm包 地址 https://pkgs.org/search/?q=postgresql12 一般至少要下载如下四个包 postgresql12-12.3-1PGDG.rhel ...
- Linux下PG数据库计划任务定期备份恢复的方法
注意事项 PG数据库需要注意的一点是需要安装OSSP-UUID的组件才能使用. 本次使用最除了冷备之外 最简单的 pg_dump和pg_restore的操作 的方式来进行处理 务必定期演练保证数据备份 ...
- ES客户端spring-boot-starter-data-elasticsearch
ES客户端分类 Es-Server提供RESTFul-Api,客户端通过发起http请求,调用api实现索引库的管理,数据的交换,server端状态的监控...... 官方java客户端: <d ...
- Spring Boot集成Actuator
一.Spring-Boot-Actuator简介 官网:https://docs.spring.io/spring-boot/docs/2.3.4.BUILD-SNAPSHOT/reference/h ...
- Redis极简教程
简介 Redis 是用C语言开发完全开源免费的,遵守BSD协议的,一个高性能的,key-value型的,NOSQL数据库. 特点 可以将内存中的数据持久化到硬盘中,重启的时候可以从硬盘中再次加载 拥有 ...
- JavaScript一种新的数据结构类型Map
什么是map 它类似于对象,是键值对的集合,但键的范围不局限在于字符串.各种类型的值(包含对象)都可以作为键. 如果同一个键被多次赋值,后面的值将会覆盖其那面的值.如果读取一个未知的键,返回的是und ...