【Unity3D】Unity与Android交互

1 Unity 发布 apk

1.1 安装 Android Build Support

在 Unity Hub 中打开添加模块窗口,操作如下。

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

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

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

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

笔者的具体环境配置如下:

Unity Editor: 2021.3.11f1c2
SDK Platforms: 29、30
SDK Build-Tools: 29.0.2、30.0.2、30.0.3
NDK: 21.3.6528147
SDK Command-line Tools: 11.0
SDK Platform-Tools: 34.0.5
Gradle: 6.1.1

1.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 页面,显示如下。

创建密钥时,也可以通过以下命令创建。

bash 复制代码
keytool -genkey -keyalg RSA -alias key_name -keystore keystore_name -validity day_time
keytool -genkey -keyalg RSA -alias first -keystore user -validity 36500

1.3 打包 apk

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

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

关闭 Player Settings,在 Build Settings 页面点击底部的 Build,构建 apk。

1.4 案例

新建一个 Unity 项目,修改 Game 页面的屏幕尺寸,如下。

搭建页面如下。

给 Button 按钮添加脚本,如下。

Test.cs

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 后,打开命令行窗口,输入以下命令安装到手机上。

bash 复制代码
adb instll -r -t -d Test.apk

运行 apk 后,在命令行窗口中通过以下命令查看日志。

bash 复制代码
adb logcat | findstr "Test-OnClick"

点击 Button 按钮,打印日志如下。

2 Unity 调 Android 的逻辑

2.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

bash 复制代码
plugins {
    id 'com.android.library'
}

android {
    namespace 'com.zhyan8.test'
    compileSdk 33
}

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 文件如下。

2.2 AndroidJavaObject 和 AndroidJavaClass

AndroidJavaObject 和 AndroidJavaClass 是 Unity 提供的调用 Java 代码的 2 个类,AndroidJavaClass 继承 AndroidJavaObject,它们只有构造方法有一点差异,没有其他的差异,因此,本节只介绍 AndroidJavaObject。

1)Set 和 Get 属性

JavaTest.java

java 复制代码
package com.zhyan8.test;

public class JavaTest {
    public static int intVal = 0;
    private String strVal = "abc";
}

说明:对于 JavaTest 的 private 属性,AndroidJavaObject 也可以访问到。

UnityTest.cs

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

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

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
    }
}

运行程序后,打印日志如下。

2.3 Unity 调用 Android 的 Toast

UnityTest.cs

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 类。

运行效果如下。

3 Android 调 Unity 的逻辑

3.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 项目中。

3.2 UnityPlayer

相关推荐
拭心11 小时前
Google 提供的 Android 端上大模型组件:MediaPipe LLM 介绍
android
带电的小王14 小时前
WhisperKit: Android 端测试 Whisper -- Android手机(Qualcomm GPU)部署音频大模型
android·智能手机·whisper·qualcomm
梦想平凡14 小时前
PHP 微信棋牌开发全解析:高级教程
android·数据库·oracle
元争栈道14 小时前
webview和H5来实现的android短视频(短剧)音视频播放依赖控件
android·音视频
阿甘知识库15 小时前
宝塔面板跨服务器数据同步教程:双机备份零停机
android·运维·服务器·备份·同步·宝塔面板·建站
元争栈道16 小时前
webview+H5来实现的android短视频(短剧)音视频播放依赖控件资源
android·音视频
MuYe16 小时前
Android Hook - 动态加载so库
android
居居飒17 小时前
Android学习(四)-Kotlin编程语言-for循环
android·学习·kotlin
Henry_He20 小时前
桌面列表小部件不能点击的问题分析
android
工程师老罗20 小时前
Android笔试面试题AI答之Android基础(1)
android