Unity C#嵌入iOS项目跨区域数字解析转换异常问题
问题背景
我有一个嵌入Unity场景作为视图的iOS项目,问题出现在系统本地化设置使用逗号,而非点号.作为小数分隔符的设备上。我从原生Swift代码向Unity发送参数字符串,Unity解析iOS传入的字符串后,生成新参数嵌入后续HTTP请求中。
异常日志
Xcode中获取的故障设备日志如下:
param from iOS: 615d48538edef900126a784e***616957b6f59835001137ae7b***98.42519685039369***100.06561679790026 Request Object: - distanceFromCeiling: 9,84251968503937E+15 - distanceFromSideWall: 1,000656167979E+16 - Obj: : UpdateRequest - Obj.distanceFromCeiling: : 9,84251968503937E+15 - Obj.distanceFromSideWall: : 1,000656167979E+16 DATA request {"distanceFromCeiling":9842519685039368.0,"distanceFromSideWall":10006561679790026.0}
预期发送的参数为98.42519685039369, 100.06561679790026,但实际请求JSON中的数值变为了9842519685039368.0, 10006561679790026.0,使用en-US本地化的设备无此问题。
可疑代码
Unity侧代码如下,is_the_problem_here注释标记了可疑位置:
using System; using System.Collections; using System.Collections.Generic; using Lean.Touch; using Newtonsoft.Json; using UnityEngine; using UnityEngine.UI; using BestHTTP; using System.Text; using System.Runtime.InteropServices; using System.Text.RegularExpressions; using UnityEngine.UIElements; public class GameManager : MonoBehaviour { // 其他函数 // ==================================== void callApiFromIOS(string param) { Debug.Log("param from iOS: " + param); string[] str = param.Split(new string[] { "***" }, StringSplitOptions.None); // is_the_problem_here System.Nullable <double> distanceFromCeiling = null; System.Nullable<double> distanceFromSideWall = null; if (str != null && str.Length >= 4) { string ceiling = str[2]; if (!ceiling.Equals("null")) { // is_the_problem_here distanceFromCeiling = Convert.ToDouble(ceiling); } string sideWall = str[3]; if (!sideWall.Equals("null")) { // is_the_problem_here distanceFromSideWall = Convert.ToDouble(sideWall); } } Debug.Log("Request Object: "); Debug.Log("- distanceFromCeiling: " + distanceFromCeiling); Debug.Log("- distanceFromSideWall: " + distanceFromSideWall); UpdateRequest updateRequest = new UpdateRequest(distanceFromCeiling, distanceFromSideWall); Debug.Log(" - Obj: : " + updateRequest); Debug.Log(" - Obj.distanceFromCeiling: : " + updateRequest.distanceFromCeiling); Debug.Log(" - Obj.distanceFromSideWall: : " + updateRequest.distanceFromSideWall); // is_the_problem_here string data = JsonConvert.SerializeObject(updateRequest); Debug.Log("DATA request " + data); // 剩余代码为将JSON数据设为请求体并发送HTTP请求 }
正常设备日志如下:
param from iOS: 615d48538edef900126a784e***616957b6f59835001137ae7b***98.42519685039369***100.06561679790026 Request Object: - distanceFromCeiling: 98.4251968503937 - distanceFromSideWall: 100.0656167979 - Obj: : UpdateRequest - Obj.distanceFromCeiling: : 98.4251968503937 - Obj.distanceFromSideWall: : 100.0656167979 DATA request {"distanceFromCeiling":98.425196850393689,"distanceFromSideWall":100.06561679790026}
尝试过的无效方案
我尝试自定义Json序列化转换器修改小数输出格式,未达到预期效果,输出仍和错误日志一致:
var converter = new FormattedDecimalConverter(CultureInfo.GetCultureInfo("en-US")); string data = JsonConvert.SerializeObject(updateRequest, converter);
转换器类代码:
using System; using System.Globalization; using Newtonsoft.Json; internal class FormattedDecimalConverter : JsonConverter { private CultureInfo culture; public FormattedDecimalConverter(CultureInfo culture) { this.culture = culture; } public override bool CanConvert(Type objectType) { return true; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { writer.WriteValue(Convert.ToString(value, culture)); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { throw new NotImplementedException(); } }
解决方案
问题根源是区域本地化解析规则差异:Convert.ToDouble默认使用当前设备的区域设置解析字符串,在使用逗号作为小数分隔符的区域,会把输入字符串中的点号识别为千位分隔符,最终解析出错误的超大数值。
修复方法是将Convert.ToDouble()替换为指定固定区域格式的解析方法:
// 替换前 distanceFromCeiling = Convert.ToDouble(ceiling); distanceFromSideWall = Convert.ToDouble(sideWall); // 替换后 distanceFromCeiling = double.Parse(ceiling, CultureInfo.InvariantCulture); distanceFromSideWall = double.Parse(sideWall, CultureInfo.InvariantCulture);
使用CultureInfo.InvariantCulture可以保证无论设备区域如何设置,都会按点号作为小数分隔符的规则解析字符串。
内容的提问来源于stack exchange,提问作者Eddie
相关产品推荐
相关产品推荐

