Siccity / SerializableCallback

UnityEvent and System.Func had a child
MIT License
359 stars 53 forks source link

iOS build il2cpp #5

Closed zakrzus closed 4 years ago

zakrzus commented 5 years ago

Hi, I tried to use dialogue node system on iOS build but when i try run "Event Class" my console shows that exception was thrown in "InvokableCallback" On the last line: (Filename: currently not available on il2cpp Line: -1)

Is there any workround ?

zakrzus commented 5 years ago

I've done some research and got message:

ExecutionEngineException: Attempting to call method 'InvokableCallback`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]::.ctor' for which no ahead of time (AOT) code was generated.

The AOT compiler does not realize that it should generate code probably for constructor in class SerializeCallback.cs

dlees commented 5 years ago

@zakrzus Did you find any simple solutions to this?

dlees commented 5 years ago

I found this documentation: https://docs.unity3d.com/Manual/ScriptingRestrictions.html#AOT and https://github.com/aws/aws-sdk-net/issues/477

Apparently, you need to explicitly call each function that you need the compiler to generate.

dlees commented 5 years ago

Note this now affects Android because Google requires 64 bit applications and (as of 2018.3) Unity only supports IL2CPP for building the 64 bit android apps.

I got the same error as zakrzus, but for different types:

08-08 10:05:24.260: E/Unity(15209): ExecutionEngineException: Attempting to call method 'InvokableCallback`2[[System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]::.ctor' for which no ahead of time (AOT) code was generated.

Since this is the constructor, I'm not sure if it's the same generic virtual method problem.

I'm trying to figure out what the System.Single is. (I think it might be float based on https://social.msdn.microsoft.com/Forums/vstudio/en-US/ed7d3355-39a5-4933-b446-2c909997b9c0/what-is-the-use-of-single-data-type-in-c?forum=netfxbcl)

dlees commented 5 years ago

This is the full stack trace that I could get:

08-08 10:05:24.260: E/Unity(15209): ExecutionEngineException: Attempting to call method 'InvokableCallback`2[[System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]::.ctor' for which no ahead of time (AOT) code was generated.

08-08 10:05:24.260: E/Unity(15209): at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) [0x00000] in <00000000000000000000000000000000>:0

08-08 10:05:24.260: E/Unity(15209): at System.RuntimeType.CreateInstanceImpl (System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, System.Object[] args, System.Globalization.CultureInfo culture, System.Object[] activationAttributes, System.Threading.StackCrawlMark& stackMark) [0x00000] in <00000000000000000000000000000000>:0

08-08 10:05:24.260: E/Unity(15209): at System.Activator.CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, System.Object[] args, System.Globalization.CultureInfo culture, System.Object[]

So the error happens here: https://github.com/Siccity/SerializableCallback/blob/84bf6a7f8840be6d4061369d123b3a254a42ae95/SerializableCallbackBase.cs#L42

dlees commented 5 years ago

Another potential cause: https://forum.unity.com/threads/il2cpp-no-constructor-found-for-system-resources-runtimeresourceset.349940/

Basically, the code stripper could be removing the constructor of InvokableCallback and we could add a link.xml file to preserve it. This thread doesn't get resolved and the error/build is slightly different. So I'm not sure if this is the issue.

dlees commented 5 years ago

I think since the constructor of InvokableCallback is called via reflection, IL2CPP never notices the constructor is needed so strips the constructor away. Then at runtime it can't find it.

https://stackoverflow.com/questions/56183606/invoke-generic-method-via-reflection-in-c-sharp-il2cpp-on-ios

This could only be a problem with generics of value types.

Either way, we can manage the bytecode stripping with this: https://docs.unity3d.com/Manual/IL2CPP-BytecodeStripping.html . (making the link.xml file as described in the protobuf example.)

dlees commented 5 years ago

So the link.xml change wasn't necessary. Here's how I fixed these errors in my project:

For every error like:

ExecutionEngineException: Attempting to call method 'InvokableCallback`2[[System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]::.ctor' for which no ahead of time (AOT) code was generated.

This means IL2CPP never generated a constructor for the InvokableCallback of the type listed. So, we must hard-code create the class that matches the types given and call the constructor.

So to fix this one, I added code in my repo (doesn't matter what class it's in, so I'd recommend it's own AotGenerationFixer class):

private static void OnlyForIL2CPPAOT() {
    new FloatStringInvokable(4.0f, "");
}

class FloatStringInvokable : InvokableCallback<float, string> {
    public FloatStringInvokable(object target, string methodName) : base(target, methodName) { }
}

I made an InvokableCallback<float, string> because the exception listed this type specifically was missing. ('InvokableCallback`2[[System.Single, ...],[System.String, ...]]::.ctor') (Note: System.Single = float)

I'm not sure how to anticipate when these errors show up. (I never used any Serializable or InvokableCallbacks like these as far as I'm aware.) So for now, the best approach is to build, launch on phone, see what errors you get, and create the necessary class to fix the error, rinse/repeat.

Hope this helps someone!

silkentrance commented 4 years ago

Here are some links to get around the dead / unused code elimination feature:

If you experience problems with the editor:

And in order to preserve code (e.g. methods, classes etc) you can define your own PreserveAttribute and use that for annotating the respective classes, methods or constructors

More information on this can be found in this comment

See also

zakrzus commented 4 years ago

Thank you very much :)