Unity与Android交互(4)——接入SDK

news2024/9/20 8:10:50

【前言】

unity接入Android SDK有两种方式,一种是把Unity的工程导出google project的形式进行接入,另一种是通过把Android的工程做成Plugins的形式进行接入。我们接入SDK基本都是将SDK作为插件的形式接入的。

对我们接入SDK的人来说,SDK也是分等级的:

第一等级:只有so文件,这种so文件里一般是算法居多,他们不懂得如何做成SDK,这时需要做这个JAR中间层,C#调用JAR接口,JAR接口调用so文件接口,如果你懒得做,可以让给so文件的人做,本来就是他们应该做的。或者直接用C#调用C++的方式来接入。如果连so文件都没给,可以直接开喷,一般不会出现这种情况。

第二等级:有Androrid SDK和接入文档,我们知道Android SDK一般包含so文件和jar,理论上我们可以直接在C#端调用了。如果是功能简单的SDK可以这样做,如果SDK比较复杂,尤其是涉及Activity有生命周期的,必须自己再写个Jar作为中间层。这时候,如果接入文档不清晰就有很多坑。如果有直接的SDK对接人,任何不清楚的地方就要直接问。很多SDK不是一般不是面向Unity的,都在这个范围内

第三等级:有Android SDK和中间层Jar、接入文档。这种SDK接入起来比较舒服Jar层大的框架都给你搭建好了,你肯定要拿到Jar的代码的,根据项目需要和使用SDK的需要,在Jar层修改些代码,在C#层调用就可以了。这种一般是面向Unity的SDK。

第四等级:有Android SDK和中间层Jar以及C#层调用接口。这种SDK接起来最轻松,只需要根据需要在C#调用接口,写回调函数即可,看文档的时候注意调用什么方法,参数都是什么,代表什么意义,回调参数都是什么即可。一般这种SDK是比较成熟的可以面向Unity的大型SDK,接口回调什么的都会给你设置好。

SDK接入多了熟练了之后,你会发现接入SDK是一件无聊又费时的事情,你不知道别人家的SDK会不会在文档中没说明什么问题,坑很多,Android的和iOS的有时候又往往不一样。SDK的测试相比GamePlay等在Editor上就能测试的而言会繁琐很多,你必须需要等到出包之后才能进行验证和测试,Android和iOS都要测一遍,甚至不同的机型也要测下,看Log还需要连接adb拿log,自己看不懂log还要交给对方去看,需要来回沟通。为了提高效率,必须要了解如何热更和打包。

【接入SDK的两种方式】

第一种是,将 Unity 在安卓平台选择 Gradle 打包出来,然后在Android Studio中接入原生SDK,并生成APK

第二种是,将SDK做成 Unity Plugin,生成jar或arr在C#层调用。

基本上我们都是用第二种方式接入的。

【UnityPlayer与UnityPlayerActivity】

Activity生命周期

游戏启动时调用MainActivity,也即UnityPlayerActivity。(以下代码源自反编译)

按照Activity的生命周期,先调用onCreate(),onCreate时new了一个UnityPlayer

UnityPlayer实例化时主要做了以下事情:

  1. 指定currentActivty,上下文mContext;
  2. preloadJavaPlugins()预加载JavaPlugins,主要是调用com.unity3d.JavaPluginPreloader,其是Unity引擎的一个Java类,用于在Android应用程序启动时提前加载相关插件,以提高应用程序的性能和稳定性
  3. loadNative(getUnityNativeLibraryPath(var1))中加载libmain.so文件,libmain.so是一个动态共享库文件,用于处理Unity游戏引擎的启动和初始化过程,该库包含了Unity引擎的主要逻辑和函数,包括资源管理、场景管理、物理引擎、渲染引擎等。
  4. this.mContext.registerReceiver(this.mKillingIsMyBusiness,newIntentFilter("com.unity3d.intent.action.SHUTDOWN")) 使用Activity的registerReceiver()方法来注册一个BroadcastReceiver,并指定想要监听的广播时间类型为com.unity3d.intent.action.SHUTDOWN,收到该事件时指定onReceive方法,也即finish方法,这finish方法是Android系统的finish(),用于结束当前Activity并退出应用程序
  5. this.m_MainThread.start() unity主线程开始运行(前面进行过实例化),设置了线程名字为UnityMain。

 

