版本
Unity2019.3以上 Android 3.4以上
前言
UnityPlayerActivity找不到!UnityPlayerActivity找不到!UnityPlayerActivity找不到!
换了2019.4版本 ,导出android发现很多错误.例如UnityPlayerActivity找不到,资源重复等等问题.原因在于Unity做了更改.好像是2019.2之后的版本做了升级(具体那个版本不知)
更新2022/1/19
发现之前的有些误人子弟 重新写
直接导出导出Java类文件到Unity中
创建一个类库
Android Studio中的配置和代码示例
首先导入classes.jar
,这一步都是没有变化,根据自己andriod项目mono/IL2Cpp
,找到对应的jar包,例如我的项目
ctrl+c,然后在AS Libs文件夹中ctrl+v,然后再点击Add as library
然后新建一个类MainActivity
,发现继承不了UnityplayerActivity
插件unity的Classes.jar包中是没有这个类存在的,这个时候我们需要在Untiy中找到UnityPlayerActivity
,例如我的路径
直接把这个包拷贝过来
然后我们在MainActivity
中写代码
package com.tantrum.md;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import com.unity3d.player.UnityPlayerActivity;
public class MainActivity extends UnityPlayerActivity {
public static MainActivity Ins=null; //单例模式
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Ins=this;
Log.i(AndroidUnityConnecter.UnityTag,"启动");
}
public void GetString(String args)
{
String a= "Unity:"+args;
Log.i(AndroidUnityConnecter.UnityTag,a);
AndroidUnityConnecter.SendMsgToUnity(a);
}
public void SayToast(final String msg)
{
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(),msg,Toast.LENGTH_LONG).show();
}
});
}
@Override
protected void onStart() {
super.onStart();
Log.i(AndroidUnityConnecter.UnityTag,"开始Start");
}
}
AndroidUnityConnecter
package com.tantrum.md;
import com.unity3d.player.UnityPlayer;
public class AndroidUnityConnecter {
private static final String connecterName = "UnityAndroidConnecter"; //通信物体
private static final String defaultMethodName = "ReceiveAndroidMsg"; //方法
public static final String UnityTag="Unity";
//发送消息到Unity
public static void SendMsgToUnity(String args)
{
UnityPlayer.UnitySendMessage(connecterName, defaultMethodName,args);
}
//发送消息到Unity
public static void SendMsgToUnity(String methodName,String args)
{
UnityPlayer.UnitySendMessage(connecterName,methodName,args);
}
/*接收到Unity发来的消息*/
public static void ReceiveUnityMsg(String key,String args)
{
//根据接受到的消息处理
switch (key)
{
case "getstring":
MainActivity.Ins.GetString(args);
break;
case "toast":
MainActivity.Ins.SayToast(args);
break;
}
}
}
Unity中操作
在PlayerSetting中,勾选之后会自动生成一个Androidmainfest.xml
修改AndroidManifest.xml
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.如下图
然后把我们写的MainActivity.java
AndroidUnityConnecter.java
放到Unity->Plugins->Android
文件夹下面
然后建立一个简单界面,写交互代码
新建一个GameObject名字是Java代码设定的名字,比如我的就是UnityAndroidConnecter
, 关于UnityPlayer.UnitySendMessage
,第二个方法名字,可以是private 也可以是public
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
public class UnityAndroidConnecter : MonoBehaviour
{
[Header("默认交互 包.静态类名(AndroidJavaClass)")]
[SerializeField] string defaultAndroidPackageClass= "com.tantrum.md.AndroidUnityConnecter";
[Header("默认 静态类.接收消息方法名")]
[SerializeField] string defaultReceiveMethodName= "ReceiveUnityMsg";
public UnityEngine.UI.Button btnToast, btnMsg;
public UnityEngine.UI.Text text;
private void Start()
{
btnToast.onClick.AddListener(Toast);
btnMsg.onClick.AddListener(CallAndroid);
}
public void Toast()
{
SendMsgToAndroid("toast", "Hello Android");
}
public void CallAndroid()
{
SendMsgToAndroid("getstring", "Hello Android");
}
/// <summary>
/// 发送消息到Android
/// </summary>
/// <param name="key">key</param>
/// <param name="args">参数</param>
public void SendMsgToAndroid(string key, string args)
{
using (AndroidJavaClass jc = new AndroidJavaClass(defaultAndroidPackageClass))
{
jc.CallStatic(defaultReceiveMethodName, key, args);
}
}
/// <summary>
/// 接收来自Android的消息 (ReceiveAndroidMsg方法名要和java代码中保持一致)
/// </summary>
/// <param name="args">参数</param>
public void ReceiveAndroidMsg(string args)
{
//根据接收到的消息自定义处理
text.text = $"来自Android的消息:{args}";
}
}
然后直接Unity中打包
遇到的问题
- 不能使用下面代码调用Toast
但是可以调用using (AndroidJavaObject jo = new AndroidJavaObject("com.tantrum.md.MainActivity")) { jo.Call("SayToast", "Hello Android"); }
这个问题暂时不知道,应该跟Toast有关系using (AndroidJavaObject jo = new AndroidJavaObject("com.tantrum.md.MainActivity")) { jo.Call("GetString", "Hello Android"); }
导出Jar包,ARR包
略了,直接到处java最方便
总结一些知识
-
AndroidJavaClass
: 是java.lang.Class 类 主要用于获取静态字段或调用静态方法 C#中静态类.方法
或类.静态方法
AndroidJavaObject
:是java.lang.Object 实例对象 调用对象方法: Call 方法,有泛型与非泛型的两个版本。 这就是一个实例对象.例如Unity 你 获取一个GameObject然后调用他的方法.这个是直接找到包名下对应的类,是一个类 不是一个对象,所以只能调用一些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
-
附加几个文章链接
https://www.jianshu.com/p/b5e3cfcdf081
https://blog.csdn.net/osuckseed/article/details/84940618 -
最后大家可以看看这个系列视频哈 讲的很明白https://www.bilibili.com/video/BV1Qt4y1a7aW?p=6&t=392