Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/409.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何将我在apple设备上保存的数据与service worker同步?_Javascript_Vuejs2_Service Worker_Workbox - Fatal编程技术网

Javascript 如何将我在apple设备上保存的数据与service worker同步?

Javascript 如何将我在apple设备上保存的数据与service worker同步?,javascript,vuejs2,service-worker,workbox,Javascript,Vuejs2,Service Worker,Workbox,我知道苹果生态系统不支持后台同步API,所以你如何绕过它,并制定一个在苹果生态系统和其他平台上也能运行的解决方案,现在我有了一个使用后台同步API的解决方案,出于某种原因,它实际上在IOS上不做任何事情,它只保存失败的请求,然后再不同步-s,我是否可以用indexedDB包装器以某种方式访问同步队列,然后在任意时间同步? 我试过一次,结果什么都坏了,你们知道怎么做吗 const bgSyncPlugin = new workbox.backgroundSync.Plugin('uploa

我知道苹果生态系统不支持后台同步API,所以你如何绕过它,并制定一个在苹果生态系统和其他平台上也能运行的解决方案,现在我有了一个使用后台同步API的解决方案,出于某种原因,它实际上在IOS上不做任何事情,它只保存失败的请求,然后再不同步-s,我是否可以用indexedDB包装器以某种方式访问同步队列,然后在任意时间同步? 我试过一次,结果什么都坏了,你们知道怎么做吗

    const bgSyncPlugin = new workbox.backgroundSync.Plugin('uploadQueue', {
    maxRetentionTime: 60 * 24 * 60,
    onSync: async ({ queue }) => {
        return getAccessToken().then((token) => {
            replayQueue(queue, token).then(() => {
                return showNotification();
            });
        });
    },
});
这是我的密码,他们都是。有一个目的,因为我的令牌有一个超时,所以我必须检查令牌是否过期,然后继续,如果过期,则在标题中替换令牌,并且我还必须在请求主体中同步时更改数据,但这在除apple设备外的任何设备上都可以正常工作。Apple设备从不触发onsync,我尝试通过以下方式监听获取事件并触发onsync:

self.registration.sync.register('uploadQueue');
但毫无疑问,我试图在servvice worker注册上注册sync,但似乎没有任何帮助。 如果同步注册在ios上不可行,那么我可以以某种方式访问上载队列表吗?
附言:我正在使用dexie.js作为indexedDB包装器,它是一个vue.js应用程序,带有laravel api,同步过程非常复杂,但它正在工作,只是需要弄清楚如何在IOS上实现它

经过两周的思考和待办事项,我终于找到了答案。 现在买些爆米花,把你自己绑起来,因为这真是个大麻烦。 在我的例子中,同步过程相当复杂,因为我的用户可能会离开任何连接很长时间,以至于我的AccessToken将过期,因此我必须检查访问令牌的过期情况,并重新蚀刻它。 此外,我的用户可以向人员数据库中添加新的人员,这些人员都有唯一的服务器端id-s,因此我必须先发送人员注册,然后再发送为他们完成的任务和活动,这样我才能从API接收相应的id

现在来看有趣的部分: 首先,您不能使用bgSyncPlugin,因为您不能访问replayQueue,您必须使用普通队列,如下所示:

var bgSyncQueue = new workbox.backgroundSync.Queue('uploadQueue', {
    maxRetentionTime: 60 * 24 * 60,
    onSync: () => syncData(),
   });
if (this.$online && this.isIOSDevice) {
                    if (window.MessageChannel) {
                        var messageChannel = new MessageChannel();
                        messageChannel.port1.onmessage = (event) => {
                            this.onMessageSuccess(event);
                        };
                    } else {
                        navigator.serviceWorker.onmessage = (event) => {
                            this.onMessageSuccess(event);
                        };
                    }
                    navigator.serviceWorker.ready.then((reg) => {
                        try {
                            reg.active.postMessage(
                                {
                                    text: 'sync',
                                    port: messageChannel && messageChannel.port2,
                                },
                                [messageChannel && messageChannel.port2]
                            );
                        } catch (e) {
                            //firefox support
                            reg.active.postMessage({
                                text: 'sync',
                            });
                        }
                    });
                }
并将失败的请求推送到获取侦听器内的队列:

this.onfetch = (event) => {
    let requestClone = event.request.clone();
    if (requestClone.method === 'POST' && 'condition to match the requests you need to replay') {
        event.respondWith(
            (() => {
                const promiseChain = fetch(requestClone).catch(() => {
                    return bgSyncQueue.pushRequest(event);
                });
                event.waitUntil(promiseChain);
                return promiseChain;
            })()
        );
    } else {
        event.respondWith(fetch(event.request));
    }
};
当用户有连接时,我们会触发“syncData()”函数,在ios上这有点复杂(稍后会详细介绍),在android上会自动发生,因为服务人员看到它有连接,现在让我们看看syncData做了什么:

async function syncData() {
    if (bgSyncQueue) //is there data to sync?
        return getAccessToken() //then get the access token, if expired refresh it
            .then((token) => replayQueue(bgSyncQueue, token).then(() => showNotification({ body: 'Succsesful sync', title: 'Data synced to server' })))
            .catch(() => showNotification({ title: 'Sync unsuccessful', body: 'Please find and area with better coverage' })); //replay the requests and show a notification
    return Promise.resolve('empty');//if no requests to replay return with empty
}
对于我们完成的android/桌面方面,您可以很高兴您修改的数据被同步,现在在iOS上,我们不能只在用户重新启动PWA时才上传数据,这是糟糕的用户体验,但我们正在使用javascript,一切都有可能

每次客户端代码看到它有internet时,都会触发一个消息事件,如下所示:

var bgSyncQueue = new workbox.backgroundSync.Queue('uploadQueue', {
    maxRetentionTime: 60 * 24 * 60,
    onSync: () => syncData(),
   });
if (this.$online && this.isIOSDevice) {
                    if (window.MessageChannel) {
                        var messageChannel = new MessageChannel();
                        messageChannel.port1.onmessage = (event) => {
                            this.onMessageSuccess(event);
                        };
                    } else {
                        navigator.serviceWorker.onmessage = (event) => {
                            this.onMessageSuccess(event);
                        };
                    }
                    navigator.serviceWorker.ready.then((reg) => {
                        try {
                            reg.active.postMessage(
                                {
                                    text: 'sync',
                                    port: messageChannel && messageChannel.port2,
                                },
                                [messageChannel && messageChannel.port2]
                            );
                        } catch (e) {
                            //firefox support
                            reg.active.postMessage({
                                text: 'sync',
                            });
                        }
                    });
                }
这是Vue.js watch函数中的一个函数,它监视我们是否有连接,如果我们有连接,它还会检查这是否是来自苹果生态系统的设备,如下所示:

isIosDevice() {
            return !!navigator.platform && /iPad|iPhone|MacIntel|iPod/.test(navigator.platform) && /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
        }
所以它告诉服务人员它有互联网,它必须同步,在这种情况下,这段代码被激活:

this.onmessage = (event) => {
    if (event.data.text === 'sync') {
        event.waitUntil(
            syncData().then((res) => {
                if (res !== 'empty') {
                    if (event.source) {
                        event.source.postMessage('doNotification');//this is telling the client code to show a notification (i have a built in notification system into the app, that does not use push notification, just shows a little pill on the bottom of the app with the message)
                    } else if (event.data.port) {
                        event.data.port.postMessage('doNotification'); //same thing
                    }
                    return res;
                }
            })
        );
    }
};
现在我认为最有用的部分是replay queue函数,这家伙从getAccessToken获取队列和令牌,然后它像发条一样工作:

    const replayQueue = async (queue, token) => {
        let entry;
        while ((entry = await queue.shiftRequest())) {//while we have requests to replay
            let data = await entry.request.clone().json();
            try {
//replay the person registrations first and store them into indexed db
                if (isPersonRequest) {
                    //if new person
                    await fetchPerson(entry, data, token);
//then replay the campaign and task submissions
                } else if (isTaskOrCampaignRequest) {
                    //if task
                    await fetchCampaigns(entry, data, token);
                } 
            } catch (error) {
                showNotification({ title: 'no success', body: 'go for better internet plox' });
                await queue.unshiftRequest(entry); //put failed request back into queue, and try again later
            }
        }
        return Promise.resolve();
    };
现在,这是一个关于如何在iOS设备上使用这个家伙并让苹果疯狂的大问题:)我对任何相关的问题都持开放态度,在这段时间里,我认为我对服务人员相关的东西已经变得相当好了,因为这不是这个项目唯一困难的部分,但我离题了,这是另一天的故事

