Unity和Android的交互

一、前言

Unity和Android原生交互的方式大概有2种,一种是Android导出jar/aar包给Unity,然后Unity来构建apk;另外一种是Unity勾选Export Project,导出为一个Android工程,然后用AndroidStudio构建APK;这里讲讲第一种方式

二、Android导出jar/aar包到Unity

2.1 版本说明

  • 这里我用的Unity版本是 2020.3.33f1c2; AndroidStudio 用的版本是 2021.3.1
    思路大致是一致的,但不同版本可能导出的文件路径不太一样或内容可能不太一样,这个要注意一下

2.2 拷贝Unity的classes.jar给Android工程

2.2.1 classes.jar的位置

classes.jar 位于 {Unity 安装位置}\Editor\Data\PlaybackEngines\AndroidPlayer\Variations{mono或il2cpp}\Release\Classes\ 目录下

  • 这里主要涉及到2个变量,一个是Unity版本,一个是mono或il2cpp;
    不同Unity版本的安装路径不一样,可以用UnityHub点击 设置按钮-在资源管理中显示。快速进入到对应版本的目录;
    在这里插入图片描述
    至于mono或il2cpp,主要看你选用哪种打包方式。由于是示例空工程,并且要快速构建,所以我这里选了mono;

2.2.2 Android Studio创建module

先用Android Studio新建一个Android Studio空工程,接着我们创建一个module模块来实现功能
点击 File-New-New Module,拉起创建面板
在这里插入图片描述
注意,这里要先切换到Android Library页签,然后可以输入你喜欢的module名字
在这里插入图片描述

2.2.3 拷贝classes.jar 到 Android工程并启用

  • 拷贝第一步的classes.jar,并粘贴进模块的libs目录下
    在这里插入图片描述
  • 启用classes.jar
    粘贴进来后,其实还没起作用。右键classes.jar,然后点击 Add as Library
    在这里插入图片描述
    然后你会发现classes.jar有个三角标了,这时才起作用了。
    在这里插入图片描述
    Add as Library 这一步操作等同于在module的build.gradle里添加 implementation files(‘libs\classes.jar’), 然后 点击 File - Sync Project with Gradle Files按钮;
    我们也可以通过修改文件的方式来快速的添加和移除lib
    在这里插入图片描述

2.3 编写Android工程代码

2.3.1 创建 MainActivity

在模块下创建MainActivity ,也不一定要这个名字,可以根据你喜欢的来
在这里插入图片描述

2.3.2 MainActivity改继承 UnityPlayerActivity

这里MainActivity 改继承自UnityPlayerActivity,不出意外,改继承后这里会报红。这是因为新版本的Unity(大概是2019和之后的版本),导出的 classes.jar 不再包含 UnityPlayerActivity了。所以我们需要再拷贝一个UnityPlayerActivity过来
在这里插入图片描述

2.3.3 拷贝 UnityPlayerActivity

这个路径在对应Unity版本的 Editor\Data\PlaybackEngines\AndroidPlayer\Source\com\unity3d\player目录下。只要找到前面的classes.jar,相信这个对你来说也是轻松找到
在这里插入图片描述

  • 拷贝进Android工程
    如下图,可以保持和MainActivity同级,拷贝进来
    在这里插入图片描述
    然后修改package路径(可以从MainActivity.java里拷贝package路径粘贴进来)和 引入命名空间
    代码如下,熟悉的朋友也可以在报红处按下Alt + Enter,手动引入
package com.example.linkunitylibrary; //这里拷贝你MainActivity的package
//import导入依赖
import com.unity3d.player.IUnityPlayerLifecycleEvents;
import com.unity3d.player.MultiWindowSupport;
import com.unity3d.player.UnityPlayer;

然后 MainActivity就不报红了
在这里插入图片描述

  • 题外话
    记得好像有些教程是放在com.unity3d.player目录下,并保持原包名,如下图的层级和package路径。我有测试过,但在最后构建apk会报错。
    在这里插入图片描述
  • 原因我觉得是这样:因为最终我们要把android studio构建出来的jar包或aar包,放回unity。那如果这里保持一样的包名,到时放回unity,就相当于有2个一样的 com.unity3d.player.UnityPlayerActivity 类了,那就会报错。所以我觉得这种方式应该不可行…

2.3.4 编写Android工程代码

这里我们分别 写一个方法给Unity调用 和 调用Unity里的一个方法
在这里插入图片描述
代码如下

