progressive-web-apps

pwa: deferredPrompt.prompt() can only use once


I use pwa to click addToHomeScreen.But I found it works only the first click, when I canceled, click doesn't work, and the install dialog doesn't show. html code like this

if ('serviceWorker' in navigator) {
    window.addEventListener('load', () => {
        navigator.serviceWorker.register('/sw.js')
            .then(registration => {
                console.log('Service Worker registered');
            })
            .catch(error => {
                console.error('Service Worker registration failed:', error);
            });
    });
}

router file use useeffect to listen and bind function

//app.tsx
useEffect(() => {
    window.addEventListener('beforeinstallprompt', (event) => {
        event.preventDefault();
        console.log('👍', 'beforeinstallprompt', event);
        // 这个变量后面要用
        window.deferredPrompt = event;
        // 你用来显示 添加到PWA 的 按钮可以显示出来了
        // your code here
    });

    window.addEventListener('appinstalled', (event) => {
        console.log('👍', 'appinstalled', event);
        // 回收 deferredPrompt 变量
        window.deferredPrompt = null;
    });
}, []);

button component is used to click for addtohomescreen

//button.tsx
const handleAddToHomeScreen = () => {
    const promptEvent = window.deferredPrompt;
    if (!promptEvent) {
        // deferred prompt 不可用
        return;
    }
    promptEvent.prompt();
    promptEvent.userChoice.then((choiceResult) => {
        console.log('👍', 'userChoice', choiceResult);
        if (choiceResult.outcome === 'accepted') {
            console.log('用户 同意了');
            // 成功之后的业务回掉操作
            // your code here
        } else {
            console.log('用户 没同意');
        }
        // 回收 deferredPrompt 变量, prompt() 只能被调用一次
        window.deferredPrompt = null;
    });
};

// 在这里编写你的组件逻辑
return (
    <div
        className={styles.container}
        id="addToHomeScreen"
        onClick={handleAddToHomeScreen}
    >
        添加快捷方式
    </div>
);

Solution

  • it seems that in the service worker file, I didn't use the fetch handler.