Unity调用Android

这么做方便,但是对于一般人而言,不太会写,而且容易拼写错误

所有还是使用AS导出jar包或者aar包,亦或者直接把写好的java代码放在unity/plugins/android目录下面

新建AS工程然后导入unity下路的classes.jar包, 2019版本及以上版本中classes.jar包中可能没有UnityPlayerActivity,需要单独重新导入

  • classes.jar路径:xx/Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes
  • UnityPlayerActivity:xx/Editor\Data\PlaybackEngines\AndroidPlayer\Source\com\unity3d\player
  1. image-20221224141313616

  2. image-20221224141551392

  3. 新建一个Activity继承UnityPlayerActivity,然后在里面写一些逻辑代码

  4. 如果只是工具类 不想继承UnityPlayerActivity,那么自己规定好包名使用静态方法调用即可

  5. 如新建了Activity继承UnityPlayerActivity,需要在Unity中创建AndroidManifest.xml,指向启动的activity

    https://blog.csdn.net/wu_wenhuan/article/details/44941545/
    Android.intent.action.MAIN决定应用程序最先启动的
    ctivity android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里
    通过实验后,发现有问题?
    MAIN 与 LAUNCHER 并不是单纯的各管各的事情;
    我测试的结果是,如果一个应用没有LAUNCHER则该apk仍能安装到设备上,但是在桌面中图标中看不到。如果给那个Activity 设定了LAUNCHER,且同时设定了Main,则这个Activity就可出现在程序图标中;如果没有Main,则不知启动哪个Activity,故也不会有图标出现。可见,Main指的是,点击图标后启动哪个Activity。当然,Main可以给多个Activity设定,但只设定Main不设定LAUNCHER,仍然无法进入activity。
    可见,Main和LAUNCHER同时设定才有意义,如果多个activity同时设定,则会出现两个图标,分别先进入不同的activity.

  6. 最后把写好的java代码放到Unity/Plugins/Android 目录下

  7. 编写C#代码

    AndroidJavaClass : 是java.lang.Class 类 主要用于获取静态字段或调用静态方法 C#中静态类.方法 或类.静态方法
    AndroidJavaObject:是java.lang.Object 实例对象 调用对象方法: Call 方法,需要new

    直接找到包名下对应的类,是一个类 只能调用一些static 方法
    AndroidJavaClass androidJC = new AndroidJavaClass(com.xxx.xx.xxxClass)

    获取一个对象也可以直接用
    AndroidJavaObject androidJO = new AndroidJavaObject(com.xxx.xx.xxxClass)

    表示new一个该包名下的类,这个也可以直接找到对象 然后调用对象上面的普通方法

    我们常用的
    AndroidJavaClass androidJC = new AndroidJavaClass(com.unity3d.player.UnityPlayer); AndroidJavaObject jo=androidJC.GetStatic<AndroidObject>("currentActivity");
    其实就是在或者获取 UnityPlayerActivity 单例
    com.unity3d.player.UnityPlayer 是classes.jar 中的一个类

    在这里插入图片描述

    在这里插入图片描述

    调用android方法最好是在ui线程中 即: runOnUiThread