package com.example.linkunitylibrary;
import android.os.Bundle;
import com.unity3d.player.UnityPlayer;

/**
 * Created by super41 on 2024/4/5.
 */
public class MainActivity extends UnityPlayerActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //调用Unity的方法
        a2u_add(1,5);
    }

    //写一个方法给Unity调用
    public int u2a_add(int a,int b){
        return a + b;
    }

    //调用unity里的方法
    public void a2u_add(int a,int b){
        sendMsg2Unity("a2u_add",a+"|"+b);
    }

    private static final String LinkGameObjectName  = "UnityLinkAndroidGo";
    /**
     * 给Unity发消息
     * @param methodName 方法名
     * @param params 参数
     */
    private void sendMsg2Unity(String methodName,String params){
        //依次传入 GameObjectName, GameObject里的方法,参数
        //因为这里 GameObjectName 一般固定,所以封装起来
        //只能传递一个参数,多个参数拼接在params里
        UnityPlayer.UnitySendMessage(LinkGameObjectName,methodName,params);
    }
}

2.3.5 编写AndroidManifest.xml

修改AndroidManifest.xml,这里记得替换为你自己的包名和类名

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <application
        android:allowBackup="true"
        android:supportsRtl="true">
        <activity android:name="com.example.linklibrary.MainActivity" android:exported="true"> <!--包名和类名,这里换成你自己的包名和类名-->
            <intent-filter>
                <action android:name="android.intent.action.MAIN" /> <!--主入口Activity-->
                <category android:name="android.intent.category.LAUNCHER" /> <!--添加到桌面-->
            </intent-filter>
            <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
        </activity>
    </application>

</manifest>

2.4 编写Unity工程代码

2.4.1 搭建游戏物体GameObject

  • 创建2个Text文本,一个显示Unity_Call_Android的加法结果,一个显示Android_Call_Android的加法结果
    在这里插入图片描述
  • 创建UnityLinkAndroidGo物体,这里游戏名字要跟Android代码里的物体名字一致。
    创建任意名字的脚本,如UnityLinkAndroidScript,代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UnityLinkAndroidScript : MonoBehaviour
{

    public Text Txt1;
    public Text Txt2;
    
    // Start is called before the first frame update
    void Start()
    {
        u2a_add(100,200);
    }

    /// <summary>
    /// Unity调用Android
    /// </summary>
    void u2a_add(int a, int b)
    {
        //标准操作,获取MainActivity对象
        AndroidJavaClass javaClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject javaObject = javaClass.GetStatic<AndroidJavaObject>("currentActivity");
        //调用方法
        var result = javaObject.Call<int>("u2a_add", a, b);
        Txt1.text = $"UnityCallAndroid {a} + {b} = {result}";
    }

    /// <summary>
    /// 给android调用的方法
    /// </summary>
    /// <param name="objs"></param>
    void a2u_add(string objs)
    {
        var arrays = objs.Split('|');
        var a = int.Parse(arrays[0]);
        var b = int.Parse(arrays[1]);
        var result = a + b;
        Txt2.text = $"AndroidCallUnity {a} + {b} = {result}";
    }
    
}

然后把2个Text附上
在这里插入图片描述

2.5 导出和构建APK

一切准备就绪,接下来就是导出和构建APK了

2.5.1 导出Java文件

我们一般是导出jar包和aar包文件。其实也可以用导出java文件的方式
如下图,3个文件导出到Unity的Assets/Plugins/Android/目录下,如没有目录则创建
在这里插入图片描述
在这里插入图片描述
接着就是常规的构建apk了。我们来看运行结果。可以看到成功运行了起来
在这里插入图片描述

2.5.2 导出Jar包

2.5.2.1 构建Jar包

上面的导出java文件一般不是主流的方式,还是导出成一个压缩包的形式更好管理一点。我们来看看怎么导出jar包
选中你的module,然后点击 Build - Make Module xxx. 然后打开资源管理器,就可以看到这里生成了一个build目录
在这里插入图片描述
进入build\intermediates\aar_main_jar\debug\目录(这里不同Android版本可能输出路径不一样,思路是一致的)
可以找到classes.jar
在这里插入图片描述
拷贝这里的classes.jar拷贝到Plugins/Android/目录下,并删除掉原来的java文件。如下图
在这里插入图片描述
然后就是构建apk了,也可以得到我们想要的效果;

