Unity与andorid交互的那些坑

近期接触到需要Unity与andorid交互的项目,我负责andorid开发,记录一下开发过程遇到的坑,代码偏向于android端处理,unity端其他操作自行百度

 一.unity工程师导出andorid项目

有两种方式,推荐用Gradle方式导出(unity同事工作),导出的工程结构如下

二.合并进主项目

上图红框中文件都可在导出的unity工程文件中找到,添加进合并的原生项目里,并在AndroidManifest.xml以中添加

    <uses-feature android:glEsVersion="0x00020000" /><uses-feature android:name="android.hardware.vulkan" android:required="false" /><uses-feature android:name="android.hardware.touchscreen" android:required="false" /><uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="false" /><uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" android:required="false" />
<application ....>
<activity android:label="@string/app_name"android:hardwareAccelerated="true"android:launchMode="singleTask"android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection"android:name=".ui.activity.UnityPlayerActivity"><meta-data android:name="unityplayer.UnityActivity" android:value="true" /></activity>
</application>

build.gradle(app)中添加

    implementation files('libs/unity-classes.jar')implementation(name: 'UniWebView', ext: 'aar')

启动Unity项目

//原生中调用
startActivity(Intent(this, UnityPlayerActivity.class));

三.数据交互 

/*** andorid 端原生调用unity* */UnityPlayer.UnitySendMessage("Unity项目C中的类名", "类的方法名", "params");/*** unity调用的原生方法*/
C#中的代码
1.新建两个按钮
2.点击调用
按钮一:
AndroidJavaObject jc =
new AndroidJavaObject("com.xxx.xxx.connection.UnityMessage");
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("Instance");
jo.Call ("showToast","我是Unity传来的消息");按钮二:
AndroidJavaObject jc =
new AndroidJavaClass ("com.xxx.xxx.ui.activity.UnityPlayerActivity");
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
jo.Call ("showToast","我是Unity传来的消息");

以上是网上各处都会提到的方法,具体参数含义看看其他博客说明,此处只说明需要注意的点

    1.'UnityMessage'  'UnityPlayerActivity' 需要已经实例化

    2.'Instance'  'currentActivity' 需要在类中声明

    3.'showToast' 方法无法直接实现 ,需要 handle / runOnUiThread 实现

UnityPlayerActivity.java中添加以下代码

