外观
Stage06|JSB & Native Bridge
Lesson078|Web 与 Native 的运行环境为什么不完全一致
Tags: #Creator2.x #Stage06 #Web #Native #PlatformDifficulty: ⭐⭐⭐⭐☆
真实问题:Web 能播音,iOS 无声,应该先改哪一行
Web 浏览器允许用户点击后播放音频;iOS 需要用户手势解锁 Audio Session;Native 文件路径和 Web URL也不是同一语义。
环境差异至少包括:
text
JavaScript Engine
文件系统/沙盒
网络安全与域名
音频会话/权限
GPU/纹理格式
线程与生命周期
基础库/OS版本一、本课目标
Creator 让业务代码尽量跨平台复用,但“相同 API”只代表抽象接口相同,不代表底层行为、性能和生命周期完全相同。
二、运行时差异
| 维度 | Web | Native |
|---|---|---|
| JS 引擎 | 浏览器提供 | 应用嵌入式运行时 |
| 渲染 | WebGL / 浏览器 | Native Renderer / 图形 API |
| 文件 | 浏览器沙盒和 Web API | 应用沙盒和原生文件系统 |
| 音频 | WebAudio / HTML Audio | 原生音频实现 |
| 网络 | 浏览器安全策略 | 原生网络栈或引擎封装 |
| 调试 | DevTools | JS 调试器 + Native 调试器 |
具体实现随 Creator 版本和平台变化,表格只说明抽象边界。
三、文件系统差异
Web 中通常不能任意访问用户磁盘;Native 中也受到应用沙盒、权限和平台目录约束。
text
资源只读目录
可写目录
缓存目录
临时目录
外部存储或平台共享目录路径分隔符、编码、大小写和权限都可能不同。不要硬编码桌面开发机绝对路径。
四、JavaScript Engine 差异
不同引擎可能在以下方面不同:
- 语法支持和 Polyfill。
- JIT/AOT 能力。
- GC 策略。
- 堆内存限制。
- 异常堆栈格式。
- 定时器和微任务行为。
构建前应确认目标 Native 运行时支持的 JavaScript 特性,不能只依据当前浏览器。
五、渲染和纹理差异
text
WebGL 能力
Native 图形 API
GPU 驱动
纹理压缩格式
RenderTarget
Shader 编译同一 Shader 在 Web 预览可运行,Native 设备上仍可能因为精度、扩展、驱动或格式出现差异。
六、网络和安全策略
Web 可能受:
- CORS。
- HTTPS Mixed Content。
- 浏览器缓存。
- 域名和 Cookie 策略。
Native 可能受:
- 平台网络权限。
- 证书和系统版本。
- App Transport Security 等平台规则。
- 后台网络限制。
相同 URL 在不同平台失败,需要分别检查平台层错误。
七、生命周期差异
移动 Native 应用可能经历:
text
前台
→ 失去焦点
→ 后台
→ 被系统挂起
→ 恢复
→ 被系统终止Web 页面也可能隐藏、冻结或被浏览器回收,但事件和资源策略不同。倒计时、音频、网络和资源恢复必须监听对应平台生命周期。
八、调试策略
text
先在 Web 快速验证业务逻辑
→ Native 构建验证平台分支
→ 目标设备复现
→ 同时收集 JS 日志和 Native 日志
→ 必要时使用 C++ 断点和符号“Web 正常”只能缩小范围,不能结束排查。
九、案例:Web 音频正常,iOS 无声
排查层次:
text
AudioClip 是否加载
→ Creator Audio API 参数
→ Native Audio Binding
→ iOS 音频会话和静音策略
→ 前后台恢复
→ 设备音量和权限如果问题只出现在 Native,优先比较平台适配和生命周期,而不是重写全部业务逻辑。
十、常见误区
误区一:跨平台 API 保证完全相同行为
它提供共同抽象,平台限制仍然存在。
误区二:浏览器支持的 JavaScript 语法 Native 一定支持
要看嵌入式 JS Engine 版本和构建转换。
误区三:Native 可以任意访问文件系统
应用沙盒和平台权限仍然限制路径。
误区四:模拟器能代替真机性能测试
GPU、内存、驱动和生命周期差异很大。
十一、练习与答案
- Web 与 Native 至少有哪些运行时差异?
- 为什么不能硬编码开发机文件路径?
- Web Shader 正常但 Native 异常,应检查什么?
- 为什么需要同时收集 JS 和 Native 日志?
答案:
- JS 引擎、文件、渲染、音频、网络、线程和生命周期。
- 平台沙盒、权限、分隔符和可写目录不同。
- 图形 API、扩展、精度、纹理格式、驱动和平台 Shader 编译。
- 问题可能发生在业务、绑定、C++ 或平台层。
Creator 2.4.x 双端差异实验
EnvMatrixProbe.ts
ts
const { ccclass } = cc._decorator;
@ccclass
export default class EnvMatrixProbe extends cc.Component {
start() {
cc.log(
'[env]',
'native=', cc.sys.isNative,
'platform=', cc.sys.platform,
'os=', cc.sys.os
);
}
async run(action: string, fn: () => Promise<void>) {
const begin = Date.now();
try {
await fn();
cc.log('[env]', action, 'ok', Date.now() - begin);
} catch (error) {
cc.error('[env]', action, 'failed', error);
}
}
}逐项实验
- 冷启动并记录首屏。
- 用户点击后播放短音频,再自动播放一次。
- 写入/读取一条设置。
- 访问一个资源和一个远程 URL。
- 切后台再恢复。
- 在同一设备 WebView/Native(若项目支持)对照。
结果按“能力、权限、错误码、回退”记录,不按平台名写大量散落分支。
能力适配层
ts
interface AudioService {
unlockByUserGesture(): Promise<void>;
play(id: string): Promise<void>;
}
interface FileService {
read(key: string): Promise<string | null>;
}业务只调用接口;Web/Native 实现负责路径、权限、会话和错误。这样平台差异在边界内可测试。
真实项目故障:Web 资源路径在 Native 失效
代码保存 /assets/config.json,Native 包中不存在这个开发机 URL。正确做法是:
- 静态资源用 Creator 资源入口;
- 动态资源用 resources/Bundle 逻辑路径;
- 用户数据用平台可写沙盒接口;
- 远程数据使用 HTTPS 与合法域名;
- 统一错误/超时/回退。
诊断矩阵
| 能力 | Web 先查 | Native 先查 |
|---|---|---|
| 音频 | autoplay/用户手势 | Audio Session/权限/格式 |
| 文件 | URL/浏览器存储 | 沙盒路径/权限 |
| 网络 | CORS/HTTPS | 域名/证书/网络权限 |
| 纹理 | WebGL 支持 | GPU 格式/内存 |
| 生命周期 | 页面可见性 | 后台/暂停/原生回调 |
版本边界与练习答案
Web/Native 差异受浏览器、OS、基础库和 Creator 2.4.x 构建影响。课程不写死平台限制数值,发布前查当前官方文档。
- 为什么能力适配层比 if platform 分散更好? 集中处理权限、错误和回退,业务语义一致且可测试。
- Web 音频正常是否证明 Native 音频资源正确? 不证明,音频会话、格式和用户手势规则可能不同。
- 用户数据为什么不能用 assets 路径写? assets/通常是发布资源,设备上不可写或不是持久数据目录。
- 差异实验要固定什么? Creator 版本、构建配置、设备、OS、网络、缓存和用户动作。
十二、本课总结
text
跨平台复用的是接口和大部分业务,不是完全相同的底层环境。
Web 用于快速验证,Native 和真机用于最终确认。十三、下一课预告
text
Lesson079|主线程、渲染、网络、音频与平台线程边界