unity-web端h5记录

unity-web端h5记录


前篇


web 端使用 tolua (不成熟, 不可用)


平台适配

文件 io 适配

  • web 请求资源, 全都需要异步加载

构建和运行 WebGL 项目

Build 文件夹详解

Build 文件夹包含以下文件([ExampleBuild] 表示目标构建文件夹的名称):

文件名 包含
[ExampleBuild].loader.js 网页需要用来加载 Unity 内容的 JavaScript 代码。
[ExampleBuild].framework.js JavaScript 运行时和插件。
[ExampleBuild].wasm WebAssembly 二进制文件。
[ExampleBuild].mem 用于初始化播放器堆内存的二进制映像文件。Unity 仅针对多线程 WebAssembly 构建生成此文件。
[ExampleBuild].data 资源数据和场景。
[ExampleBuild].symbols.json 调试错误堆栈跟踪所需的调试符号名称。仅当启用 Debug Symbols 选项时 (File > Build Settings > Player Settings),才会为 Release 构建生成此文件。
[ExampleBuild].jpg 在构建加载时显示的背景图像。仅当在 Player Settings (File > Build Settings > Player Settings > Splash Image) 中提供了背景图像时,才会生成此文件。有关更多信息,请参阅启动画面页面。

如果对构建启用某种压缩方法,Unity 会识别与压缩方法对应的扩展名,并将此扩展名添加到 Build 子文件夹中的文件的名称中。如果启用 Decompression Fallback,Unity 将扩展名 .unityweb 附加到构建文件名。否则,Unity 为 Gzip 压缩方法附加扩展名 .gz,或者为 Brotli 压缩方法附加扩展名 .br。 有关更多信息,请参阅 WebGL:压缩构建和服务器配置


包体优化


压缩配置

  • https://docs.unity3d.com/cn/2021.3/Manual/webgl-deploying.html

  • 压缩格式

    image-20230310181338678

    压缩方法 描述
    gzip 这是默认选项。gzip 文件比 Brotli 文件更大,但构建速度更快,且所有浏览器都基于 HTTP 和 HTTPS 实现此格式的本机支持。
    Brotli Brotli 压缩提供最佳压缩比。Brotli 压缩文件小于 gzip,但需要更长的压缩时间,因此会增加发布版本的迭代时间。Chrome 和 Firefox 仅原生支持基于 HTTPS 的 Brotli 压缩。
    Disabled 禁用压缩。如果要在后期处理脚本中实现您自己的压缩,请使用此选项。如果计划在托管服务器上使用静态压缩,也应该使用此选项。

剥离引擎代码

  • 打开“ 其他设置”以访问“ 剥离引擎代码”选项。默认情况下会选中此选项以启用WebGL的代码剥离。选中此选项后,Unity不会包含您不使用的任何类的代码。例如,如果您不使用任何物理组件或功能,则整个物理引擎
    ,从您的构建中删除。有关详细信息,请参阅下面的“剥离”部分。

    img


分包

  • 将引擎编译的和自己的代码分离出来, 这样多个游戏包就可以引用同一个引擎代码, 浏览器就会使用缓存

预加载

  • 将不同游戏的 wasm 预加载到本地, 进入游戏时就会很快了

使用 nginx 作为文件服务器

