Hey to all, My game uses a interlayer plugin(dll files in Plugins folder, coded with .NET3.5) which we use to communicate with our backend. Everythings works pretty much well in Editor. However, when I build it with IL2CPP(SRV: .NET 4.x equivalent, ACL: .NET Standart 2.0), I get NullReferenceException. I started to think that our interlayer plugin is not compatible with IL2CPP. Then, I go through the code try to detect some classes which I suspect(by taking into consideration Scripting Restrictions). Can someone(@JoshPeterson) help me who knows IL2CPP, AOT, etc concepts. Sorry for including that much scripts, but I think that this thread may also help most plugin developers. Here is the error: Code (CSharp): 09-26 20:52:17.049 4036 4115 E Unity : NullReferenceException: Object reference not set to an instance of an object.09-26 20:52:17.049 4036 4115 E Unity : at GameManager+<CheckServerStatus>d__14.MoveNext () [0x00000] in <00000000000000000000000000000000>:0 09-26 20:52:17.049 4036 4115 E Unity : at UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) [0x00000] in <00000000000000000000000000000000>:0 09-26 20:52:17.049 4036 4115 E Unity : at GameManager+<InitializeGame>d__9.MoveNext () [0x00000] in <00000000000000000000000000000000>:0 09-26 20:52:17.049 4036 4115 E Unity : at UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) [0x00000] in <00000000000000000000000000000000>:0 09-26 20:52:17.049 4036 4115 E Unity : at GameManager.Start () [0x00000] in <00000000000000000000000000000000>:0 09-26 20:52:17.049 4036 4115 E Unity : <InitializeGame>d__9:MoveNext() 09-26 20:52:17.049 4036 4115 E Unity : UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr) 09-26 20:52:17.049 4036 4115 E Unity : GameManager:Start() 09-26 20:52:17.049 4036 4115 E Unity : 09-26 20:52:17.049 4036 4115 E Unity : (Filename: currently not available on il2cpp Line: -1) Here is the ChechServerStatus() function of GameManager where i get the error exactly at Container.Resolve<IUserManager>() Code (CSharp): public IEnumerator CheckServerStatus() { // I get NullReferenceException at Resolve function Container.Resolve<IUserManager>().CheckServerStatus((ServerStatusResultModel model) => { // Some code here } } Here is the Container script Code (CSharp): using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; namespace RedApple.GameFramework.contanier { /// <summary> /// ref:https://www.codeproject.com/Articles/1075189/Lets-write-a-Tiny-IoC-Container-to-learn-and-for-f?msg=5194025 /// </summary> public class Container : IContainer { Dictionary<Type, RegistrationModel> instanceRegistry = new Dictionary<Type, RegistrationModel>(); public void RegisterInstanceType<I, C>() where I : class where C : class { RegisterType<I, C>(REG_TYPE.INSTANCE); } public void RegisterSingletonType<I, C>() where I : class where C : class { RegisterType<I, C>(REG_TYPE.SINGLETON); } private void RegisterType<I, C>(REG_TYPE type) { if (instanceRegistry.ContainsKey(typeof(I)) == true) { instanceRegistry.Remove(typeof(I)); } instanceRegistry.Add( typeof(I), new RegistrationModel { RegType = type, ObjectType = typeof(C) } ); } public I Resolve<I>() { return (I)Resolve(typeof(I)); } private object Resolve(Type t) { object obj = null; if (instanceRegistry.ContainsKey(t) == true) { RegistrationModel model = instanceRegistry[t]; if (model != null) { Type typeToCreate = model.ObjectType; ConstructorInfo[] consInfo = typeToCreate.GetConstructors(); var dependentCtor = consInfo.FirstOrDefault(item => item.GetCustomAttributes(true).FirstOrDefault(att => att.GetType() == typeof(TinyDependencyAttribute)) != null); if (dependentCtor == null) { // use the default constructor to create obj = CreateInstance(model); } else { // We found a constructor with dependency attribute ParameterInfo[] parameters = dependentCtor.GetParameters(); if (parameters.Count() == 0) { // Futile dependency attribute, use the default constructor only obj = CreateInstance(model); } else { // valid dependency attribute, lets create the dependencies first and pass them in constructor List<object> arguments = new List<object>(); foreach (var param in parameters) { Type type = param.ParameterType; arguments.Add(this.Resolve(type)); } obj = CreateInstance(model, arguments.ToArray()); } } } } return obj; } private object CreateInstance(RegistrationModel model, object[] arguments = null) { object returnedObj = null; Type typeToCreate = model.ObjectType; if (model.RegType == REG_TYPE.INSTANCE) { returnedObj = InstanceCreationService.GetInstance().GetNewObject(typeToCreate, arguments); } else if (model.RegType == REG_TYPE.SINGLETON) { returnedObj = SingletonCreationService.GetInstance().GetSingleton(typeToCreate, arguments); } return returnedObj; } } }
Is it mis-binding because "Container" is misspelled as "Contanier" in some places? I'm not sure what the cross-binding mechanism uses to find entrypoints.
I'll be honest, I didn't study the code all that closely... but one thing that comes to mind is if you are expecting anything "object-y" to go through that call boundary, because AFAIK it will not. If you're passing and/or returning primitives such as int, string, bool, float, that will work fine. (Strings have to be marshaled through from a System.IntPtr however). But pretty sure if you're slanging around your own class instances it won't work across the interop boundary with IL2CPP.
You can't easily use dependency injection with IL2CPP. In a MonoBehaviour's Start, try instantiating your concrete implementation once. But better to just not use dependency injection.
I suspect that the problem is with managed code stripping. Some code in the interlayer plugin likely uses reflection, so the managed code stripper that runs as part of the IL2CPP build process is probably removing IL code that is required. You can prevent this from happening by adding a link.xml file to the project. See the documentation about this feature here: https://docs.unity3d.com/Manual/IL2CPP-BytecodeStripping.html