Unity Newtonsoft JSON安卓IL2CPP打包ReferenceConverter构造方法缺失报错
异常根因
这个异常是IL2CPP构建的固有特性触发的:
Unity执行IL2CPP构建时会默认对.NET基础类库执行未使用代码裁剪,编辑器下使用Mono运行时不会执行裁剪逻辑,所以运行正常。Newtonsoft.Json反序列化接口类型的属性时,会尝试调用
System.ComponentModel.ReferenceConverter处理类型转换,这个类默认会被IL2CPP裁剪,导致运行时找不到构造方法抛出异常。
解决方案
以下方案按实施成本从低到高排序:
方案1:添加裁剪配置保留缺失类
在Assets目录下新建名为link.xml的文件,写入以下内容即可,无需修改业务代码:<linker> <assembly fullname="System"> <type fullname="System.ComponentModel.ReferenceConverter" preserve="all"/> </assembly> </linker>方案2:修改属性类型避免接口转换
直接把IpLocationData的属性从接口类型改为具体实现类类型,从根源避免Newtonsoft调用ReferenceConverter:public class IpLocationData : IIpLocationData { public IpLocationData(ConnectionData connection, CurrencyData currency, LocationData location, bool success, TimeData time) { ConnectionData = connection; CurrencyData = currency; LocationData = location; Success = success; TimeData = time; } [JsonProperty("connection")] public ConnectionData ConnectionData { get; } [JsonProperty("currency")] public CurrencyData CurrencyData { get; } [JsonProperty("location")] public LocationData LocationData { get; } [JsonProperty("success")] public bool Success { get; } [JsonProperty("time")] public TimeData TimeData { get; } public override string ToString() { return JsonConvert.SerializeObject(this); } }这个方案修改量小,运行效率最高。
方案3:保留接口设计,自定义类型转换器
如果你需要保留接口抽象的架构设计,可以实现通用的接口转实现类转换器,替代系统的ReferenceConverter:
首先实现转换器类:public class ConcreteTypeConverter<TInterface, TImplementation> : JsonConverter<TInterface> where TImplementation : TInterface { public override void WriteJson(JsonWriter writer, TInterface value, JsonSerializer serializer) { serializer.Serialize(writer, value); } public override TInterface ReadJson(JsonReader reader, Type objectType, TInterface existingValue, bool hasExistingValue, JsonSerializer serializer) { return serializer.Deserialize<TImplementation>(reader); } }然后给每个接口属性绑定对应的转换器:
[JsonProperty("connection")] [JsonConverter(typeof(ConcreteTypeConverter<IConnectionData, ConnectionData>))] public IConnectionData ConnectionData { get; } [JsonProperty("currency")] [JsonConverter(typeof(ConcreteTypeConverter<ICurrencyData, CurrencyData>))] public ICurrencyData CurrencyData { get; } // 剩余两个接口属性同理配置即可
验证方法
如果不确定是否是裁剪导致的问题,可以临时把Unity PlayerSettings里的Managed Stripping Level调整为Disabled,构建测试如果不再报错,就可以确认是裁剪问题,再选择对应方案处理即可,不建议长期禁用裁剪,会导致包体大幅增大。
内容的提问来源于stack exchange,提问作者Стас Рыжов
相关产品推荐
相关产品推荐

