Skip to content

Commit 0f37e56

Browse files
committed
fix(dweb): retry virtual keyboard overlay initialization
1 parent abfe2bf commit 0f37e56

3 files changed

Lines changed: 102 additions & 3 deletions

File tree

src/lib/dweb-keyboard-overlay.test.ts

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import { describe, expect, it, vi } from 'vitest'
2-
import { applyDwebKeyboardOverlay, type DwebPluginsModule } from './dweb-keyboard-overlay'
2+
import {
3+
applyDwebKeyboardOverlay,
4+
startDwebKeyboardOverlay,
5+
type DwebPluginsModule,
6+
} from './dweb-keyboard-overlay'
37

48
describe('dweb keyboard overlay', () => {
59
it('skips when current environment is not dweb', async () => {
@@ -56,4 +60,53 @@ describe('dweb keyboard overlay', () => {
5660

5761
warnSpy.mockRestore()
5862
})
63+
64+
it('retries until dweb environment is ready', async () => {
65+
vi.useFakeTimers()
66+
67+
const setOverlay = vi.fn<(overlay: boolean) => Promise<void>>().mockResolvedValue()
68+
const loadPlugins = vi.fn<() => Promise<DwebPluginsModule>>().mockResolvedValue({
69+
virtualKeyboardPlugin: { setOverlay },
70+
})
71+
72+
let ready = false
73+
const stop = startDwebKeyboardOverlay({
74+
isDweb: () => ready,
75+
loadPlugins,
76+
maxAttempts: 4,
77+
retryDelayMs: 100,
78+
})
79+
80+
expect(loadPlugins).not.toHaveBeenCalled()
81+
82+
ready = true
83+
await vi.advanceTimersByTimeAsync(120)
84+
85+
expect(loadPlugins).toHaveBeenCalledTimes(1)
86+
expect(setOverlay).toHaveBeenCalledWith(true)
87+
88+
stop()
89+
vi.useRealTimers()
90+
})
91+
92+
it('stops retrying after cleanup', async () => {
93+
vi.useFakeTimers()
94+
95+
const loadPlugins = vi.fn<() => Promise<DwebPluginsModule>>().mockResolvedValue({})
96+
const stop = startDwebKeyboardOverlay({
97+
isDweb: () => true,
98+
loadPlugins,
99+
maxAttempts: 10,
100+
retryDelayMs: 100,
101+
})
102+
103+
await vi.advanceTimersByTimeAsync(120)
104+
expect(loadPlugins).toHaveBeenCalledTimes(2)
105+
106+
stop()
107+
await vi.advanceTimersByTimeAsync(500)
108+
expect(loadPlugins).toHaveBeenCalledTimes(2)
109+
110+
vi.useRealTimers()
111+
})
59112
})

src/lib/dweb-keyboard-overlay.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ export interface ApplyDwebKeyboardOverlayOptions {
1313
loadPlugins?: () => Promise<DwebPluginsModule>
1414
}
1515

16+
export interface StartDwebKeyboardOverlayOptions extends ApplyDwebKeyboardOverlayOptions {
17+
maxAttempts?: number
18+
retryDelayMs?: number
19+
}
20+
1621
async function defaultLoadPlugins(): Promise<DwebPluginsModule> {
1722
const moduleName = '@plaoc/plugins'
1823
const module = await import(/* @vite-ignore */ moduleName)
@@ -46,3 +51,43 @@ export async function applyDwebKeyboardOverlay(
4651
return false
4752
}
4853
}
54+
55+
/**
56+
* 启动键盘 overlay 应用流程(包含重试),用于规避运行时初始化时机过早导致的失效。
57+
*/
58+
export function startDwebKeyboardOverlay(
59+
options: StartDwebKeyboardOverlayOptions = {},
60+
): () => void {
61+
const maxAttempts = Math.max(1, options.maxAttempts ?? 10)
62+
const retryDelayMs = Math.max(50, options.retryDelayMs ?? 300)
63+
let stopped = false
64+
let timer: ReturnType<typeof setTimeout> | null = null
65+
let attempts = 0
66+
67+
const run = async (): Promise<void> => {
68+
if (stopped) {
69+
return
70+
}
71+
72+
const applied = await applyDwebKeyboardOverlay(options)
73+
attempts += 1
74+
75+
if (applied || stopped || attempts >= maxAttempts) {
76+
return
77+
}
78+
79+
timer = setTimeout(() => {
80+
void run()
81+
}, retryDelayMs)
82+
}
83+
84+
void run()
85+
86+
return () => {
87+
stopped = true
88+
if (timer !== null) {
89+
clearTimeout(timer)
90+
timer = null
91+
}
92+
}
93+
}

src/service-main.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
installLegacyAuthorizeHashRewriter,
44
rewriteLegacyAuthorizeHashInPlace,
55
} from '@/services/authorize/deep-link'
6-
import { applyDwebKeyboardOverlay } from '@/lib/dweb-keyboard-overlay'
6+
import { startDwebKeyboardOverlay } from '@/lib/dweb-keyboard-overlay'
77

88
export type ServiceMainCleanup = () => void
99

@@ -19,7 +19,7 @@ export function startServiceMain(): ServiceMainCleanup {
1919
rewriteLegacyAuthorizeHashInPlace()
2020

2121
// DWEB: keep viewport stable when soft keyboard appears.
22-
void applyDwebKeyboardOverlay()
22+
const cleanupKeyboardOverlay = startDwebKeyboardOverlay()
2323

2424
// Initialize preference side effects (i18n + RTL) as early as possible.
2525
preferencesActions.initialize()
@@ -37,5 +37,6 @@ export function startServiceMain(): ServiceMainCleanup {
3737

3838
return () => {
3939
cleanupDeepLink()
40+
cleanupKeyboardOverlay()
4041
}
4142
}

0 commit comments

Comments
 (0)