Unity与Android交互通信系列(3)

本文详细介绍了如何在Unity中通过创建Android模块并生成aar包,实现与Android原生代码的模块化通信,以及使用AndroidJavaObject和AndroidJavaProxy提高性能和代码管理效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  在上两篇文章中,我们已经能够通过直接使用Java,或者通过AndroidJavaClass、AndroidJavaObject这两个类实现在Unity端和Android原生端的通信。这已经可以解决很多问题,但这种方式不够模块化,不够优雅。

  在实际使用中,将Android端代码编译成aar包供Unity端调用更有利于代码管理、人员分工、降低开发工具之间的耦合,而且目前有大量第三方库是通过aar包的形式提供,本节我们主要演示通过Android Studio生成aar包及在Unity中调用aar包中功能的流程及方法。
在Android Studio中生成aar包流程如下:

  (1)创建新Android Studio工程。在Android Studio中,依次选择File →New → New Project,如图1所示。
在这里插入图片描述

图1 创建新工程

  选择New Project之后会打开新工程创建面板,如图2所示,在面板左侧列表中选择Phone and Tablet,然后在右侧图像列表中选择No Activity、Basic Activity、Empty Activity模板之一,本节选择Empty Activity模板。
在这里插入图片描述

图2 新工程创建面板

  选择好所使用的工程模板后,点击Next进入工程信息填写面板,如图3所示,其中Package name即为所使用的包名,需要认真填写;Minimum SDK建议选择Android 8.0以上(ARCore不支持Android 7.0以下版本);其余项可根据需要填写,点击Finish按钮完成工程创建。

在这里插入图片描述

图3 填写工程信息

  工程创建完成后,因为我们希望以模块的形式导出aar包,所以首先创建应用模块。在新创建的工程左侧Project列表面板app目录上鼠标右键,在弹出的级联菜单中依次选择New →Module,如图4所示。

在这里插入图片描述

图4 新建Module模块

  在打开的新建模块面板中,因为我们希望创建Android类库,在其左侧列表中选择Android Library,然后在右侧面板中填写Module name(模块名)与其它信息,如图5所示,最后点击Finish按钮完成android2unity模块的创建[ 在本示例中,工程名与模块名重名,实际使用中建议根据模块功能命名并避免与工程重名]。

在这里插入图片描述

图5 Module模块信息填写面板

  Android Studio会自动生成模块的层级结构,依次选择android2unity模块下的java →com.davidwang.android2unity包名,并在其上鼠标右键打开级联菜单,如图6所示。

在这里插入图片描述

图6 在模块下新建Java类

  在弹出的级联菜单中依次选择New →Java Class创建新类,本节类名命名为example,并编写代码如下:

//代码片段1
//Java端代码
package com.davidwang.android2unity;

import android.app.Activity;
import android.widget.Toast;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class example {
    private Activity _unityActivity;
    private String _unityObject;
private String _unityMethod;
//初始化,注册Unity对象与回调方法
    public void Init(String unityObject,String unityMethod){
        try {
            Class<?> classtype = Class.forName("com.unity3d.player.UnityPlayer");
            Activity activity = (Activity) classtype.getDeclaredField("currentActivity").get(classtype);
            _unityActivity = activity;
        }
        catch (ClassNotFoundException e) { }
        catch (IllegalAccessException e) { }
        catch (NoSuchFieldException e) { }
        _unityObject = unityObject;
        _unityMethod = unityMethod;
}
//通过UnitySendMessage方法传播消息
    private boolean callUnity(String args){
        try {
            Class<?> classtype = Class.forName("com.unity3d.player.UnityPlayer");
            Method method =classtype.getMethod("UnitySendMessage", String.class,String.class,String.class);
            method.invoke(classtype,_unityObject,_unityMethod,args);
            return true;
        }
        catch (ClassNotFoundException e) {}
        catch (NoSuchMethodException e) {}
        catch (IllegalAccessException e) {}
        catch (InvocationTargetException e) {}
        return false;
}
//调用Android端本地方法
    public boolean showToast(String content){
        Toast.makeText(_unityActivity,content,Toast.LENGTH_SHORT).show();
        callUnity("Call from android");
        return true;
    }
}

  在上述代码中,我们采用UnitySendMessage()消息传播方式回调Unity端的方法,由于UnitySendMessage()方法需要明确的场景中游戏对象、游戏对象脚本中方法名作为参数,为方便Unity中的调用,这里通过Init()方法由Unity端注入这两个参数,从而不需要一一绑定游戏对象与脚本方法名。同时,为避免引入Unity引擎的Classes.jar包,这里采用了反射的方式获取当前Activity。

  至此,Android端的模块已完成,在左侧Project列表中选中android2unity模块,然后在Android Studio菜单中依次选择Build →Rebuild Project开始构建模块aar包,如图7所示,构建完成后,可以在android2unity模块下的build →outputs →aar目录中找到生成的aar包。