当暂停时,调用UnityPlayer的Pause方法, 如果这个暂停是结束,会调用到UnityPlayer.ShutDown,否则调用Semaphore.release()用于释放一个许可证并增加信号量的计数器,以便其他线程可以获取许可证并访问共享资源。调用Semaphore.drainPermits来判断是否需要Destroy。

(Semaphore 是 Java 中的一个多线程同步工具,它可以用来控制并发线程数,防止出现线程安全问题。在 Semaphore 中,许可证的数量表示可以同时执行的线程数。当一个线程需要执行某个操作访问共享资源时,它需要先调用acquire()方法获取一个许可证,这会减少信号量的计数器,如果当前许可证的数量为 0,那么这个线程就会被阻塞。当共享资源被释放时,线程需要调用release()方法来释放许可证并增加信号量的计数器。而调用 Semaphore.drainPermits() 方法后,Semaphore 中所有的许可证都会被强制释放。这个方法通常在一些特殊情况下使用,比如在程序退出时,需要强制释放 Semaphore 中的所有许可证,以确保程序能够正确退出。)

 

 当Resume时,调用UnityPlayer的Resume方法,最终会调用UnityPlayer.this.nativeResume(),其会继续调用Unity游戏引擎底层的C++代码,以便在Android系统中恢复Unity的渲染和逻辑处理。同时主线程Resume。

 当Destory时,调用UnityPlayer的quit方法,在该方法中主线程销毁,卸载libmain.so

这些会经过Unity C++ NativeCode会调用到C#的 OnApplicationPause、OnApplicationFocus、OnApplicationQuit

 UnitySendMessage

UnitySendMessage最终调用了nativeUnitySendMessage

 还有其他的一些例如各种输入事件等,都是从Java调用Unity的C++ NativeCode,继而调用我们平常使用的Unity C# API

 可以看到UnityPlayerActivity是Activity和UnityPlayer的中间层,核心都在UnityPlayer中。

【在Unity中接入SDK】

如果把前面的文章都看完了,那么对于如何接入SDK就有了一定的了解,理顺一些初始化、调用关系等在实现逻辑上应该没有疑惑了。

接入单个SDK

先判断这个SDK需不需要生命周期,如果需要可以继承UnityPlayerActivity,在onCreate等方法中调用SDK的方法等,其他的写一些Java方法,让C#可以调用即可。

如果有生命周期,又不想继承UnityPlayerActivity,可以在Java通过onCreate等调用SDK的方法改为C#通过OnApplicationPause等调用。

如果SDK不需要生命周期,在Java里写入一些初始化方法,参数从C#调用时传递进去即可,如果SDK仅需要Activity参数,获取到UnityPlayer的curActivty传递进去即可。

如果SDK必须有独立的Activity,那就在Java中通过Intent调用另一个Activtiy,也就是如何切换Activty的问题。

接入多个SDK

考虑接入单个SDK时,我们有三层,C#、JAR、SDK,在C#层我们会将业务层直接调用C#方法,在Jar层我们会直接调用SDK的方法。

如果要接入多个SDK每个SDK分开接入的话,就会有多个上述的三层,不好管理。我们自然而言的就会想到合并,合并就是要做一个中间层,供业务层和SDK通信。这个中间层就是中间件。

中间件包括C#层和Jar层,原来业务层是直接调用C#方法,C#调用Java方法,Java方法里调用SDK方法,现在是业务层调用中间件的C#层,C#调用Jar层,Jar层调用SDK的方法。

我们知道SDK提供的方法可以分为以下几类:

初始化相关的方法A、可能的生命周期方法B、业务需要的功能方法C

假设要接入三个SDK: X Y Z

那么我们至少要调用9个方法(3x3)

我们在调用方法时有三个选择:一个是直接在C#调用某个SDK的某个方法,例如AndroidJavaClass.Call(XA)。另一个是在C#传入参数,间接调用,在Java端再直接调用方法,例如调用SDK的初始化方法时,将SDK类型作为参数,在Java端根据类型再调用对应SDK的初始化方法。三是更进一步的是将调用的方法名字也作为参数传入。

