​ WebGL 平台限制了文件访问系统,在 Unity 以前版本中,开发者想要在 WebGL 上保存游戏到本地很不方便。

​ 目前,Unity 新版中给出了一项解决方案,但经测试,该方案目前不可取(截止 2025-01-07)。

  • Unity 版本:6000.0.26f1c1

1 问题描述

​ Unity WebGL 平台中,游戏保存数据到 Application.persistentDataPath 不生效(官方链接:https://docs.unity3d.com/ScriptReference/Application-persistentDataPath.html)。

image-20250107001802329

​ 老版本 Unity 2019.2 官方给出了解释:Unity WebGL 将会话之间必须保留的所有文件(例如 PlayerPrefs 或保存在 persistentDataPath 中的文件)存储到浏览器 IndexedDB。这是一个异步 API,因此不确定何时完成。

image-20250107010458838

2 老版解决方案(测试可行)

​ 借助 js 脚本,在保存后显式写入数据到/idbfs中。

2.1 创建 js 脚本

​ 在项目 /Assets/Plugins/ 目录下创建名为 Save 的 txt 文件,写入如下内容,更改后缀名为 .jslib:

mergeInto(LibraryManager.library, {
    // 刷新数据到 IndexedDB
    SyncDB: function () {
        FS.syncfs(false, function (err) {
           if (err) console.log("syncfs error: " + err);
        });
    }
});

2.2 添加 js 引用

  1. 在需要使用 js 脚本的 C# 代码块中添加命名空间 System.Runtime.InteropServices; 引用。
  2. 在需要使用 js 脚本的 C# 代码块中加入外部函数声明。
  3. 在负责保存的 C# 代码后面加入外部函数调用。

示例:

// 1. 引用命名空间
#if UNITY_WEBGL && !UNITY_EDITOR
using System.Runtime.InteropServices;
#endif

public class TxtHelper
{
    // 2. 加入外部函数声明
#if UNITY_WEBGL && !UNITY_EDITOR
    [DllImport("__Internal")]
    private static extern void SyncDB();
#endif
    
    public static void Save(string filePath, string content)
    {
        ... // Your code here
            
        // 3. 调用外部函数
#if UNITY_WEBGL && !UNITY_EDITOR
    	SyncDB();
#endif
    }

    public static string Load(string filePath)
    {
        ...
    }
}

​ 参考链接:

3 新版解决方案(测试不可行)

​ 对于较新的 Unity 版本(2021.3.44f1、2022.3.44f1、6000.0.11f1 及以上),有此问题的更新:

  • 修复了 Application.persistentDataPath 不会自动持久化的问题,通过添加新的 JS 配置选项“autoSyncPersistentDataPath: true”来启用 Application.persistentDataPath 到 IndexedDB 的自动同步。
  • 该选项位于 Builds/Index.html 文件中,取消注释并刷新正在运行的构建页面,问题将得到解决。

​ 即,不需要任何代码操作,只需要打包完成后,将 Builds/Index.html 文件中的第 78 行取消注释即可。

image-20250107012115743

​ 当然,前提是你选择了 WebGL 平台的 Default 模板,如下图所示(其他模板自行探索)。

image-20250107012433437

​ 如果不想每次打包后都修改 Builds/Index.html 文件,也可以直接修改模板中的 Index.html ,一劳永逸。其位置在 S:\Unity Editor\6000.0.26f1c1\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\WebGLTemplates\Default 目录中。

image-20250107012617172

​ 参考链接:

4 实际问题

​ 在 Unity 6000.0.26f1c1 版本中,按照步骤将上述第 78 行代码注释后,打包运行时出现如下报错:

image-20250107032152086 image-20250107032223093

报错信息:

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading ‘length’)
at Object.hashName (WebGL.framework.js:9:66347)
at Object.lookupNode (WebGL.framework.js:9:66977)
at Object.rmdir (WebGL.framework.js:9:54898)
at Object.rmdir (WebGL.framework.js:9:2685)
at Object.rmdir (WebGL.framework.js:9:75286)
at ___syscall_rmdir (WebGL.framework.js:9:177933)
at WebGL.wasm:0x14b27f
at WebGL.wasm:0x2610db6
at WebGL.wasm:0x26167f1
at WebGL.wasm:0x30ac93e
at WebGL.wasm:0x30ad59b
at WebGL.wasm:0x26101ae
at WebGL.wasm:0x29c020e
at WebGL.wasm:0x29bca03
at WebGL.wasm:0x29c119d
at WebGL.wasm:0x29c11b3
at WebGL.wasm:0x29b9849
at WebGL.wasm:0x29b6b88
at WebGL.wasm:0x327a445
at WebGL.framework.js:9:142371
at HandleError (WebGL.framework.js:9:142414)
at WebGL.framework.js:9:144075

​ 解决方法是:将 config.autoSyncPersistentDataPath 设置为 false 或将该行注释掉。问题跟踪来源:https://issuetracker.unity3d.com/issues/webgl-typeerror-cannot-read-properties-of-undefined-reading-length-error-is-thrown-when-starting-the-player-when-config-dot-autosyncpersistentdatapath-is-set-to-true

image-20250107033431171

​ 也就是说,新版解决方案在 Unity 6000.0.26f1c1 版本中失效。

​ 目前退回到使用老版解决方案,测试可行。

​ WebGL 可真是太好玩辣!

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