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