至于使用哪种方式看你自己,推荐的方式是中间件的方法直接调用,SDK的初始化和声明周期方法间接调用,功能方法全参数调用。

回调参数设计

我们有多个SDK的多个方法,但回调时Unity只给有一个string类型的参数,为了解决各种不同类型的回调,我们自然而然想到的是用json字符串。格式如下: 

{
    "sdkname": "xxx",
    "methodname": "xxx",
    "result": 0,
    "data": {
        "type": "xxx.",
        "filename": "xxx",
        "country": "xx"
}

在回调用方法中,将Json字符串转为C#对象,依次switch sdkname、methodname,创建对应的处理方法,有一个简单的result用于区分同一个方法在不同情况下的回调,回调的结果放在data里,每个方法有各自不同的data。

之后如果有新增的Sdk,直接创建对应的方法即可。

中间件结构设计

C#层:

C# SDKManager类,其中包含业务调用的接口,持有各种不同的SDK基类(将不同的SDK当作组件),及回调函数

各种SDK基类及其PC子类、Android子类、iOS子类,在Android子类中调用Jar层方法,相同功能的SDK可以再抽象出一个基类

Jar层:

JavaSDKManager类,其中包括C#层调用的接口,持有各种SDK类,及UnitySendManager等

各种SDK类包含调用SDK的方法。

【参考】

Unity3d Android SDK接入解析(二)Unity3d Android SDK的设计与两种接入方式_android unity 3d app 架构_小杨在玩iOS的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/705161.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文了解PoseiSwap的质押系统

PoseiSwap 正在向订单簿 DEX 领域深度的布局,并有望成为订单簿 DEX 领域的早期开创者。

jmeter发送请求的request body乱码问题解决

JMeter的Put请求,响应结果中文出现乱码的解决方法 原文地址: http://www.taodudu.cc/news/show-808374.html?actiononClick

【云原生丶Kubernetes】从应用部署的发展看Kubernetes的前世今生

在了解Kubernetes之前,我们十分有必要先了解一下应用程序部署的发展历程,下面让我们一起来看看! 应用部署的发展历程 我们先来看看应用程序部署的3个阶段:从物理机部署到虚拟机部署,再到容器化部署,他们之…

Jenkins服务器连接JMeter分布式中的test-master

Jenkins想要连接test-master就要通过代理 将下载好的agent.jar传输到test-master机器上的/usr/local(实际上任何目录都可以)下 然后我们在/usr/local目录下输入: (这个是在Jenkins页面自己生成的命令) java -jar ag…

SQL频率低但笔试会遇到: 触发器、索引、外键约束

一. 前言 在SQL面笔试中,对于表的连接方式,过滤条件,窗口函数等肯定是考察的重中之重,但是有一些偶尔会出现,频率比较低但是至少几乎会遇见一两次的题目,就比如触发器,索引和外键约束&#xff0…

C++ 教程

C 教程 C 是一种高级语言,它是由 Bjarne Stroustrup 于 1979 年在贝尔实验室开始设计开发的。C 进一步扩充和完善了 C 语言,是一种面向对象的程序设计语言。C 可运行于多种平台上,如 Windows、MAC 操作系统以及 UNIX 的各种版本。 本教程通过…

Stanford点云公开数据集:S3DIS

S3DIS (Stanford Large-Scale 3D Indoor Spaces Dataset) 是斯坦福大学提供的大场景室内3D点云数据集,包含6个教学和办公Area,总共有695,878,620个带有色彩信息以及语义标签的3D点。 该数据集目前已经被包含在一个更大的Full 2D-3D-S Dataset当中&#x…

深入探讨Seata RPC模块的设计与实现

在Seata中,TM,RM与TC都需要进行跨进程的网络调用,通常来说就会需要RPC来支持远程调用,而Seata内部就有自身基于Netty的RPC实现,这里我们就来看下Seata是如何进行RPC设计与实现的 RPC整体设计 抽象基类AbstractNettyRemoting 该类是…

Dinky:问题总结

一、启动时指定flink版本,因为dinky本身也集成了部分flink ./auto.sh start 1.12 二、数据源管理新增mysql时的url jdbc:mysql://ip:3306/dinky?useUnicodetrue&characterEncodingutf8&useSSLfalse&autoReconnecttrue&failOverReadOnlyfalse 不要…

2、JAVA 分支结构 switch结构 for循环

1 分支结构 1.1 概述 顺序结构的程序虽然能解决计算、输出等问题 但不能做判断再选择。对于要先做判断再选择的问题就要使用分支结构 1.2 形式 1.3.1 练习:商品打折案例 创建包: cn.tedu.basic 创建类: TestDiscount.java 需求: 接收用户输入的原价。满1000打9折…

网工内推 | 运营商招网工,3年以上网安经验,CISP/CCIE认证优先

01 微算互联 招聘岗位:网络工程师 职责描述: 1、负责生产系统的网络管理、网络监控告警、网络设备数据资料备份/恢复容灾管理; 2、海外、tob 、私有云网络搭建及运维7 X 24小时值班; 3、负责业务系统工程网络层面规划、建设、升级…

Java之Javac、JIT、AOT之间的关系

Javac:javac 是java语言编程编译器。全称java compiler。但这时候还是不能直接执行的,因为机器只能读懂汇编,也就是二进制,因此还需要进一步把.class文件编译成二进制文件。 Java的执行过程 详细流程 结论:javac编译后…

使用Python调用aapt命令查看APK文件信息

以下演示内容在window的操作系统 1、下载 aapt 下载完成后注意配置环境变量!!! 地址:https://www.mediafire.com/file/e8ww8wbgcowbti4/aapt 2、代码实现 import os import re import subprocess#获取当前操作系统 current_os o…

S型平滑函数功能块(CODESYS ST完整源代码)

S型平滑函数在多段曲线控温上的应用。完整算法介绍请参看下面文章博客: 带平滑功能的斜坡函数(多段曲线控温纯S型曲线SCL源代码+完整算法分析)_RXXW_Dor的博客-CSDN博客PLC运动控制基础系列之梯形速度曲线,可以参看下面这篇博客:PLC运动控制基础系列之梯形速度曲线_RXXW_…

RTL8720CF烧录工具

一、环境准备 1、 解压烧录工具包 AmebaZII_PGTool_v1.2.39.zip 2、 日志串口接串口调试助手 3、 模组A0脚接高电平 二、烧录 1、模组重新上电,串口有Download Image over …… 输出,表示模组已进入烧录模式,如图: 2、打开上…

springboot+vue校园一卡通管理系统_q7e7o

近些年来,随着科技的飞速发展,互联网的普及逐渐延伸到各行各业中,给人们生活带来了十分的便利,校园一卡通利用计算机网络实现信息化管理,使整个校园一卡通管理的发展和服务水平有显著提升。 本文拟采用java技术和Sprin…

【算法题】动态规划中级阶段之买卖股票的最佳时机、三角形最小路径和

动态规划中级阶段 前言一、三角形最小路径和1.1、思路1.2、代码实现 二、买卖股票的最佳时机 II2.1、思路2.2、代码实现 总结 前言 动态规划(Dynamic Programming,简称 DP)是一种解决多阶段决策过程最优化问题的方法。它是一种将复杂问题分解…

计算机网络————运输层

文章目录 概述UDPTCP首部格式 连接管理连接建立连接释放 概述 从IP层看,通信双方是两个主机。 但真正进行通信的实体是在主机中的进程,是这个主机中的一个进程和另一个主机中的一个进程在交换数据。 所以严格的讲,两个主机进行通信就是两个…

关于【系统学习】和【按需学习】我想说的

😜作 者:是江迪呀✒️本文关键词:心得、闲聊、学习、知识☀️每日 一言:不要停驻不前,做一点点都要比什么都不做强上百倍! 前言 说起来学习,那就离不开学习的方式。学生时期我们的…

SpringCloudAlibaba实战入门之RocketMQ消息发送(六)

本篇文章是承接上一篇文章《SpringCloudAlibaba实战入门之RocketMQ下载配置和启动(五)》,如果没有看过上一篇文章并按照指导配置和启动Rocket MQ的网友,请先阅读该篇文章以后再阅读本篇 一、创建spring-cloud-rocketmq项目 1、复制之前的项目模块新建一个项目模块,修改新…