环信客服云app(环信即时通讯云)
大家好,小杨来为大家解答以上问题,环信客服云app,环信即时通讯云很多人还不知道,现在让我们一起来看看吧!
1、作为领先的即时通讯云服务提供商,欢信在游戏行业也进行了不断的探索和R&D投资。产品发布初期(2015年),推出Unity SDK,帮助游戏开发者快速实现世界频道、游戏公会、群聊等游戏场景。
2、1对1私聊等功能,安全稳定的服务也为游戏玩家带来了出色的实时交流体验。
3、2021年第二季度,对其进行了重组和改版,正式发布了欢信IM Unity SDK 2.0。主要改进包括以下内容:
4、迭代更新,更实用的API接口
5、即时消息推送增强功能的补充
6、C#语言在7.09.0版本之后引入了一些新的语法改进。
7、特别是增加了PC端Unity编辑器环境下的编译调试支持,大大提高了开发效率。
8、在过去的一段时间里,作者也参与了相应的研发工作。在整个过程中,为了解决各种问题,不仅要到处翻看资料,还要尝试各种方法和参数组合。其间还经历了各种程序崩溃,甚至系统崩溃。
9、诡异的程序表现让开发者一次次感到无奈,处处碰壁,真的就像半夜走在迷宫里,手里拿着一个待解的魔方。“此路不通,请绕行!”是一次次尝试后的无奈叹息和不舍。一旦问题最终得到圆满解决,
10、就像飞上云端,从上帝的视角俯瞰一座迷宫。一切看起来都是那么的自然,复杂,琐碎,但做程序员也是一种极大的快乐和满足。
11、我不敢一个人享受,所以录了一些经验给你参考,也欢迎资深玩家上。NET平台批评指正我。下面,欣赏!
12、开发概述:Native/Unmanaged Plugin)Unity是基于微软开发的游戏引擎2。Net框架,它采用了开源。NET平台。
13、并且依靠这个框架来达到跨越硬件设备和运行时(操作系统)的目的,也就是所谓的“一次编写,随处运行”。语言方面,Unity选择C#作为主要的脚本语言。
14、虽然。NET平台本身支持多种语言。
15、此外,Unity支持两个脚本后端,Mono和ILC2PP。尤其是,Unity Editor使用了Mono脚本框架。
16、一般游戏库的开发者可以选择直接用C#语言开发,目标类库可以在的基本功能基础上实现高级功能。NET框架。这种插件称为托管插件。
17、既然欢信IM的核心SDK都是基于C开发的,我们选择了另一种方式的原生插件,这就把我们引向了迷宫。两种插件的介绍见3。
18、遗憾的是,Unity网站上关于Native Plugin的相关介绍很少,具体可以参考微软MSDN文档。作为一个定义相当好的文档介绍,微软的文档是合格的,但是,
19、当你真正开始编程的时候,你会发现这些远远不够:下面记录的一些坑,很难在相应的文档中得到直接的提示;而是通过谷歌大法,结合其他程序员留下的线索,加上自己的不断调试来最终确认。
20、在微软文档的上下文中,Unity Native Plugin还有另外一个名字:Unmanaged Plugin,即非托管插件。简单来说,
21、的运行时环境中。NET框架(类似Java的JVM),而非托管插件则活在这个运行时环境之外,也就是说,它们是运行时环境的兄弟。
22、如果你原来的类库实现符合微软的COM(组件对象模型)规范,自然最好使用COM Interop4互操作性。而欢信IM SDK本身就是纯c实现。
23、所以采用平台Invoke5(简称P/Invoke),本文其余部分基于P/Invoke。
24、下图概述了托管和非托管区域代码如何互操作:
25、更具体地说,为了实现对非托管DLL函数的调用,只需要四个简单的步骤6:
26、确定DLL类库中需要操作的函数;
27、创建一个C#类来关联这些被操作的函数(给函数穿上马甲,进行集中管理和重复调用);
28、用DllImport标志在托管端(C#)定义函数原型;
29、在托管端随意调用相关的非托管区域函数。
30、在上图中,标准编组服务在两个方面负责编组/解组数据。
31、它主要定义了在两个不同的内存区域中复制和引用数据的规则7,迷宫中的坑主要与这些特定的规则有关。
32、Marshall/Unmarshall中的一个坑:sizeof(bool)=?大多数基本类型属于可直接复制到本机结构中的类型8:例如System。字节,系统。单身等。
33、经过调试跟踪,动态打印sizeof(bool)来确认非托管端的bool类型的数据长度,就会发现那个系统。Boolean默认会保存为4字节,而在macOS环境下(对于其他环境,
34、需要自认证),C定义的bool实际上只有一个字节。因此,当您在非托管端获取bool值时,您实际上只读取了System.Boolean的1/4字节。
35、当您声明多个连续的System.Boolean/bool值时,可能在非托管端读取的bool值只是第一个系统的不同偏移字节。布尔值。
36、知道了原因,解决方案自然就出来了,系统的时候只用了一个字节。布尔字段在托管端被强制声明,并被封送到非托管端:
37、[封送为(非托管类型.U1)]publicboolTrueOrFalse;坑二:字节对齐对于C开发者来说,
38、您可能知道,当类或结构中的字段在内存中排列时,字节将根据设置的打包长度对齐,例如:
39、struct my struct { intoneshorttwointthreboolfour }假设在我们的平台上,
40、Sizeof (int)=4,Sizeof (short)=2,Sizeof (bool)=1,如果我问你sizeof(MyStruct)=?你可能马上做一道加法得出答案,但答案不一定对。
41、看情况!假设我们按照4字节对齐,上面的结构实际上在内存中的排列如下:
42、理解这一点对我们的编码有两个意义:
43、通过合理安排字段声明顺序,优化存储效率,在内存布局上不留漏洞;
44、MarshalAsAttribute支持布局。对于绝对定位是显式的,并且理解字节对齐可以与非托管端的内存排列规则配合使用,以确保正确的字段长度映射。
45、否则也会出现字段长度不一致带来的麻烦。
46、Pit 3: How to avoid the double free standard marshalling service/interoperability marshaller always trying to release the memory allocated by uncontrolled side code 9,
47、这会带来双免的问题。如果遇到这个问题,程序会直接崩溃。
48、参考文献中给出了以下示例:
49、BSTRMethodOne(BSTRb){ returnb;}如果这段代码直接从非托管端DLL执行,不会发生额外的内存释放;但是当您从托管端调用这个方法时,
50、b会被释放两次。
51、而更让人抓狂的是,并没有相应的信息提示究竟是哪个指针,哪个字段被Double Free了,你唯一能做的就是一点点加代码来验证自己猜测。所以,严格来说,
52、并没有一个万无一失的方案来避免Double Free,你唯一能做的就是通过测试来验证结果(有点盲拧魔方的味道了)。
53、有两个基本的方法来解决Double Free的问题:
54、按照官方文档建议,在Unmanaged侧通过使用CoTaskMemAlloc来分配内存,通过此种方法分配的内存,
55、除非显式调用了CoTaskMemFree方法(在Unmanaged侧或者Managed侧均可以调用),Interop Marshaller会严格保证不去释放该内存。
56、使用这种方法可以灵活的在任意一侧分配内存,并在合适的时候在另一侧释放内存。
57、但上面这种方法貌似仅适用于Windows平台,在macOS下没有办法使用(需要引用win32base.dll相关实现)。
58、在macOS下仅能通过在Mananged侧调用Marshal.AllocCoTaskMem()方法分配内存,
59、并通过Marshal.FreeCoTaskMem()来在同一侧进行释放(按照此方法分配的内存指针传入Unmanaged侧后,不要进行任何释放即可)。
60、另外有一个不太可靠的workaround是:在Unmanaged一侧创建的内存指针尽量通过IntPtr传递,并在可能的时候将对象中一些指针类型的属性值置空,以避免Double Free的发生。
61、坑四:virtual函数带来的内存布局变化vptr和vtable是C++的一个概念:当你定义的类型中有虚函数存在时,内存对象的第一个位置会存放一个vptr指针,该指针指向vtable(虚函数表)。
62、因此当你开始创建的自定义类型一开始没有虚函数时(包括虚析构函数virtual ~MyClass()),一切运行正常。有一天你重构此类型,增加了一些虚函数:DUANG,
63、一切都崩塌了!原因就在于Unmanaged侧内存对象的排列规则变了,原有的对象字段都被新加入的vptr往后面移位了。
64、此时可能你唯一能做的就是通过Layout.Explicit来手工对齐每一个字段新的位置。
65、其它坑坑一:针对M1芯片编译对于M1芯片的macOS系统,编译环信IM Unity SDK时候需要注意几个问题:
66、XCode编译时需要Excluded Architecture中排除arm64架构(很奇葩的设置,不是应该排除x86吗?)
67、类库的依赖解决:通过otool -L命令来确认相应的plugin依赖的类库位置都正确(文件路径下文件确实存在),
68、如果相应文件不存在要手工拷贝文件到指定目录:而新的macOS安全架构限制了往系统目录下(如/usr/lib)进行任何改动,
69、一个临时的解决方法是通过install_name_tool工具主动修改类库依赖路径到另一个可以放置新文件的位置(如home目录)。
70、坑二:Delegate的正确使用姿势如果Managed侧的编程语言是C#,则Delegate是实现回调的重要手段。
71、在Unmanaged侧完成期望工作时回调一个FunctionPtr即可实现通用的回调模式,而此FunctionPtr正是对应到Managed侧的Delegate。
72、当你的Delegate绑定到一个类对象上时,你有两种选择:
73、namespaceChatSDK{//delegatedefinitionpublicvoiddelegateOnMessageReceived(EMMessagemessage);publicclassMyDelegate{//Option1:fieldpublicOnMessageReceivedMyMessageReceived;//Option2:instancemethodpublicvoidOnMessageReceived(EMMessagemessage){.}}//senddelegatemethodtounmanagedsideMyDelegatemd=new();NativeMethods.SetOnMessageReceivedCallback(md.MyMessageReceived);//option1NativeMethods.SetOnMessageReceivedCallback(md.OnMessageReceived);//option2}看起来两个方式都没有问题,
74、至于该Delegate字段的定义可以在此类的构造函数中通过以下方式实现:
75、.publicMyDelegate(){MyMessageReceived=(EMMessagemessage)={.}}.参考资料
76、List of Unity Games:
77、Unity and .NET:
78、Unity Scripting-Plugins:
79、COM Interop:
80、Platform Invoke:
81、如何调用Unmanaged DLL Functions:
82、Interop Marshalling:
83、Blittable Types:
84、Double Free:
本文到此结束,希望对大家有所帮助。