public static UnityPlayerActivity currentActivity;@Overrideprotected void onCreate (Bundle savedInstanceState){....currentActivity = this;UnityMessage.getInstance();}public void showToast(String msg){ThreadUtils.runOnUiThread(new Runnable() {@Overridepublic void run() {ToastUtils.showLong(msg);//andorid 端调用unityUnityPlayer.UnitySendMessage("Main", "OnLogin", "Test Login"); //unity方法UnityPlayer.UnitySendMessage("Main", "TestSend", "TestSend"); //unity方法}});}

UnityMessage.java

import com.blankj.utilcode.util.ThreadUtils;
import com.blankj.utilcode.util.ToastUtils;/*** <pre>* Created by DengDongQi on 2020/4/23* </pre>*/
public class UnityMessage {private static UnityMessage Instance = null;private UnityMessage() {}public static UnityMessage getInstance() {if(Instance == null){synchronized (UnityMessage.class){if(Instance == null){Instance = new UnityMessage();}}}return Instance;}public void showToast(String msg){ThreadUtils.runOnUiThread(new Runnable() {@Overridepublic void run() {ToastUtils.showLong(msg);}});}
}

测试交互

点击按钮

至此双向交互完成

四.后记

测试完交互后发现,启动unity页面后,按系统返回键无法退回原生界面,只能在UnityPlayerActivity 中某处调用finish()方法结束页面

调用finish之后会出现整个进程也会随着页面结束而被杀掉,原因是UnityPlayerActivityonDestroy()中调用了mUnityPlayer.quit(); quit中调用了this.kill();

为了退出unity界面而不结束进程,需要在AndroidManifestUnityPlayerActivity的声明中添加android:process=":unity3d"

声明为子进程后双向交互有出现问题,之后需要使用跨进程交互方式才能在原生主进程中接收交互信息

五.跨进程数据交互

选用比较简单的Messenger方式实现:修改后具体代码

UnityMessage.java

/*** <pre>* Created by DengDongQi on 2020/4/23* Unity 直接发送数据至 UnityMessage 再由UnityMessage 传递进 HandleUnityMessengerService ,Service处理并返回结果** Unity项目为客户端 , 原生APP为服务端** 原生APP内 Unity进程为客户端 ,主进程为服务端** </pre>*/
public class UnityMessage {// 客户端请求码public static final int CLIENT_REQUEST_CODE = 0X1001;// 客户端请求字段public static final String CLIENT_REQUEST_MSG = "client_request";// 单例private static UnityMessage Instance = null;// 上下文private Context mContext;// 客户端handleprivate ClientHandler mhandle = new ClientHandler();// 客户端送信者private Messenger mMessenger = new Messenger(mhandle);// 服务端送信者private Messenger mServiceMessenger = null;// 服务连接对象private UnityMsgServiceConnection mServiceConnected;// 避免内存泄露 弱引用获取contextprivate static WeakReference<Context> weakReference;private static void initWeakReferenceContext(Context context) {weakReference = new WeakReference<>(context);}private Context getWeakReferenceContext() {return weakReference.get();}private UnityMessage() {}public static UnityMessage getInstance() {if (Instance == null) {synchronized (UnityMessage.class) {if (Instance == null) {Instance = new UnityMessage();}}}return Instance;}public void init(Context context){initWeakReferenceContext(context);this.mContext = getWeakReferenceContext();mServiceConnected = new UnityMsgServiceConnection();bindService();}public void sendMsgToAndroid(String msg) {ThreadUtils.runOnUiThread(new Runnable() {@Overridepublic void run() {sendMsgToService(msg);}});}public void showToast(String msg){ThreadUtils.runOnUiThread(new Runnable() {@Overridepublic void run() {LogUtils.d("unity进程收到信息:"+msg);sendMsgToService(msg);}});}/*** 发送消息到服务端* @param msg*/private void sendMsgToService(String msg) {Message message = mhandle.obtainMessage();message.what = CLIENT_REQUEST_CODE;Bundle bundle = new Bundle();bundle.putString(CLIENT_REQUEST_MSG, msg);message.setData(bundle);message.replyTo = mMessenger;if (mServiceMessenger != null) {try {LogUtils.d("发送至主进程:"+msg);mServiceMessenger.send(message);} catch (RemoteException e) {e.printStackTrace();}}}/*** 客户端handler* 处理服务端(主进程)返回的数据* */private class ClientHandler extends Handler {@Overridepublic void handleMessage(@NonNull Message msg) {super.handleMessage(msg);if (msg != null) {if (msg.what == HandleUnityMessengerService.SERVICE_RESULT_CODE) {// 服务端返回的数据String data = msg.getData().getString(HandleUnityMessengerService.SERVICE_RESULT_MSG);// 返回给unity项目if(data!=null) {LogUtils.e(data);UnityPlayer.UnitySendMessage("Main", "TestSend", data);}}}}}/*** 绑定服务*/private void bindService() {Intent intent = new Intent(mContext, HandleUnityMessengerService.class);mContext.bindService(intent, mServiceConnected, Service.BIND_AUTO_CREATE);}private class UnityMsgServiceConnection implements ServiceConnection {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {LogUtils.d("绑定-->" + name.getClassName());mServiceMessenger = new Messenger(service);}@Overridepublic void onServiceDisconnected(ComponentName name) {LogUtils.d("解绑-->" + name.getClassName());mServiceMessenger = null;}}/*** 释放资源* */public void release(){unbindService();if(mhandle!=null){mhandle.removeCallbacksAndMessages(null);}}/*** 解绑服务* */private void unbindService() {if (mServiceConnected != null && mContext != null) {mContext.unbindService(mServiceConnected);}}}
HandleUnityMessengerService.kt
/*** 服务端创建一个 Service 来处理客户端请求,同时通过一个 Handler 对象来实例化一个 Messenger 对象,* 然后在 Service 的 onBind 中返回这个 Messenger 对象底层的 Binder 即可。* */
class HandleUnityMessengerService : Service() {companion object{//服务端的返回码const val SERVICE_RESULT_CODE = 0X1002//服务端的返回数据字段const val SERVICE_RESULT_MSG = "service_result"}private class MessageHandler : Handler(){override fun handleMessage(msg: Message?) {super.handleMessage(msg)when(msg!!.what){UnityMessage.CLIENT_REQUEST_CODE -> {LogUtils.e("服务端收到客服端信息:${msg.data.getString(UnityMessage.CLIENT_REQUEST_MSG)}")val client = msg.replyToval replyMsg = Message()replyMsg.what = SERVICE_RESULT_CODEval bundle = Bundle()bundle.putString(SERVICE_RESULT_MSG,"客服端你好!服务端已经收到你的信息了!")replyMsg.data = bundleclient.send(replyMsg)}}}}private val messenger = Messenger(MessageHandler())override fun onBind(intent: Intent): IBinder {return messenger.binder}override fun onUnbind(intent: Intent?): Boolean {return super.onUnbind(intent)}override fun onDestroy() {super.onDestroy()}
}

UnityPlayerActivity中的onCreate()  onDestroy()中

//Unity消息接收
UnityMessage.getInstance().init(this);
    @Overrideprotected void onDestroy (){UnityMessage.getInstance().release();mUnityPlayer.quit();super.onDestroy();}

最后AndroidManifest添加

<serviceandroid:name=".connection.HandleUnityMessengerService"android:enabled="true"android:exported="true"/>

Unity与andorid交互的那些坑(偏andorid)相关推荐

  1. 开发手札:Unity与Android交互

    先祝贺我国疫情基本结束,感谢为疫情奉献热血甚至生命的医护人员! 接下来进入正题. 用unity做一个手机app游戏基本上都需要与android和ios交互,比如调用系统函数,调用sdk等.这是unit ...

  2. 记Outlook插件与Web页面交互的各种坑 (含c# HttpWebRequest 连接https 的完美解决方法)

    记Outlook插件与Web页面交互的各种坑 (含c# HttpWebRequest 连接https 的完美解决方法) 参考文章: (1)记Outlook插件与Web页面交互的各种坑 (含c# Htt ...

  3. Unity中纹理启用SRGB的坑

    Unity中纹理启用SRGB的坑 __先说结论,在shader中不使用SRGB与Linear的转换函数的前提下,如果该纹理是Albedo.Emissive.Ramp或者其它颜色贴图,建议勾上SRGB, ...

  4. Unity和AndroidStudio交互制作SDK并和其他的SDK合并(微信APP支付)

    本案例使用的AndroidStudio版本为 171.4408382 Unity版本为 5.2.4f1 如果跟我一样是新手,就请先看我下面这篇文章 https://blog.csdn.net/weix ...

  5. 2021-09-29 Unity WebGL平台开发遇到的坑

    内容简介:最近在用Unity做一个 WebGL 平台的项目,开发过程中遇到了各种各样的坑,这里简单记录一下,以免以后再踩.首先是Http请求的问题,我最开始想的是,直接用C#里的写法,编辑器里测试毫无 ...

  6. Unity WebGL(一)Unity和JS交互

    UNITY与JavaScript交互 前言 一.从 Unity 脚本调用 JavaScript 函数 1.在工程文件夹里新建"Plugins"文件夹,在内部创建一个.jslib扩展 ...

  7. Unity EvenTrigerer UI交互组件

    Unity EvenTrigerer UI交互组件 Event Trigerer组件介绍 方便之处 事件选择 使用方法 1.拖拽法 代码添加 接口法 Event Trigerer组件介绍 该组件作用与 ...

  8. 关于Unity粒子系统碰撞的几个坑

    关于Unity粒子系统碰撞的几个坑 最近公司的项目正好要用到粒子系统的碰撞,所以特意研究了一下.在实践中遇到了很多问题,所以借此文记录一下学习的过程.而且学习过程中发现网上这方面文章极少,所以也算借这 ...

  9. Unity XR实现交互(抓取、移动、旋转、传送、射击)-Pico

    Unity XR 支持交互(抓取.移动.旋转.传送.射击) 文章目录 前言 Unity XR 提供了 XR 交互工具包,可以直接在包管理器中安装/更新.对于简单的交互需求unity 射线碰撞检测,可以 ...

最新文章

  1. 如何一小时杀入天池OCR比赛前排?
  2. Angular中数据循环ngFor、条件判断ngIf、ngSwitch、执行事件(click)、表单事件(keyup)、ngClass、ngStyle的使用
  3. C++ vector容器简单解释
  4. Android 应用 之路 百度地图API使用(3)
  5. Linux学习记录-文件、目录与磁盘
  6. DirectX - dds图片格式(DDSURFACEDESC2)
  7. Perl一行式:处理空白符号
  8. ffmpeg drawtext居中放置
  9. zxr10交换机配置手册vlan_最新中兴ZXR10交换机配置资料
  10. 树莓派 wiringpi 读取引脚_树莓派驱动的无人驾驶开发记录--驱动电机
  11. 51单片机——LED流水灯
  12. android开发者模式自动打开位置touch信息
  13. 基于JSoup的网络爬虫爬取小说内容
  14. Java OpenCV 图像处理34 图形图像 分水岭 watershed
  15. SWUST OJ 299: 平方和
  16. uniapp页面导出pdf
  17. mysql workbench安装教程_MySql可视化工具MySQL Workbench使用教程
  18. matlab谐波电流测量,基于MATLAB的谐波电流检测方法的建模与仿真
  19. painter qt 好恶心_Qt之有关于Painter的理解
  20. Easy_language

热门文章

  1. 非甲烷总烃废气处理方法
  2. 国内第1套_Spring4 视频教程-佟刚-专题视频课程
  3. C语言小白上楼梯问题(递归)
  4. (数学分析复习)含参量积分总结
  5. 如何在Windows中将图像合并为一个PDF文件
  6. Python微信订餐小程序课程汇总
  7. Android H5调起支付宝
  8. Scrum会议(晨会)总结
  9. Java继承属性后内存,java - Jackson:继承和必需的属性 - 堆栈内存溢出
  10. 计算机软件职称聘用,关于做好2017年“以聘代评”系列职称聘任工作的通知