2.5.2.2 新建Task任务构建和重命名Jar包
  • 一般我们需要重命名我们的jar包,不然叫classes.jar不太好,手动改每次都要来一遍不太好。我们可以添加task任务来实现这一步骤。打开module的build.grade,在文件的最后添加任务

在这里插入图片描述
代码如下:

//删除旧jar包
task tryDeleteOldJar(type:Delete){
    delete('release/HelloWorld.jar')
}

//导出并重命名jar包
task exportJar(type : Copy){
    from('build\\intermediates\\aar_main_jar\\debug')//从这个路径拷贝
    into('release') //拷贝到这个路径
    include('classes.jar')
    rename('classes.jar','HelloWorld.jar')
}

//添加依赖
exportJar.dependsOn(tryDeleteOldJar,build)

然后Sync刷新一下
在这里插入图片描述
点击右侧的Gradle,然后点击Task/other
在这里插入图片描述
就可以看到exportJar任务了
在这里插入图片描述
双击执行它,我们可以得到一个重命名好的HelloWorld.jar
在这里插入图片描述
如果看不到Task任务,那是一些版本的AndroidStudio隐藏掉了,可以进入File-Setting-Experimental,然后取消勾选这个Do not build… 选项,然后点击OK后你就可以看到Task了(当然不同版本可能设置不一样,这里主要介绍一种解决思路)
在这里插入图片描述
到此,导出Jar包的形式也好了

2.5.3 导出aar包

我们还可以导出aar包,aar和jar包的区别是,jar包一般只包含java文件,而aar包除此之外,还可以包含res和AndroidMainfest.xml

2.5.3.1 构建aar和修改aar包

接下来我们来实现导出aar包;
和之前一样,我们选中Module,点击Build-Make Module来构建
在这里插入图片描述
可以在build/outputs/aar里面找到aar
在这里插入图片描述
aar包本质上是一个压缩包,我们改为.zip格式,然后用压缩文件打开。目录大致如下
在这里插入图片描述
还记得我们从unity拷贝了一个classes.jar过来嘛,这个文件也会被构建进aar包,然后当我们把aar包放回unity,那么就会有重名的类。所以我们需要删除掉这个classes.jar
在这里插入图片描述
具体的操作方式是:
把libs里的classes.jar删掉,然后箭头的classes.jar拖进libs目录
在这里插入图片描述

2.5.3.2 压缩aar包细节

然后接下来就是重新压缩成一个aar包了。压缩这里有2点很关键,我当时自己也是踩坑了好几个小时。
现在说一下:

  • 选中你的文件列表,然后右键进行压缩,如下图。注意不要在外层目录压缩,不然会多嵌套一层文件夹,导致Unity识别不到;
    在这里插入图片描述
  • 压缩格式这里选zip,不要选默认的rar… 当时就是选rar,然后就进坑了…
    在这里插入图片描述
    然后把得到的压缩包改为aar后缀
    在这里插入图片描述
    然后放回Unity,因为aar包已经有了AndroidMainfest.xml,所以可以把之前的删掉,只留下aar包
    在这里插入图片描述
    接下来就是构建出APK了,也可以得到我们想到的效果;
2.5.3.3 解决Androidmainfest合并问题

如果构建过程中提示AndroidMainfest 合并失败,如下图。是因为最小sdk版本要改一下
在这里插入图片描述
这里你可以对aar包里的minSdkVersion进行修改,改成提示的版本,比如我这里是改成19,然后导出为压缩包
在这里插入图片描述
也可以对Modudle的build.gradle改下minsdk版本,我这里是改成19,这种方式更好一点。然后重新构建aar包
在这里插入图片描述

2.5.3.4 解决桌面2个启动图标

使用导出aar的方式构建出的apk,桌面上可能会有2个程序入口,也就是2个图标。
我们需要修改下AndroidMainfest.xml
进入PlayerSetting,勾选 CustomMainfest.xml
在这里插入图片描述
然后会自动生成AndroidMainfest.xml
在这里插入图片描述
进入AndroidMainfest.xml,把这个activity整段删掉,然后再构建apk即可
在这里插入图片描述

