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交互的更多相关文章

  1. [Unity3D]Unity3D游戏开发之Unity与Android交互调用研究

    各位朋友,大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei.在前一篇文章中,我们研究了Android平台上Unity3D的手势操作并在之前的基础 ...

  2. Unity3D游戏开发之Unity与Android交互调用研究

    各位朋友,大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei.在前一篇文章中,我们研究了Android平台上Unity3D的手势操作并在之前的基础 ...

  3. Unity与Android交互实现

    主要参考了这篇文章: Unity与Android交互方案优化版 链接:https://www.jianshu.com/p/86b275da600e 自己的实现(unity获取内存和温度): andro ...

  4. Unity与Android交互-Unity接入高德地图实现定位以及搜索周边的功能(使用Android Studio)详细操作

    刚进公司给安排的任务就是Unity接入高德地图,算是踩了不少坑总算做出来了,抽点时间写个博客记录一下 废话不多说 先上效果图 获取定位并根据手机朝向显示周边信息            使用的Unity ...

  5. Unity和Android交互学习

    这段时间学习Unity和Android互调,从基础开始. 网上的教程有很多,浏览了一圈教程,发现目前有两种方式:一种是直接把 .aar文件导入Unity/Plugins/Android文件夹,另一种是 ...

  6. unity与Android交互

    unity打包成安卓工程中的JAVA代码 public class UnityPlayerActivity extends Activity { //Unity中调用此函数 public int Ma ...

  7. 最新Unity 与Android 交互通信(基于Unity 2019.4 和 Android Studio 4.1.1)

    原文章链接:https://blog.csdn.net/woshihaizeiwang/article/details/115395519 CLSays:网上找了一圈,真的是很多都不能用,要么太老,要 ...

  8. Unity 和android 交互 记录

    参考文章 http://www.jianshu.com/p/c06063a403c6 趟坑如下 icon 冲突问题: 设置不了unity icon,显示的是默认的 android 小人 解决方法: 在 ...

  9. unity与android交互总结

    http://www.jianshu.com/p/4739ce2f4cd1 http://www.cnblogs.com/suoluo/p/5443889.html http://www.th7.cn ...

  10. 推荐两篇Unity与Android交互的文章

    http://www.xuanyusong.com/archives/676 里面18,19介绍

随机推荐

  1. pycharm设置保存时自动格式化代码(Auto Reformat Code)

    原文:https://blog.csdn.net/qq_41906934/article/details/124631826 1.手动格式化代码 Code -> Reformat Code 格式 ...

  2. 【收集】C & C++

    序 链接 备注 1 C语言0长度数组(可变数组/柔性数组)详解_CHENG Jian的博客-CSDN博客_0数组   2 C 语言参考 | Microsoft Learn   3 C++ 语言参考 | ...

  3. [转帖]Rust在windows下安装以后cargo build Error: linker `link.exe` not found

    D:\rust\runoob-greeting\greeting>cargo build error: linker `link.exe` not found | = note: 系统找不到指定 ...

  4. [转帖]Centos7 nginx访问日志文件割接

    一.yum安装nginx 二.各文件路径( /etc/nginx/nginx.conf) 1.访问日志路径:access_log /var/log/nginx/access.log main; 2.p ...

  5. CentOS7 RPM离线安装PG12的办法

    1. 先需要下载相应的rpm包 地址 https://pkgs.org/search/?q=postgresql12 一般至少要下载如下四个包 postgresql12-12.3-1PGDG.rhel ...

  6. Linux下PG数据库计划任务定期备份恢复的方法

    注意事项 PG数据库需要注意的一点是需要安装OSSP-UUID的组件才能使用. 本次使用最除了冷备之外 最简单的 pg_dump和pg_restore的操作 的方式来进行处理 务必定期演练保证数据备份 ...

  7. ES客户端spring-boot-starter-data-elasticsearch

    ES客户端分类 Es-Server提供RESTFul-Api,客户端通过发起http请求,调用api实现索引库的管理,数据的交换,server端状态的监控...... 官方java客户端: <d ...

  8. Spring Boot集成Actuator

    一.Spring-Boot-Actuator简介 官网:https://docs.spring.io/spring-boot/docs/2.3.4.BUILD-SNAPSHOT/reference/h ...

  9. Redis极简教程

    简介 Redis 是用C语言开发完全开源免费的,遵守BSD协议的,一个高性能的,key-value型的,NOSQL数据库. 特点 可以将内存中的数据持久化到硬盘中,重启的时候可以从硬盘中再次加载 拥有 ...

  10. JavaScript一种新的数据结构类型Map

    什么是map 它类似于对象,是键值对的集合,但键的范围不局限在于字符串.各种类型的值(包含对象)都可以作为键. 如果同一个键被多次赋值,后面的值将会覆盖其那面的值.如果读取一个未知的键,返回的是und ...