(你可能会发现错误处理并不完美,也许这并不是最安全的,但这个项目的用户数量非常少,有固定数量的用户知道如何使用它以及它的功能,所以在这种情况下,我并不真正担心安全性,但如果你在更严肃的项目中使用它,你可能需要改进)


希望我能帮上忙,大家都过得很愉快。

我已经找到了一个答案,在我的脑海里和待办事项清单上已经有两周了。 现在买些爆米花,把你自己绑起来,因为这真是个大麻烦。 在我的例子中,同步过程相当复杂,因为我的用户可能会离开任何连接很长时间,以至于我的AccessToken将过期,因此我必须检查访问令牌的过期情况,并重新蚀刻它。 此外,我的用户可以向人员数据库中添加新的人员,这些人员都有唯一的服务器端id-s,因此我必须先发送人员注册,然后再发送为他们完成的任务和活动,这样我才能从API接收相应的id

现在来看有趣的部分: 首先,您不能使用bgSyncPlugin,因为您不能访问replayQueue,您必须使用普通队列,如下所示:

var bgSyncQueue = new workbox.backgroundSync.Queue('uploadQueue', {
    maxRetentionTime: 60 * 24 * 60,
    onSync: () => syncData(),
   });
if (this.$online && this.isIOSDevice) {
                    if (window.MessageChannel) {
                        var messageChannel = new MessageChannel();
                        messageChannel.port1.onmessage = (event) => {
                            this.onMessageSuccess(event);
                        };
                    } else {
                        navigator.serviceWorker.onmessage = (event) => {
                            this.onMessageSuccess(event);
                        };
                    }
                    navigator.serviceWorker.ready.then((reg) => {
                        try {
                            reg.active.postMessage(
                                {
                                    text: 'sync',
                                    port: messageChannel && messageChannel.port2,
                                },
                                [messageChannel && messageChannel.port2]
                            );
                        } catch (e) {
                            //firefox support
                            reg.active.postMessage({
                                text: 'sync',
                            });
                        }
                    });
                }