最后导出APK就可以了。至此我们就完成了3种导出方式

  • 24
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: AndroidUnity之间的交互可以实现在Unity运行时,调用Android原生代码来实现一些功能。在Android端可以使用 Android Java API 调用 Unity 的代码。而在Unity端,可以使用 C# 代码来调用 Android 的 Java API。这种双向调用可以实现一些比较复杂的跨平台应用,例如在Unity中展示Android硬件设备的信息或者调用相机、传感器等硬件设备来实现某些功能。 例如,在Android端上获取某个传感器的数据,然后传到Unity中,就可以借助Java Native Interface(JNI)来实现。具体实现方式如下: 1. Android端: * 创建一个Native方法,在其中读取传感器数据; * 创建一个Java类,将该Native方法和Unity相关的方法绑定; * 在Unity中调用Java类中的方法,以获取传感器数据。 2. Unity端: * 在C#代码中,调用Android的Java API,以实现数据传输; * 实现Unity的渲染逻辑,以展示从Android端传输过来的数据。 需要注意的是,为了确保代码的正确性和稳定性,一定要在调用之前做好详细的测试工作。 ### 回答2: AndroidUnity是两个流行的软件开发平台,它们都具有广泛的应用。将它们结合起来,可以为应用开发者带来无限的可能性。 在androidunity交互过程中,最主要的问题是如何将android中的数据传递到unity中。这主要分为两种情况:一种是在Unity中使用安卓API(Java代码),另一种是安卓使用Unity中的可编程元素(C#代码)。 在第一种情况下,可以使用Unity的Java接口来实现,编写类似于以下的Java代码: ``` UnityPlayer.UnitySendMessage("GameObjectName", "MethodName", "Message"); ``` 其中,UnitySendMessage方法将消息发送给Unity中的一个GameObject,它接受两个参数,分别是接受消息的对象名和它上面的方法名。 在第二种情况下,可以使用Unity的C#接口来实现。我们可以使用Unity中的SendMessage或BroadcastMessage方法来向Unity对象发送消息(这些对象必须具有MonoBehaviour脚本,否则将不会工作)。 在Android中使用Unity对象也同样简单。我们需要做的就是在Android项目中添加UnityPlayerActivity类,在此类中使用UnityPlayer类的相关方法调用Unity导出的API。 综上所述,将安卓与Unity结合起来,可以极大地扩展应用的功能性,并为用户提供更好的体验。通过上述方法可以轻松实现androidunity交互。 ### 回答3: AndroidUnity交互是现在游戏开发中非常常见的一种技术,Android作为手机操作系统的代表,提供了丰富多彩的开发接口,而Unity作为一款游戏引擎,具有着强大的游戏制作功能。两者合作可以大大提高游戏的交互性和玩法。下面我们来分别了解一下AndroidUnity之间的交互方式。 首先是从AndroidUnity交互。由于Android系统是Java语言开发的,而Unity则是C#开发的,所以两者之间实现交互还需要一些中间的桥梁。目前比较常用的方式是通过JNI接口,将Java层面的信息传递到C#层面的Unity中。在Java中,你需要先获取UnityPlayer的实例,然后就可以通过UnityPlayer的方法来调用C#端的函数。具体流程如下: 1. 在Unity中编写对应的C#函数,该函数必须使用静态修饰符(static)。例如: public static void UnityMethod(string str){ Debug.Log("接收到的数据为:" + str); } 2. 在Java中,使用JNI接口调用C#函数。例如: // 获取UnityPlayer实例 UnityPlayer player = new UnityPlayer(); // 调用C#函数 player.UnitySendMessage("GameObject名字", "函数名字", "传递的参数"); UnitySendMessage方法中,第一个参数表示的是GameObject的名字,第二个参数表示的是C#函数的名字,第三个参数就是传递的参数。 其次是从UnityAndroid交互。在Unity中,通过AndroidJavaClass和AndroidJavaObject等API,可以实现调用Java层面的方法。具体流程如下: 1. 在Java中,编写需要调用的方法,这里的方法必须是public静态的。例如: public static void showAndroidToast(String msg){ Toast.makeText(context, msg, Toast.LENGTH_SHORT).show(); } 2. 在Unity中,使用AndroidJavaClass和AndroidJavaObject等API来调用Java方法。例如: // 设置Context AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"); // 调用Java方法 AndroidJavaClass cls = new AndroidJavaClass("com.example.androidTest.MainActivity"); cls.CallStatic("showAndroidToast", currentActivity, "传递的参数"); CallStatic方法中,第一个参数表示要调用的Java层面类的名称,第二个参数表示要调用的Java方法名称,接下来的参数就是要传递的参数。 综上所述,通过JNI和AndroidJavaClass等API,AndroidUnity之间可以很方便地进行交互,相互传递数据和调用各自的方法。这样就能够更好地完成游戏逻辑和UI界面的制作。同时,这种交互方式也为跨平台的开发提供了很好的经验和方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值