fbernaly
fbernaly

Reputation: 61

Using protobuf-net in Unity-iOS

I am an iOS developer and working on an app that uses protobuf to pass some messages generated in Unity to iOS as an array of bytes. I using protobuf-net (https://github.com/mgravell/protobuf-net) by Marc Gravell in my Unity project (I am not an Unity developer).

I am following the instructions in the repo's readme. I am downloading the dll from here: https://code.google.com/archive/p/protobuf-net/downloads

I decorated my classes like this:

using ProtoBuf;  

[ProtoContract]
public class AppToPortal
{
    [ProtoMember(1)]
    public uint timestamp_sec { get; set; }
    [ProtoMember(2)]
    public Command command { get; set; }
    [ProtoMember(3)]
    public byte[] accessory_message { get; set; }
}

[ProtoContract]
public class PortalToApp
{
    [ProtoMember(1)]
    public uint timestamp_ms { get; set; }

    [ProtoMember(2)]
    public Event @event { get; set; }

    [ProtoMember(3)]
    public DeviceInfo info { get; set; }

    [ProtoMember(4)]
    public CommandResponse cmdRsp { get; set; }

    [ProtoMember(5)]
    public byte[] accessory_message { get; set; }
}

[ProtoContract]
public class Command
{
    [ProtoMember(1)]
    public CommandType type { get; set; }

    [ProtoMember(2)]
    public byte[] ota_signature { get; set; }

    [ProtoContract]
    public enum CommandType
    {
        ExampleModeOne = 1,
        ExampleModeTwo = 2,
        RequestDeviceInfo = 3,
        TestMode = 4,
        Reset = 5,
        StartOTA = 6,
    }
}  

And my serializer/deserializer looks like

public class Proto
{
    public static byte[] Serialize<T>(T  obj) where T : class
    {
        if (null ==  obj) return null;
        try
        {
            using (var stream = new System.IO.MemoryStream())
            {
                ProtoBuf.Serializer.Serialize<T>(stream,  obj);
                return stream.ToArray();
            }
        }
        catch
        {
            // Log error
            throw;
        }
    }

    public static T Deserialize<T>(byte[] bytes) where T : class
    {
        if (null == bytes) return null;
        try
        {
            using (var stream = new System.IO.MemoryStream(bytes))
            {
                return ProtoBuf.Serializer.Deserialize<T>(stream);
            }
        }
        catch
        {
            // Log error
            throw;
        }
    }
}  

When I compose the message I am doing this:

// Compose message with protobuf
TimeSpan timestamp = DateTime.Now.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc));
Command command = new Command();
command.type = Command.CommandType.RequestDeviceInfo;

AppToPortal message = new AppToPortal();
message.command = command;
message.timestamp_sec = Convert.ToUInt32(timestamp.TotalSeconds);

Debug.Log(message);

// Serialize message
byte[] bytes = Proto.Serialize<AppToPortal>(message);  

When I deserializing a bytes array received I am doing this:

PortalToApp message = Proto.Deserialize<PortalToApp>(bytes);
Debug.Log("Did deserialize: " + message + " - firmware_version: " + message.info.firmware_version + " - battery_level: " + message.info.battery_level);

When I run this in my Mac I am able to serialize/deserialize any message, no error at all. But when I export my Unity project to iOS I am getting this error messages in the Xcode console:

(Filename: /Users/builduser/buildslave/unity/build/Runtime/Export/Debug.bindings.h Line: 43)

NotSupportedException: /Users/builduser/buildslave/unity/build/External/il2cpp/il2cpp/libil2cpp/icalls/mscorlib/System.Reflection.Emit/DynamicMethod.cpp(19) :  Unsupported internal call for IL2CPP:DynamicMethod::create_dynamic_method - System.Reflection.Emit is not supported.
    at System.Reflection.Emit.DynamicMethod.CreateDynMethod () [0x00000] in <filename unknown>:0 
    at System.Reflection.Emit.DynamicMethod.CreateDelegate (System.Type delegateType) [0x00000] in <filename unknown>:0 
    at ProtoBuf.Compiler.CompilerContext.BuildSerializer (IProtoSerializer head, ProtoBuf.Meta.TypeModel model) [0x00000] in <filename unknown>:0 
    at ProtoBuf.Serializers.CompiledSerializer..ctor (IProtoTypeSerializer head, ProtoBuf.Meta.TypeModel model) [0x00000] in <filename unknown>:0 
    at ProtoBuf.Serializers.CompiledSerializer.Wrap (IProtoTypeSerializer head, ProtoBuf.Meta.TypeModel model) [0x00000] in <filename unknown>:0 
    at ProtoBuf.Meta.MetaType.get_Serializer () [0x00000] in <filename unknown>:0 
    at ProtoBuf.Meta.RuntimeTypeModel.Deserialize (Int32 key, System.Object value, ProtoBuf.ProtoReader source) [0x00000] in <filename unknown>:0 
    at ProtoBuf.Meta.TypeModel.Deserialize (System.IO.Stream source, System.Object value, System.Type type, ProtoBuf.SerializationContext context) [0x00000] in <filename unknown>:0 
    at ProtoBuf.Serializer.Deserialize[T] (System.IO.Stream source) [0x00000] in <filename unknown>:0 
    at MCPP.Proto.Deserialize[T] (System.Byte[] bytes) [0x00000] in <filename unknown>:0 
    at MenuPanel.OnReceiveData (MCPP.Notification notification) [0x00000] in <filename unknown>:0 
    at MCPP.MCPPKit.PostNotification (MCPP.Notification aNotification) [0x00000] in <filename unknown>:0 
    at MCPP.IOSPlugin.didReceiveDataCallback (IntPtr ptr, Int32 length) [0x00000] in <filename unknown>:0 
