Unity中SignalR客户端编辑器正常,Android IL2CPP构建连接失败
我在Unity中使用SignalR客户端开发实时Android游戏,Unity编辑器内运行一切正常,但切换为IL2CPP脚本后端构建Android版本后,无法连接到Hub服务器。通过adb logcat调试发现,HubConnectionBuilder.Build()方法执行时抛出类型初始化异常,代码及错误信息如下:
异常触发代码
connection = new HubConnectionBuilder() .WithUrl(ApiNeed.UrlNeed + "/game", opts => { opts.HttpMessageHandlerFactory = (message) => { if (message is HttpClientHandler clientHandler) // 跳过SSL证书验证 clientHandler.ServerCertificateCustomValidationCallback += (sender, certificate, chain, sslPolicyErrors) => { return true; }; return message; }; opts.CloseTimeout = new TimeSpan(0, 5, 0); if (Token.ToLower().StartsWith("bearer")) { Token = Token.Substring("bearer".Length); } opts.Headers.Add("Authorization", Token); } ) .Build(); // 异常发生处
捕获到的异常信息
The type initializer for 'Microsoft.AspNetCore.SignalR.Client.HubConnection' threw an exception.
myQm: at System.Reflection.RuntimeConstructorInfo.InternalInvoke (System.Object obj, System.Object[] parameters, System.Boolean wrapExceptions) [0x00000] in <00000000000000000000000000000000>:0
myQm: at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor (Microsoft.Extensions.DependencyInjection.ServiceLookup.ConstructorCallSite constructorCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext context) [0x00000] in <00000000000000000000000000000000>:0
myQm: at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2[TArgument,TResult].VisitCallSiteMain (Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite callSite, TArgument argument) [0x00000] in <00000000000000000000000000000000>
补充说明:切换为Mono脚本后端构建时功能正常,但Mono无法生成x64/ARM64架构APK,且谷歌会提示应用不安全,因此必须使用IL2CPP后端。
可能的解决方法
1. 匹配SignalR客户端与IL2CPP兼容版本
IL2CPP对反射、动态代码支持有限,高版本SignalR可能存在兼容性问题:
- 降级SignalR客户端到5.0.x或6.0.x稳定版,避免使用7.x及以上预览/新版本
- 通过NuGet安装时,选择与当前Unity版本适配的包,优先选长期支持版
2. 配置IL2CPP链接器规则
IL2CPP链接器会自动剔除未被直接引用的代码,导致SignalR内部依赖服务无法初始化:
- 在
Assets/目录下创建link.xml文件,添加以下规则保留必要程序集:
<linker> <assembly fullname="Microsoft.AspNetCore.SignalR.Client" preserve="all" /> <assembly fullname="Microsoft.Extensions.DependencyInjection" preserve="all" /> <assembly fullname="System.Net.Http" preserve="all" /> <assembly fullname="System.Threading.Tasks.Extensions" preserve="all" /> <assembly fullname="Microsoft.AspNetCore.SignalR.Common" preserve="all" /> </linker>
3. 调整SSL证书验证逻辑
原代码中的匿名委托在IL2CPP下可能因序列化问题报错:
- 若SignalR版本支持,直接使用
SkipCertificateValidation快捷选项替代回调:
.WithUrl(ApiNeed.UrlNeed + "/game", opts => { opts.SkipCertificateValidation = true; // 其他配置... })
- 版本不支持时,改用静态方法替代匿名委托:
private static bool ValidateCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; } // 配置中调用静态方法 opts.HttpMessageHandlerFactory = (message) => { if (message is HttpClientHandler clientHandler) clientHandler.ServerCertificateCustomValidationCallback = ValidateCertificate; return message; };
4. 修正Authorization头处理
原代码移除Bearer前缀可能导致认证失败,且字符串处理可能存在隐式问题:
if (Token.ToLower().StartsWith("bearer")) { Token = Token.Substring("bearer".Length).Trim(); } // 标准认证头格式需包含Bearer前缀 opts.Headers.Add("Authorization", $"Bearer {Token}");
5. 启用IL2CPP调试日志
开启调试选项获取更精准的错误定位:
- 进入
Edit > Project Settings > Player > Android > Publishing Settings - 勾选
Development Build和Script Debugging - 构建后再次通过
adb logcat捕获完整异常堆栈,定位具体缺失的类型或方法
内容的提问来源于stack exchange,提问作者mohammadreza khorasani

