You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Unity安卓平台序列化与反序列化失效问题求助

解决Unity安卓打包后列表序列化/反序列化失效的问题

听起来你遇到了一个很典型的Unity跨平台文件处理问题——编辑器里正常跑,打包成APK到安卓就掉链子,还没法直接拿到报错信息。我帮你拆解下可能的问题点,再给你调整后的代码方案。

可能的问题根源

  • 文件路径与读写权限问题:安卓上persistentDataPath是唯一安全可读写的路径,但你代码里把文件写到了Application.persistentDataPath + "/Data",丢失了原文件的.xml后缀,序列化器可能无法识别文件格式。
  • WWW的异步处理不严谨:直接用while(!reader.isDone)会阻塞主线程,而且完全没处理加载失败的情况(比如文件不存在、读取错误),导致后续的文件写入根本没执行,dbPath指向的文件要么是空的要么根本不存在。
  • 序列化器的配置与IL2CPP裁剪问题:如果用的是XmlSerializer,要确保MaterialDB类和它包含的列表元素都标记了[Serializable];要是用IL2CPP后端打包,这些类还可能被自动裁剪掉,导致序列化失败。

调整后的代码方案

1. 修正文件路径与WWW加载逻辑

改用协程处理WWW加载,避免阻塞主线程,同时补全文件后缀、添加错误捕获:

private IEnumerator Start()
{
    if (Application.platform == RuntimePlatform.Android)
    {
        string oriPath = Path.Combine(Application.streamingAssetsPath, "Data.xml");
        using (WWW reader = new WWW(oriPath))
        {
            yield return reader;
            
            // 检查加载是否出错
            if (!string.IsNullOrEmpty(reader.error))
            {
                Debug.LogError($"加载StreamingAssets文件失败: {reader.error}");
                yield break;
            }
            
            // 保存到persistentDataPath,保留.xml后缀
            string realPath = Path.Combine(Application.persistentDataPath, "Data.xml");
            File.WriteAllBytes(realPath, reader.bytes);
            dbPath = realPath;
        }
    }
    else
    {
        dbPath = Path.Combine(Application.streamingAssetsPath, "Data.xml");
    }
    
    // 等路径初始化完成后再加载数据
    LoadItems();
}

2. 优化LoadItems与SaveItems的文件操作

using语句自动释放流资源,避免手动Dispose的疏漏,同时添加异常捕获和日志:

public void LoadItems()
{
    if (!File.Exists(dbPath))
    {
        // 文件不存在时初始化空数据并保存
        materialDB = new MaterialDB();
        SaveItems();
        return;
    }
    
    try
    {
        using (FileStream stream = new FileStream(dbPath, FileMode.Open))
        {
            if (stream.Length > 0)
            {
                materialDB = serializer.Deserialize(stream) as MaterialDB;
            }
            else
            {
                materialDB = new MaterialDB();
            }
        }
    }
    catch (Exception e)
    {
        Debug.LogError($"加载数据失败: {e.Message}\n{e.StackTrace}");
        materialDB = new MaterialDB();
    }
}

public void SaveItems()
{
    try
    {
        using (FileStream stream = new FileStream(dbPath, FileMode.Create))
        {
            serializer.Serialize(stream, materialDB);
        }
    }
    catch (Exception e)
    {
        Debug.LogError($"保存数据失败: {e.Message}\n{e.StackTrace}");
    }
}

额外排查建议

  • 获取安卓报错日志:用Android Studio的Logcat或者Unity的adb logcat命令,搜索你的应用包名,就能找到序列化时的具体错误(比如类型找不到、权限不足)。
  • IL2CPP裁剪保护:如果用IL2CPP后端,在PlayerSettings > Optimization > Managed Stripping Level设为Low,或者给相关类添加[Preserve]属性防止被裁剪:
    [Serializable]
    [Preserve]
    public class MaterialDB
    {
        public List<YourItemClass> items;
    }
    
    [Serializable]
    [Preserve]
    public class YourItemClass
    {
        // 你的字段定义
    }
    
  • 更换序列化方式:如果用的是BinaryFormatter,安卓上可能有兼容性问题,建议换成XmlSerializer或者导入Newtonsoft.Json包用JSON序列化。

内容的提问来源于stack exchange,提问作者user8016859

火山引擎 最新活动