并将失败的请求推送到获取侦听器内的队列:

this.onfetch = (event) => {
    let requestClone = event.request.clone();
    if (requestClone.method === 'POST' && 'condition to match the requests you need to replay') {
        event.respondWith(
            (() => {
                const promiseChain = fetch(requestClone).catch(() => {
                    return bgSyncQueue.pushRequest(event);
                });
                event.waitUntil(promiseChain);
                return promiseChain;
            })()
        );
    } else {
        event.respondWith(fetch(event.request));
    }
};
当用户有连接时,我们会触发“syncData()”函数,在ios上这有点复杂(稍后会详细介绍),在android上会自动发生,因为服务人员看到它有连接,现在让我们看看syncData做了什么:

async function syncData() {
    if (bgSyncQueue) //is there data to sync?
        return getAccessToken() //then get the access token, if expired refresh it
            .then((token) => replayQueue(bgSyncQueue, token).then(() => showNotification({ body: 'Succsesful sync', title: 'Data synced to server' })))
            .catch(() => showNotification({ title: 'Sync unsuccessful', body: 'Please find and area with better coverage' })); //replay the requests and show a notification
    return Promise.resolve('empty');//if no requests to replay return with empty
}
对于我们完成的android/桌面方面,您可以很高兴您修改的数据被同步,现在在iOS上,我们不能只在用户重新启动PWA时才上传数据,这是糟糕的用户体验,但我们正在使用javascript,一切都有可能

每次客户端代码看到它有internet时,都会触发一个消息事件,如下所示:

var bgSyncQueue = new workbox.backgroundSync.Queue('uploadQueue', {
    maxRetentionTime: 60 * 24 * 60,
    onSync: () => syncData(),
   });
if (this.$online && this.isIOSDevice) {
                    if (window.MessageChannel) {
                        var messageChannel = new MessageChannel();
                        messageChannel.port1.onmessage = (event) => {
                            this.onMessageSuccess(event);
                        };
                    } else {
                        navigator.serviceWorker.onmessage = (event) => {
                            this.onMessageSuccess(event);
                        };
                    }
                    navigator.serviceWorker.ready.then((reg) => {
                        try {
                            reg.active.postMessage(
                                {
                                    text: 'sync',
                                    port: messageChannel && messageChannel.port2,
                                },
                                [messageChannel && messageChannel.port2]
                            );
                        } catch (e) {
                            //firefox support
                            reg.active.postMessage({
                                text: 'sync',
                            });
                        }
                    });
                }
这是在Vue.js wat中