Rethrow as InvalidOperationException: It was not possible to prepare a serializer for: MCPP.PortalToApp
    at ProtoBuf.Compiler.CompilerContext.BuildSerializer (IProtoSerializer head, ProtoBuf.Meta.TypeModel model) [0x00000] in <filename unknown>:0 
    at ProtoBuf.Serializers.CompiledSerializer..ctor (IProtoTypeSerializer head, ProtoBuf.Meta.TypeModel model) [0x00000] in <filename unknown>:0 
    at ProtoBuf.Serializers.CompiledSerializer.Wrap (IProtoTypeSerializer head, ProtoBuf.Meta.TypeModel model) [0x00000] in <filename unknown>:0 
    at ProtoBuf.Meta.MetaType.get_Serializer () [0x00000] in <filename unknown>:0 
    at ProtoBuf.Meta.RuntimeTypeModel.Deserialize (Int32 key, System.Object value, ProtoBuf.ProtoReader source) [0x00000] in <filename unknown>:0 
    at ProtoBuf.Meta.TypeModel.Deserialize (System.IO.Stream source, System.Object value, System.Type type, ProtoBuf.SerializationContext context) [0x00000] in <filename unknown>:0 
    at ProtoBuf.Serializer.Deserialize[T] (System.IO.Stream source) [0x00000] in <filename unknown>:0 
    at MCPP.Proto.Deserialize[T] (System.Byte[] bytes) [0x00000] in <filename unknown>:0 
    at MenuPanel.OnReceiveData (MCPP.Notification notification) [0x00000] in <filename unknown>:0 
    at MCPP.MCPPKit.PostNotification (MCPP.Notification aNotification) [0x00000] in <filename unknown>:0 
    at MCPP.IOSPlugin.didReceiveDataCallback (IntPtr ptr, Int32 length) [0x00000] in <filename unknown>:0 
MCPP.MCPPKit:PostNotification(Notification)
MCPP.IOSPlugin:didReceiveDataCallback(IntPtr, Int32)

(Filename: currently not available on il2cpp Line: -1)

NotSupportedException: /Users/builduser/buildslave/unity/build/External/il2cpp/il2cpp/libil2cpp/icalls/mscorlib/System.Reflection.Emit/DynamicMethod.cpp(24) :  Unsupported internal call for IL2CPP:DynamicMethod::destroy_dynamic_method - System.Reflection.Emit is not supported.
    at System.Reflection.Emit.DynamicMethod.Finalize () [0x00000] in <filename unknown>:0 
UnityEngine.UnhandledExceptionHandler:PrintException(String, Exception)
UnityEngine.UnhandledExceptionHandler:HandleUnhandledException(Object, UnhandledExceptionEventArgs)

(Filename: currently not available on il2cpp Line: -1)

Apparently something wrong with the ProtoBuf.Serializer.Deserialize(stream) and ProtoBuf.Serializer.Serialize(stream, obj ).

Do you have any idea what I could be doing wrong? Any help would be appreciated.

Upvotes: 1

Views: 2453

Answers (1)

SilentSin
SilentSin

Reputation: 1036

You can't use Reflection.Emit on iOS because iOS doesn't allow JIT compiling.

That's why a NotSupportedException is coming from ...Reflection.Emit.DynamicMethod.CreateDynMethod which ProtoBuf uses to generate efficient serialization code at runtime.

See if there's an option in ProtoBuf to disable dynamic code generation. Otherwise you'll probably need to use a different serialization system.

Upvotes: 1

Related Questions