使用

  • 启动

    1
    2
    3
    C:\server\nginx-1.0.2>start nginx
    or
    C:\server\nginx-1.0.2>nginx.exe
  • 停止

    1
    2
    3
    C:\server\nginx-1.0.2>nginx.exe -s stop

    C:\server\nginx-1.0.2>nginx.exe -s quit
  • 重新载入配置

    1
    C:\server\nginx-1.0.2>nginx.exe -s reload
  • 重新打开日志文件

    1
    C:\server\nginx-1.0.2>nginx.exe -s reopen
  • 查看版本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
        C:\server\nginx-1.0.2>nginx -v



    ---

    ### 平台判断

    - 编译宏 https://docs.unity3d.com/Manual/PlatformDependentCompilation.html

    ```json
    #if UNITY_WEBGL
    LogUtil.D("--- UNITY_WEBGL ");
    #endif
  • 运行时

    1
    Application.platform == RuntimePlatform.WebGLPlayer

http

使用 best http, 版本最新即可, 如: 2.8.2


websocket

使用 best http, 版本最新即可, 如: 2.8.2


调试

查看调用栈

  • 想要在浏览器查看到调用栈, 需要打开开发模式

    开启后, 包体将会很大, 打包时间也变长, 发布时一定要关掉 !!!

    1. 发布设置

      image-20230302100219633

    2. 平台打包

      image-20230302100239709


禁用浏览器缓存

  • F12 打开开发者工具, 在 Network 中, 勾选 disable cache

    这样每次就会从服务器拉取资源, 而不是用 indexedDB 中的缓存资源

    image-20230314103951278

    • transferred: 是实际传输的大小
    • resources: 是传输后解压后的大小 (因为开 gzip 之类的, 浏览器会进行解压)

强刷浏览器

  1. 按 F12 打开开发者模式

  2. 然后才能在 刷新 按钮右键 -> 清空缓存并硬性重新加载

    image-20230308101059504


http 请求跨域

nginx 允许跨域配置

  • 暂无

临时解决方案, 禁止掉浏览器的跨域检测

  • 解决Chrome浏览器的跨域问题 - https://juejin.cn/post/7019171779478290463

    1. 找到快捷方式, 右击打开属性,找到 目标 字段,并在目标字段后面加上参数:

      image-20230303163122303

      1
      --disable-web-security --user-data-dir=D:\ChromeData\MyChromeDevUserData

      其中 D:\ChromeData\MyChromeDevUserData 为跨域浏览器数据存储的地方,可以根据需要修改。

      2.png

    2. 双击打开浏览器, 出现不安全提示就表示禁用了 跨域检测

      image-20230303163204291


使用模板

使用

  1. 项目的 Assets 文件夹并创建一个名为 WebGLTemplates 的文件夹, 然后在 WebGLTemplates 目录下, 每一个子目录是一个模板, 可以将引擎预制的模板 (模板存储在 <Unity Installation>/PlaybackEngines/WebGLSupport/BuildTools/WebGLTemplates/ 下) 拷出来放进去, 重新打开 player settings 页面就会出现可选择模板目录

    (这里我将缩略图随便涂了点红色方便辨认)

    image-20230306165329653

  2. 然后就可以在自定义的模板里加入自己的脚本逻辑了.


与 js 交互


注意事项

不能使用多线程

在 WebGL 平台上使用 AssetBundle 时的注意事项:

  • 在 AssetBundle 中使用未在主构建中使用的类类型时,Unity 可能会从构建中剥离这些类的代码。尝试从 AssetBundle 加载资源时,这可能会导致失败。请使用 BuildPlayerOptions.assetBundleManifestPath 修复该问题,或参阅下面有关*剥离*的部分以了解其他选项。
  • WebGL 不支持线程,但 http 下载内容仅在下载完成后才可用。因此,在下载完成时,Unity WebGL 构建需要在主线程上解压缩 AssetBundle 数据,而这会阻止主线程。为避免这种中断,LZMA AssetBundle 压缩不可用于 WebGL 上的 AssetBundle。此情况下使用 LZ4 对 AssetBundle 进行压缩,这种压缩格式可非常高效地按需进行解压缩。如果所需的压缩大小比 LZ4 能够提供的压缩大小更小,可将 Web 服务器配置为对 AssetBundle 使用 gzip 或 Brotli 压缩(基于 LZ4 压缩)。请参阅有关部署压缩构建的文档以详细了解如何执行此操作。
  • WebGL supports AssetBundle caching with UnityWebRequestAssetBundle.GetAssetBundle. This method uses the IndexedDB API from your browser to store a cache on the user’s device. Some browsers might have limited support for IndexedDB and any browsers might request the user’s authorization to store data on the disk. For more information, see WebGL browser compatibility.
  • 不支持多线程,因为 JavaScript 不支持多线程,所以 System.Threading 命名空间下的类不要使用;
  • 不能在 VS 中进行断点调试,后面会介绍如何进行调试;
  • 不能直接使用 Socket,包括 System.Net下的任何类型,以及 System.Net.Sockets 下的部分类型,以及 UnityEngine.Network,如果需要在 WebGL 平台使用网络功能,可以使用 WWW或者 UnityWebRequest这些都是基于 Http协议的实现,如要需要高实时性,可以选择 WebSockets或者 WebRTC;
  • WebGL 1.0是基于 OpenGL ES 2.0,WebGL 2.0基于 OpenGL ES 3.0,所以存在相应的限制;
  • WebGL 音频是基于自定义的后台,只具备基本的音频功能;
  • WebGL 是 AOT(ahead of time,即静态编译平台,因此不能使用 System.Reflection.Emit 下的类型进行代码生成,IL2CPP和 iOS 也是如此。
  • webgl 不支持 LZMA 压缩, 只能用 LZ4
  • 内置的video player 无法播放。(可以使用AVPro 播放)
  • 不支持ComputeShader: SystemInfo.supportsComputeShaders

解决显示不支持移动端

  • 浏览器运行时提示: WebGL builds are not supported on mobile devices.

    image-20230304113032992

  • 在构建出来包里的 index.html 的提示去掉即可

    image-20230304113401763


包体大小优化


持久化数据

  • 使用 PlayerPrefs 相关 api 即可.

    1
    PlayerPrefs.SetString("Name", "hello");

    手动清除浏览器缓存, 会将它清除掉; 如果是强制刷新重新加载页面, 则不会清除掉.

    Unity WebGL 将所有持久化数据(PlayerPrefs、缓存)都保存到浏览器的 IndexedDB 中,在开发者工具中,可以通过 Application 标签页查看,这一API 是异步的,所以不知道什么时候能够完成。


踩坑

未开启 gz

  • 报错

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
        Unable to parse Build/aaa.framework.js.gz! This can happen if build compression was enabled but web server hosting the content was misconfigured to not serve the file with HTTP Response Header "Content-Encoding: gzip" present. Check browser Console and Devtools Network tab to debug.

    官方推荐的是 使用 nginx, 参考: https://docs.unity3d.com/cn/2021.2/Manual/webgl-server-configuration-code-samples.html

    - 在

    ```json
    http {

    # 增加一个 server 配置
    server {
    listen 8811;
    server_name localhost;
    root C:/Users/wilker/Desktop/aaa; # unity 打出的 h5 包
    index index.html
    # location / {
    # root html;
    # index index.html index.htm;
    # }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    root html;
    }

    ########################################
    # Add the following config within http server configuration
    # ...

    # On-disk Brotli-precompressed data files should be served with compression enabled:
    location ~ .+\.(data|symbols\.json)\.br$ {
    # Because this file is already pre-compressed on disk, disable the on-demand compression on it.
    # Otherwise nginx would attempt double compression.
    gzip off;
    add_header Content-Encoding br;
    default_type application/octet-stream;
    }

    # On-disk Brotli-precompressed JavaScript code files:
    location ~ .+\.js\.br$ {
    gzip off; # Do not attempt dynamic gzip compression on an already compressed file
    add_header Content-Encoding br;
    default_type application/javascript;
    }

    # On-disk Brotli-precompressed WebAssembly files:
    location ~ .+\.wasm\.br$ {
    gzip off; # Do not attempt dynamic gzip compression on an already compressed file
    add_header Content-Encoding br;
    # Enable streaming WebAssembly compilation by specifying the correct MIME type for
    # Wasm files.
    default_type application/wasm;
    }

    # On-disk gzip-precompressed data files should be served with compression enabled:
    location ~ .+\.(data|symbols\.json)\.gz$ {
    gzip off; # Do not attempt dynamic gzip compression on an already compressed file
    add_header Content-Encoding gzip;
    default_type application/octet-stream;
    }

    # On-disk gzip-precompressed JavaScript code files:
    location ~ .+\.js\.gz$ {
    gzip off; # Do not attempt dynamic gzip compression on an already compressed file
    add_header Content-Encoding gzip;
    default_type application/javascript;
    }

    # On-disk gzip-precompressed WebAssembly files:
    location ~ .+\.wasm\.gz$ {
    gzip off; # Do not attempt dynamic gzip compression on an already compressed file
    add_header Content-Encoding gzip;
    # Enable streaming WebAssembly compilation by specifying the correct MIME type for
    # Wasm files.
    default_type application/wasm;
    }
    }
    }





    ---

    #### 移动设备不支持

    - 报错

    ```json
    WebGL builds are notsupported on mobile devices.



    据说不用管这个



    ---

    #### 中文显示

    - a



    ---

    #### http 请求

    ##### 原生端旧的 best http 插件报错

    ```json
    Invoking error handler due to
    ReferenceError: Runtime is not defined
    at XMLHttpRequest.http_onload (http://localhost:8811/Build/aaa.framework.js.gz:3:85864)
  • 解决办法: 升级 best http 插件到 2.8.2+ 即可.

UnityWebRequest 请求报错
1
2
3
exception thrown: TypeError: Cannot set properties of undefined (setting '1'),TypeError: Cannot set properties of undefined (setting '1')
at _JS_WebRequest_Create (http://localhost:8811/Build/slotsweb.framework.js.gz:3:73755)
at http://localhost:8811/Build/slotsweb.wasm.gz:wasm-function[47545]:0x10870bf

edge, firefox 运行异常


不要使用阻塞代码

不要是阻塞代码来等待 WWW 或 WebRequest 完成,比如下面代码:

1
while(!www.isDone){}

因为 WebGL 是单线程,而 XMLHttpRequest 又是异步方法,整个一直执行 while 循环,而不能更新 XMLHttpRequest 响应信息,可以使用协程和 yield 来等待下载完成。