Protobuf-net在Unity WebPlayer中的兼容解决方案

由于项目需要所以使用了Unity + Protobuf。
但是问题随之而来,因为Protobuf是JIT运行时动态编译的,而Unity不支持这种运行时动态编译,同时Protobuf是基于.net2.0框架的,因此当项目发布在PC时,出现了异常:

1
2
3
4
5
6
7
8
9
10
ArgumentOutOfRangeException: Argument is out of range.

Parameter name: options
at System.Text.RegularExpressions.Regex.validate_options (RegexOptions options) [0x0003a] in /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/System/System.Text.RegularExpressions/Regex.cs:248

at System.Text.RegularExpressions.Regex..ctor (System.String pattern, RegexOptions options) [0x00017] in /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/System/System.Text.RegularExpressions/Regex.cs:214

at Google.ProtocolBuffers.Descriptors.DescriptorPool..cctor () [0x00000] in :0
Rethrow as TypeInitializationException: An exception was thrown by the type initializer for Google.ProtocolBuffers.Descriptors.DescriptorPool
......

这里使用的是Protobuf-Csharp包,通过排查,在发布时将PlayerSetting中Api Compatibility Level 设置成.Net 2.0即可解决。

如图

但当需要发布到WebPlayer的时候,发现一个基本无解的问题——WebPlayer PlayerSetting中的Api Compatibility Level按钮是灰色的!只支持.Net 2.0 subset模式,因此发布后依然无法解决protobuf异常问题。

因此开始搜索国内外的所有帖子寻求解决方案,发现国内基本没有WebPlayer使用Protobuf的相关帖子,但有类似Protobuf不能在Unity IOS版本下运行的案例,因此参考其中一个案例的解决方案开始尝试,到
http://protobuf-net.googlecode.com/svn/trunk/protobuf-net/
protobuf-net的SVN上下载了其源代码,导入Unity中。此时在Unity中编译时,会报错unsafe不能使用,在Assets目录下面新建smcs.rsp文件,并在其中写入-unsafe 字符串,前后不加空格,重新启动unity即可。
此时打包PC端时甚至不再需要将Api Compatibility Level设置成.Net 2.0。
但当打包成WebPlayer时异常依旧存在,在C:\Users\Administrator\AppData\Local\Temp\UnityWebPlayer\log目录下查看其日志发现异常内容为

1
2
3
4
5
6
7
MethodAccessException: Attempt to access a private/protected method failed.
at System.Security.SecurityManager.ThrowException (System.Exception ex) [0x00000] in :0
at ProtoBuf.BufferPool.GetBuffer () [0x00000] in :0
at ProtoBuf.ProtoWriter..ctor (System.IO.Stream dest, ProtoBuf.Meta.TypeModel model, ProtoBuf.SerializationContext context) [0x00000] in :0
at ProtoBuf.Meta.TypeModel.Serialize (System.IO.Stream dest, System.Object value, ProtoBuf.SerializationContext context) [0x00000] in :0
at ProtoBuf.Meta.TypeModel.Serialize (System.IO.Stream dest, System.Object value) [0x00000] in :0
at ProtoBuf.Serializer.Serialize[IExtensible] (System.IO.Stream destination, IExtensible instance) [0x00000] in:0

MethodAccessException: Attempt to access a private/protected method failed.
似乎是安全沙箱的问题,但是检测了服务端的843端口确认已经开启,并成功抓包到的返回串

因此排除沙箱的问题。
虽然变了一个异常,但似乎是离真像又近了一步,继续Google解决方案,终于在Unity的官方发现一篇类似的提问
Does protobuf-net work in the Unity web player?
在其中非常幸运的发现了protobuf-net的作者marc.gravell的回复:

看到最后一句This has been fixed, with r594 now available on google-code as a pre-built binary that is confirmed working.瞬间就放心了,这个问题已经被作者注意到并且更新版本后解决。

因此去Protobuf-net的Google下载点下载marc.gravell所说的” the download from google-code includes a “unity” build” https://code.google.com/p/protobuf-net/downloads/list
这里用的是目前最新的protobuf-net r668
下载完毕后打开压缩包,在Full\unity中找到protobuf-net.dll将其添加到项目中。再次打包成WebPlayer,运行,抓包,消息成功发送!

到此protobuf兼容Unity WebPlayer的问题就算是完美的解决了,关于Protobuf-net在Unity中的使用方式我在后续一篇中会给出一个最简的模型,方便大家举一反三。
本篇到此,谢谢关注。

BeiTown
2014-05-15

本文链接:Protobuf-net在Unity WebPlayer中的兼容解决方案

转载声明:BeiTown原创,转载请注明来源:BeiTown's Coder 编码之源,谢谢


Tags: , ,