在这里插入图片描述

图7 构建模块aar包

  将该aar包文件复制到Unity工程Assets/Plugins/Android目录或其子目录下,完成aar包的导入。为测试其功能,在Unity中新建Android2Unity.cs脚本文件,代码如下:

//代码片段2
//C#端代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Android2Unity : MonoBehaviour
{
    void Start()
    {
        using(AndroidJavaObject jo = new AndroidJavaObject("com.davidwang.android2unity.example"))
        {
            jo.Call("Init",gameObject.name, "AndroidCallback");
            bool success = jo.Call<bool>("showToast", "Content from unity");
            if (true == success)
            {
                Debug.Log("Method executed");
            }
        }
}
//Android端回调的方法
    public void AndroidCallback(string str)
    {
        Debug.Log(str);
    }
}

  该脚本逻辑比较简单,首先通过实例化Android端的类,并通过其Init()方法注入回调游戏对象名及脚本方法名。将该脚文件挂载到场景中的任意对象上,连接手机,打包运行,可以看到,Unity端的方法参数可以正确传递到Android端,Android端也可以正确回调Unity端的脚本方法。

  由于UnitySendMessage()方法需要遍历场景中的游戏对象,效率并不很高,特别是在频繁调用或者场景比较复杂的情况下可能会导致性能问题,在实际开发中,建议通过AndroidJavaProxy类交互。通过构建模块aar包的形式,有利于代码管理,并且可以方便的整合第三方类库,提供一个整体的模块方案,简化Unity端的调用形式。

  通过这种包/库的方式调用就舒服多了。

### 如何在 Unity 中实现 Android交互 #### 使用 UnityAndroid 接口进行交互Unity3D 开发中,可以通过 Unity 提供的 `AndroidJavaObject` 和 `AndroidJavaClass` 类来访问 Android 原生 API。这使得开发者可以在 Unity 中调用 Android 的功能模块,例如显示 Toast 消息、启动 Activity 或者操作其他 Android 组件。 以下是通过 Unity 调用 Android Toast 消息的一个简单示例: ```csharp using UnityEngine; public class AndroidInteraction : MonoBehaviour { public void ShowToast(string message) { if (Application.platform == RuntimePlatform.Android) { using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) { var currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"); currentActivity.Call("runOnUiThread", new AndroidJavaRunnable(() => { var toastClass = new AndroidJavaClass("android.widget.Toast"); var toastObject = toastClass.CallStatic<AndroidJavaObject>( "makeText", currentActivity, message, toastClass.GetStatic<int>("LENGTH_SHORT") ); toastObject.Call("show"); })); } } } } ``` 此代码片段展示了如何利用 Unity 的 `AndroidJavaObject` 来获取当前活动 (`currentActivity`) 并在其线程上调用 Android 的 `Toast` 方法[^1]。 --- #### 启动 Android 自定义 Activity 除了简单的消息提示外,还可以通过 Unity 启动自定义的 Android Activity。这种情况下通常需要创建一个带有特定入口点的 Android 应用程序,并将其打包到 APK 文件中以便于集成。 以下是如何从 Unity 启动 Android Activity 的方法: 1. **准备 Android 工程** 在 Android Studio 中构建一个新的项目并导出其 AAR 文件或直接编译成 APK。 2. **配置 Unity 项目** 将生成的文件导入至 Unity Assets/Plugins/Android 下面作为依赖库加载。 3. **编写脚本以触发 Activity 加载** ```csharp using UnityEngine; using System.Collections; public class LaunchAndroidActivity : MonoBehaviour { private const string ACTIVITY_CLASS_NAME = "com.example.MyCustomActivity"; IEnumerator Start() { if (Application.platform != RuntimePlatform.Android) yield break; try { using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) { var activityContext = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"); using (var intent = new AndroidJavaObject("android.content.Intent")) { intent.Call<AndroidJavaObject>("setClassName", activityContext.Call<string>("getPackageName"), ACTIVITY_CLASS_NAME); activityContext.Call("startActivity", intent); } } } catch (System.Exception e) { Debug.LogError($"Failed to start custom Android activity: {e.Message}"); } } } ``` 这段代码演示了如何动态构造 Intent 对象并通过它激活指定名称的目标 Activity[^2]。 --- #### 更复杂的交互方式——双向通信 对于更复杂的应用需求来说,可能还需要支持数据交换以及事件回调等功能。此时可以考虑采用 JNI(Java Native Interface)技术或者借助插件工具简化流程。具体做法如下所示: - 定义接口类用于接收来自 C# 层的消息; - 实现该接口并将实例传递给 Java 部分处理逻辑; - 当有响应返回时再通知回 Unity 端更新界面状态或其他动作。 更多细节可参阅官方文档说明[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_DavidWang_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值