ArkWeb 白屏很容易被误判。用户看到的是页面空白,开发者第一反应可能是网络慢、接口挂了、前端页面有问题。但在 HarmonyOS 7 / API 26 的应用里,ArkWeb 白屏至少要分成四段看:容器有没有创建出来,内核有没有初始化完成,首个 URL 有没有真正开始加载,失败后有没有离线兜底。
如果这四段混在一起排查,最后很容易改错地方。比如明明是首屏资源超时,却去改组件层状态;明明是离线兜底没接住,却去怀疑内核初始化。
先把白屏拆成四个检查点
我会先把 ArkWeb 白屏拆成下面四类:
| 检查点 | 说明 | 常见表现 |
| 容器创建 | Web 组件是否进入页面树 | 页面区域空,连 loading 都没有 |
| 内核初始化 | Web 内核是否完成可用状态 | 页面有容器,但一直不加载 |
| 资源加载 | 首个 URL、静态资源、接口是否返回 | loading 很久或中途失败 |
| 兜底恢复 | 超时、断网、失败是否能展示替代页 | 白屏停住,用户无法继续 |
这张表的价值是先把问题定位到阶段。阶段错了,后面代码改得再多也很难稳定。
给 ArkWeb 页面加阶段 trace
先做一个轻量的阶段记录器,不要把所有日志都写成一行。
~~~ts
type WebStage = 'container' | 'kernel' | 'navigation' | 'resource' | 'fallback'
type WebTrace = {
traceId: string
stage: WebStage
step: string
costMs?: number
success?: boolean
detail?: string
}
class ArkWebTraceRecorder {
private startedAt = Date.now()
print(trace: WebTrace): void {
console.info(
'[arkweb-trace]',
trace.traceId,
trace.stage,
trace.step,
'cost=' + (trace.costMs ?? Date.now() - this.startedAt),
'success=' + (trace.success ?? true),
trace.detail ?? ''
)
}
}
~~~
这段代码不解决白屏,但它能帮我们知道白屏停在哪一步。没有这个 trace,后面只能靠猜。
案例一:容器出来了,但首屏资源超时
很多 Web 页面不是完全加载失败,而是首屏资源太慢。应用如果没有设置自己的超时兜底,用户看到的就是一直白着。
~~~ts
class WebFirstScreenGuard {
private timeoutId: number | undefined
private recorder = new ArkWebTraceRecorder()
start(traceId: string): void {
this.recorder.print({ traceId, stage: 'container', step: 'webCreated' })
this.timeoutId = setTimeout(() => {
this.showFallback(traceId, 'first screen timeout')
}, 5000)
}
markFirstContent(traceId: string): void {
if (this.timeoutId !== undefined) {
clearTimeout(this.timeoutId)
this.timeoutId = undefined
}
this.recorder.print({ traceId, stage: 'resource', step: 'firstContentVisible' })
}
showFallback(traceId: string, reason: string): void {
this.recorder.print({
traceId,
stage: 'fallback',
step: 'showOfflineCard',
success: false,
detail: reason
})
this.visibleFallback = true
}
}
~~~
这里我选择 5000ms 作为首屏兜底阈值,不是说所有页面都必须 5 秒,而是要有明确阈值。没有阈值,白屏就会变成无限等待。
案例二:离线状态没有兜底,返回页面后继续白屏
第二类问题经常出现在弱网或离线后恢复。页面第一次加载失败,用户切到后台再回来,还是一片空白。
~~~ts
class WebRecoverController {
private lastUrl = ''
private failedReason = ''
open(url: string): void {
this.lastUrl = url
this.failedReason = ''
this.loadUrl(url)
}
onLoadFailed(reason: string): void {
this.failedReason = reason
this.showRecoverPanel(reason)
}
retry(): void {
if (!this.lastUrl) {
return
}
this.failedReason = ''
this.loadUrl(this.lastUrl)
}
private showRecoverPanel(reason: string): void {
console.info('[arkweb-recover]', reason)
this.recoverVisible = true
}
}
~~~
这段代码的重点是:失败后要有可操作的恢复入口。不要只在日志里记失败,也不要让用户停在白屏里。
加载状态不要只靠一个 loading
ArkWeb 页面如果只有一个 loading 布尔值,排查时信息太少。更好的做法是把状态拆成阶段。
~~~ts
type WebLoadState =
function reduceWebState(state: WebLoadState, event: string): WebLoadState {
if (event === 'create') {
return { type: 'creating' }
}
if (event === 'visible' && state.type === 'loading') {
return { type: 'contentVisible', url: state.url, costMs: Date.now() - state.startedAt }
}
if (event === 'fail' && state.type === 'loading') {
return { type: 'failed', url: state.url, reason: 'load failed', canRetry: true }
}
return state
}
~~~
状态分清楚以后,页面展示也简单:creating 显示骨架,loading 显示进度,failed 显示恢复卡片,contentVisible 才显示 Web 内容。
本地复现脚本
可以不用真实网页,先模拟两条路径:首屏超时和加载失败后重试。
~~~ts
async function fakeLoad(costMs: number, shouldFail: boolean): Promise<'visible'> {
await new Promise(resolve => setTimeout(resolve, costMs))
if (shouldFail) {
throw new Error('network unavailable')
}
return 'visible'
}
async function verifyArkWebGuard(): Promise<void> {
const traceId = 'web-' + Date.now()
const guard = new WebFirstScreenGuard()
guard.start(traceId)
try {
await fakeLoad(300, false)
guard.markFirstContent(traceId)
} catch (error) {
guard.showFallback(traceId, String(error))
}
}
~~~
再跑失败路径:
~~~ts
async function verifyArkWebFailPath(): Promise<void> {
const controller = new WebRecoverController()
controller.open('https://example.com/detail')
controller.onLoadFailed('network unavailable')
controller.retry()
}
~~~
这两个用例至少能证明:首屏成功时会清掉超时兜底;失败时用户能看到恢复入口。
验收标准要写到代码评审里
| 检查项 | 通过标准 |
| 容器创建 | 进入页面后能看到 Web 容器或骨架 |
| 首屏超时 | 超过阈值显示可恢复兜底,不无限白屏 |
| 失败恢复 | 失败态有重试入口,重试使用最后一次 URL |
| 日志归因 | 每次打开都有 traceId 和阶段输出 |
| 后台恢复 | 切后台再回来不会停在旧 loading |
我会把这些检查放进发布前自测。ArkWeb 白屏不是一个点的问题,它是容器、内核、资源和兜底四段链路共同决定的。
小结
HarmonyOS 7 / API 26 里排查 ArkWeb 白屏,先不要急着改页面。先确认白屏停在哪个阶段:容器、内核、资源还是兜底。再把首屏超时、失败恢复、状态分层和 trace 日志补起来。这样后面再出现白屏,能直接看到问题落在哪段,而不是在 UI、网络、Web 前端之间来回猜。