我的csdn文章有具体操作:(Unity与Android通信交互_Zero_LJ的博客-CSDN博客_unity android 交互

Android调用Unity

Android中调用Unity代码,就是给Unity发消息,Unity针对不同的消息处理逻辑

在Java代码中使用UnityPlayer.UnitySendMessage(string str1,string str2,string arg)方法

该方法有三个参数:

  • 参数1是Unity场景GameObject名称
  • 参数2是该GameObject上面的方法
  • 第三个是该方法的参数 可以为null

使用AndroidJavaProxy进行交互

UnityPlayer.UnitySendMessage(string str1,string str2,string arg)性能及其不好,采用AndroidJavaProxy

AndroidJavaProxy需要在java和C#建立桥接

java代码

1
2
3
4
5
6
7
8
//声明包名
package com.zeroultra.connecter;

//声明接口
public interface NativeAndroidProxy {
//定义桥接方法名
public void SendToUnity(String cmd,String msg);
}

C#代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using System;
using UnityEngine;

/// <summary>
/// Android代理
/// <code>声明方法只要和Java中的interface保持一致即可,可以是私有方法</code>
/// </summary>
public class NativeAndroidProxy : AndroidJavaProxy
{
/// <summary>
/// 当接收消息
/// </summary>
public event Action<string, string> OnReceiveMsg;

/// <summary>
/// 声明代理 传入具体名(com.zeroultra.connecter.NativeAndroidProxy)
/// </summary>
public NativeAndroidProxy(string proxyName) : base(proxyName) { }


/// <summary>
/// 发送消息到unity 可以私有方法 和java代码保持一致
/// </summary>
void SendToUnity(string cmd, string msg)
{
OnReceiveMsg?.Invoke(cmd, msg);
}
}

然后C#层声明代理传入Java层

java

1
2
3
4
5
6
7
8
9
10
11
12
package com.zeroultra.connecter;

import android.util.Log;
//引入包名

public class TestAndroid
{
public void SendToUnity(NativeAndroidProxy proxy)
{
bridge.SendToUnity("android","hello窝窝窝");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Test:Monobehaviour
{
void Start()
{
//声明代理
NativeAndroidProxy proxy=new NativeAndroidProxy();
//监听事件
proxy.OnReceiveMsg+=(cmd,msg)=>{};
//声明对象
using (AndroidJavaObject jo = new AndroidJavaObject("com.zeroultra.connecter.TestAndroid"))
{
//调用方法
jo.Call("SendToUnity",proxy);
}
}
}

Unity直接调用android代码记录

Toast

1
2
3
4
5
6
7
8
9
10
11
12
13
private void ToastText(string str)
{
AndroidJavaClass UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = UnityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
AndroidJavaClass Toast = new AndroidJavaClass("android.widget.Toast");
AndroidJavaObject context = currentActivity.Call<AndroidJavaObject>("getApplicationContext");
currentActivity.Call("runOnUiThread", new AndroidJavaRunnable(() =>
{
AndroidJavaObject javaString = new AndroidJavaObject("java.lang.String", str.ToString());
Toast.CallStatic<AndroidJavaObject>("makeText", context, javaString, Toast.GetStatic < int("LENGTH_SHORT")).Call("show");
}
));
}

Intent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//appid为bundleIdentifier的值,如果是本应用,可用 Application.bundleIdentifier 来获取。
//如果应用正在研发,还没有投放到应用市场上,可用新浪微博的appid即“com.sina.weibo”来测试
private void openAPPinMarket(string appid){

#if UNITY_ANDROID
//init AndroidJavaClass
AndroidJavaClass UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");;
AndroidJavaClass Intent = new AndroidJavaClass ("android.content.Intent");
AndroidJavaClass Uri = new AndroidJavaClass ("android.net.Uri");

// get currentActivity
AndroidJavaObject currentActivity = UnityPlayer.GetStatic<AndroidJavaObject>("currentActivity");

AndroidJavaObject jstr_content=new AndroidJavaObject("java.lang.String","market://details?id="+appid);

AndroidJavaObject intent = new AndroidJavaObject ("android.content.Intent",Intent.GetStatic<AndroidJavaObject>("ACTION_VIEW"),Uri.CallStatic<AndroidJavaObject>("parse",jstr_content));

currentActivity.Call ("startActivity",intent);
#endif
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
AndroidJavaClass UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = UnityPlayer.GetStatic<AndroidJavaObject>("currentActivity");


AndroidJavaClass Uri = new AndroidJavaClass("android.net.Uri");
var newuri = Uri.CallStatic<AndroidJavaObject>("parse", uri);

AndroidJavaClass intentClass = new AndroidJavaClass("android.content.Intent");
AndroidJavaObject intentObject = new AndroidJavaObject("android.content.Intent");
intentObject.Call<AndroidJavaObject>("setAction", intentClass.GetStatic<string>("ACTION_VIEW"));
//或者
//AndroidJavaObject intentObject = new AndroidJavaObject("android.content.Intent", intentClass.GetStatic<AndroidJavaObject>("ACTION_VIEW"));
intentObject.Call<AndroidJavaObject>("setData", newuri);
try
{
currentActivity.Call("startActivity", intentObject);
}
catch (Exception e)
{
Debug.LogError("未安装 " + e.ToString());
}

遇到的问题

Unity2021.2以上版本Android不能放res文件夹

描述

12

Unity - Manual: Upgrading to Unity 2021.2 (unity3d.com)

解决方案

  1. 用AndroidStudio打包成arr,然后导入 参考:AndroidStudio打包AAR供Unity使用流程

  2. 直接把文件命名成xxxx.androidlib,然后添加两个文件,一个AndroidManifest.xmlproject.propertiesUnity2021.2版本打包报错

AndroidManifest.xml

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="custom.android.res" <--这里随便命名-->
android:versionCode="1"
android:versionName="1.0">
</manifest>

project.properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt

# Project target.
#target=android-30
android.library=true

然后把res文件和这两个放在一起就可以了

image-20220825113300010