哎,各种坑,总算整差不多明白了,放了一个github工程,把配套的protobuf-net源码,dll和生成工具都放一起了。
注意仔细读README,如果使用mono的,直接把dll放到工程的Plugins目录下就行了,要选择.net 2.0,不能用.net 2.0 subset。
如果要使用il2cpp的,需要把协议文件与protobuf-net for Unity的dll文件一起编译成一个dll库,然后用precompile工具生成一个预编译的Serializer,在Unity工程中使用这个Serializer和生成的协议文件库。这样做是因为il2cpp只支持AOT代码,也就是全编译的机器码,但是protobuf-net里面有一些模板库,会在运行时动态生成一些代码来执行,在il2cpp的时候会报错。
下面还是保留了一下以前写的内容,但是后来发现是不对的。即使不使用enum,在有repeated字段的时候,还是会触发JIT的代码导致运行失败。尝试了预先写好一些AOT Function的方法也是不行。后来就直接放弃了,还是用precomplier的方式了。虽然复杂一点,但是写好自动化脚本也还可以。
======================= 以前的内容 =====================
还要注意的是,如果要用il2cpp,那么proto文件里面不要引用其他文件中的enum,因为这样会引发protobuf执行一段平台上不支持的JIT代码,使用字符串反射到执行的方法的一块代码。例如,如下的两个proto:
common.proto里面定义了一个enum
enum COMMON_OP
{
OP_DEFAULT = 0;
OP_OP1 = 1;
OP_OP2 = 2;
}
然后在另外一个proto里面的一个消息里使用COMMON_OP时,按照proto2的语法,需要制定默认值:
message somemsg
{
optional common.COMMON_OP operation = 1[default = OP_DEFAULT];
}
这样的消息在序列化的时候就会出错,报错信息像这样:
ExecutionEngineException: Attempting to call method 'ProtoBuf.Property.PropertyUtil`1 for
which no ahead of time (AOT) code was generated. at System.Reflection.MonoMethod.Invoke
(System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder,
System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in
<filename unknown>:0
把enum换成简单类型int32,用的时候只使用enum的整数值作比较就能规避这个问题。
message somemsg
{
optional int32 operation = 1;
}
如果有人知道protobuf-net的代码能怎样改改支持这种消息,请留言告诉我。