pusher / pusher-websocket-dotnet

Pusher Channels Client Library for .NET
MIT License
112 stars 113 forks source link

Incompatibility with il2cpp due to dynamic keyword #69

Closed cdauphinee closed 4 years ago

cdauphinee commented 5 years ago

I have a Unity 2019.2 project that builds for iOS, using the il2cpp scripting back-end. At run time, I receive the following exception whenever a dynamic is read or written to (i.e. receiving messages or subscribing to a presence channel):

[Exception] NullReferenceException: Object reference not set to an instance of an object.
    System.Linq.Expressions.Interpreter.LightLambda.MakeRunDelegateCtor (System.Type delegateType) (at <00000000000000000000000000000000>:0)
    System.Linq.Expressions.Interpreter.LightLambda.GetRunDelegateCtor (System.Type delegateType) (at <00000000000000000000000000000000>:0)
    System.Linq.Expressions.Interpreter.LightLambda.MakeDelegate (System.Type delegateType) (at <00000000000000000000000000000000>:0)
    System.Linq.Expressions.Expression`1[TDelegate].Compile (System.Boolean preferInterpretation) (at <00000000000000000000000000000000>:0)
    System.Runtime.CompilerServices.CallSite`1[T].MakeUpdateDelegate () (at <00000000000000000000000000000000>:0)
    System.Runtime.CompilerServices.CallSite`1[T].GetUpdateDelegate (T& addr) (at <00000000000000000000000000000000>:0)
    System.Runtime.CompilerServices.CallSite`1[T]..ctor (System.Runtime.CompilerServices.CallSiteBinder binder) (at <00000000000000000000000000000000>:0)
    System.Runtime.CompilerServices.CallSite`1[T].Create (System.Runtime.CompilerServices.CallSiteBinder binder) (at <00000000000000000000000000000000>:0)

It seems like it's trying to do run-time code generation. To my knowledge, this isn't supported by il2cpp (and not allowed on iOS, even if it were supported). I suspect the same problem is also present on Android builds.

Looking at the code, I came up with two quick solutions that would fix this:

  1. Replace internal deserialization to dynamic (i.e. used for presence channels) with classes.
  2. Replace the usage of dynamic in the EventEmitter callbacks with string.
    • Interface compatibility can be maintained by having both Action<string> and Action<dynamic> overloads, though internally only Action<string> is stored
    • This also allows the consumer to decide which JSON library to use for message deserialization, and could be useful if they have custom converters.

I have no problem making these changes myself, but I want to put this out there for discussion before opening a PR.

damdo commented 5 years ago

Hey @cdauphinee, thank you for reporting this and for your overall analysis on the library potential issues. Could you open a PR with your recommended fix? We (me and @imaji) will be more than happy to review it and move forward with this. Thank you.

cdauphinee commented 5 years ago

@damdo @imaji Thanks for the response, I've put up https://github.com/pusher/pusher-websocket-dotnet/pull/77 for early feedback.

damdo commented 4 years ago

Resolved by #77

Alienide-Interactive commented 3 years ago

thanks cdauphinee. I am doing Replace the usage of dynamic in the EventEmitter callbacks with string as a way arround.

dotsquid commented 3 years ago

You could just make Unity not strip required code by using the following link.xml

<linker>
    <assembly fullname="System.Core">
        <type fullname="System.Linq.Expressions.Interpreter.LightLambda" preserve="all" />
    </assembly>
</linker>
CavernHead commented 2 years ago

I have exactly the same error when i run my app on android il2cpp I don't know how to do this: -Replace internal deserialization to dynamic. -Replace the usage of dynamic in the EventEmitter callbacks with string I get my issue when i call the JObject.Parse(string) any help would be appreciated