IndexedDB persistence in PWA application - progressive-web-apps

PWA application storage (IndexedDB) isn't able to provide data persistence.
In case that PWA is pinned to home screen it is possible to clear all application data from browser by clearing browsing history.
It might be unclear for users that cleaning browser data can affect pinned application and unsynchronised data will be lost.
Is there any way to avoid this?
The only way I see for now - turn back to native apps.

The clear storage mechanism in browsers is to put the user in control of their device.
This is why you as an application should never (native or web) assume your cached assets are cached.
If it is absolutely important to you to make sure you have core assets and data persisted then you need to have some sort of integrity check when the service worker initiates. That way you can restore cached state in case the application goes offline.
You also need to realize the operating system, looking at you iOS, will purge data when it feels like it (think when the available disk space gets critical), which takes you out fo control. It does this for native apps too as far as I know.

I do not know a way around that. The function in Chrome to "clear storage" (for example) does exactly that. I suppose it is reasonable for a user to be able to remove any data from their own device, but I agree it is not a good situation for the developer.

This is not possible.
The Storage API provides a StorageManager.persist() method to request the user explicit permission to persist data until deleted by the user itself:
if (navigator.storage && navigator.storage.persist)
navigator.storage.persist().then(function(persistent) {
if (persistent)
console.log("Storage will not be cleared except by explicit user action");
else
console.log("Storage may be cleared by the UA under storage pressure.");
});
If the local storage is running out of space, the User Agent will start automatically pruning cached resourced except the ones set as "persistent". However if the user itself chooses to clear the local data, there is no way to prevent this.
As far as I am aware, there is no event you can intercept in order to detect a browser clear action from the user.
See API reference doc :
https://developer.mozilla.org/en-US/docs/Web/API/StorageManager/persist

Related

Angular PWA Offline Storage

I’m building a new web application which needs to work seamlessly even when there is no internet connection. I’ve selected Angular and am building a PWA as it comes with built-in functionality to make the application work offline. So far, I have the service worker working perfectly and driven by the manifest file, this very nicely caches the static content and I’ve set it to cache a bunch of API requests which I want to use whilst the application is offline.
In addition to this, I’ve used localStorage to store attempts to invoke put, post and delete API requests when the user is offline. Once the internet connection is re-established, the requests stored in localStorage are sent to the server.
This far in my proof of concept, the user can access content whilst offline, edit data and the data gets synced with the server once the user’s internet connection is re-established. This is where my quandary begins though. There is API request data cached automatically by the service worker as defined in the manifest file, and there is a separate store of data for data edits whilst offline. This leads to a situation where the user edits some data, saves the data, refreshes the page and the data is served by the service worker cached API.
Is there a built in mechanism to update API data cached automatically by the service worker? I don’t fancy trying to unpick this manually as it seems hacky and I can’t imagine it’ll be future proof as service workers evolve.
If there isn’t a standard way to achieve what I need to do, is it common for developers to take full control of offline data by storing it all in IndexedDB/localStorage manually? i.e. I could invoke API requests and write some code which caches the results in a structured format in IndexedDB to form an offline database, then writes back to the offline database whenever the user edits some data, and uploads any data edits when the user is back online. I don’t envisage any technical problems with doing this, it just seems like a lot of effort to achieve something which I was hoping to be standard functionality.
I’m fairly new to developing with Angular, but have many years of other development experience. So please forgive me if I’m asking obvious questions, I just can’t seem to find a good article on best practices for working with data storage with service workers.
Thanks
I have a project where my users can edit local data when they are offline and I use Cloud Firestore to have a local database cached available. If I understood you correctly, this would be exactly your requirement.
The benefit of this solution is that with just one line of code, you get not only a local db, but also all the changes made offline are automatically synchronised with the server once the client gets online again.
firebase.firestore().enablePersistence()
.catch(function(err) {
// log the error
});
// Subsequent queries will use persistence, if it was enabled successfully
If using this NoSQL database is an option for you I would go with it, otherwise you need to implement the local updates by yourself as there is not a built in solution for that.

Does facebook have its own cache?

While developing Facebook applications I have faced this problem many times that if I delete any image, then it appears on the application while testing, even I delete the whole file then, even, it is executed successfully, so I want to know "Does Facebook have its own cache from where files are executed?".
If so then is there any solution of this problem?
If not then why is happening this?
Best Regards & Thanks in advance
Not sure about image files (they reside in CDN) but facebook uses MemCached server to cache their stuff.
It's not that it has cache but that its main backing store doesn't provide any more coherency than is strictly necessary. Coherency has a cost, so if you don't need it, it makes sense not to pay the cost.
When operations have no enforced order between them, they may complete as if they were executed in either order. If your retrieval and your delete have on enforced order, then they may complete as if they were executed in either order. This applies even if one operation receives its response before the other operation was sent.
My understanding was that there was a cache. Especially for images and styles.
I have frequently made changes to css and updated images only to be left wondering why i can not see these updates.
I always change my css url to be something like styles/styles.css?time= which remedies everything.
In regards to the images , right click on the image in application and view in browser. Refresh to get the updated image and then go back to you application.

Recreating core data at application launch

I have an app that connects to a website. I store its data as core data and then I use the core data to load my tableviews. I believe, I want to reload the data from the website every time I launch the app, since the user could change the data if they were to go onto the website.
What's the best way to approach this? Should I just delete the core data each time the app terminates?
It depends on how critical it is that data on the device always be current, on how long you expect users to wait before working with the app, and on what you want to happen if someone tries to use the app when the network is slow or unavailable. If you delete the store, and the app can't connect immediately, the user has no data. Even if the network is fine, the user still has to wait on network and server latency before they can start using the app. This is likely to be poor UX.
On the other hand if you allow data to persist after the app exits, the user's data might not be current, at least not at first.
If you don't ever want the data to persist after the app exits, an in-memory store might be the best choice, because it will never be saved to a file anyway.
If presenting potentially old data is OK either (a) briefly when the app starts up or (b) when the network is unavailable, a better choice would be to keep the data store but make new network calls to update the existing data. You could provide some sort of UI to indicate that updates are in progress. You might also have some in-app indication of when your app last synced with the server.
I'm not sure of how your application makes use of the Core Data stack, but if you don't care about (or don't have) changes made locally on the device, I'd say the easiest way to refresh the data from the server is just what you said: wipe out the store file, re-create it and import the data from the server. However, I wouldn't do this systematically on each application launch. Make sure the user knows about it and think of providing a "refresh" button to trigger that procedure. Also make sure you can download new content from the server, before wiping out the local store.
If you want to load all the data in memory (and also want to do updates) then you can create a managed object context backed by a NSAtomicStore persistent store subclass. In the NSAtomicStore subclass you can implement the read: (load: method) and the CRUD actions (newReferenceObjectForManagedObject:, save: and updateCacheNode:fromManagedObject: methods)

Strategies on synching data and caching data between iphone and server

Say I have a TODO list iphone app, that can be edited/viewed from both a web application and the iphone application.
When on the iphone, when a user views all his todo lists, or sub-items, I would think that each time the user views a particular list it shouldn't be hitting the web applications API every-time, but rather cache locally the values and only hit the web when things change.
What strategies are there for this type of scenerio?
I agree with you in your dirty-otherwise-do-not-contact-the-server point. And I think this point is pretty straightforward and easy to implement.
However, be careful in this scenario: it gets dirty but at the same time, the device cannot reach the internet. In this scenario, I suggest you check the internet accessibility on a frequent basis (even when your app is in the background), and try to reach your server and update whenever possible.
This is a tricky problem. I'm currently working on an app that needs to perform a similar synchronization, and I haven't decided how I want to handle it yet.
You're right in that you don't want to be hitting the web repeatedly. It would slow the app down considerably. Keeping a local cache is the way to go.
One drawback is that the user could change/add an item on the web and you wouldn't see it on the phone. You'd need to have a refresh button (like in the Mail application, for example) to allow the user to get the changes.
Then you have an issue with conflict resolution. Say the same item is edited on both the phone and on the web. How does the user pick which one to keep, or do they get duplicated?
I think the best way to do this is to replicated your server's schema in CoreData. Then load a given element from the local DB, and in the background go out and check that element for updates if the device has an internet connection. You're hitting the db each time, but the user is not slowed down by the process.
You should not query the internet everytime you view the list.
But when you make updates to it, or edit it, you should update the server as well. That will make your life a whole lot simpler. That way when the user updates an item that he deleted in the web server, the server will just throw that request out...

What's the best way to do one-way synching from a server-side database to iPhone?

I've got a database on my server which is about 3mb big. I'd like to ship that with my iphone application.
The most important thing is that I'd like to promote changes to the database (insert, updates, deletes) to the iphone. What's the best way of doing that? I mean - what is necessary on
- the server
- the client (= iphone)
- between; how to transfer this data?
I'm pretty free in using technologies serverside; right now, I've got an sqlite-database on the server filled with the data I'd like to sync to the iphones.
How often do you need the database to be updated, and how urgent are the changes?
If the database updates are infrequent and non-urgent, I'd have the app check for a new version of the database on startup, and if it has changed, download the entire new file.
The app would always download a small metadata file from a known URL on startup. The metadata file contains an version identifier for the latest version and a location where that version of the database can be downloaded. If the version identifier has changed from the version the app already has, will download the new version. If the version identifier has not changed, or if it can't check, the app can keep using the version it has.
Pro tip: if you want to show a progress bar for the download, include the size of the database in the metadata file. Cell networks often have transparent proxies that strip out the Content-Length header from HTTP responses.
Try using web hooks.
The concept of a WebHook is simple. A
WebHook is an HTTP callback: an HTTP
POST that occurs when something
happens; a simple event-notification
via HTTP POST.
A web application implementing
WebHooks will POST a message to a URL
when certain things happen. When a web
application enables users to register
their own URLs, the users can then
extend, customize, and integrate that
application with their own custom
extensions or even with other
applications around the web. For the
user, WebHooks are a way to receive
valuable information when it happens,
rather than continually polling for
that data and receiving nothing
valuable most of the time. WebHooks
have enormous potential and are
limited only by your imagination! (No,
it can't wash the dishes. Yet.)
You can find out more on Webhooks here:
http://www.webhooks.org/ and http://webhooks.pbworks.com/
Wonder if you have considered using a Sync Framework to manage the synchronization. If that interests you can take a look at the open source project, OpenMobster's Sync service. You can do the following sync operations
two-way
one-way client
one-way device
bootup
Besides that, all modifications are automatically tracked and synced with the Cloud. You can have your app offline when network connection is down. It will track any changes and automatically in the background synchronize it with the cloud when the connection returns. It also provides synchronization like iCloud across multiple devices
Also, modifications in the Cloud are synched using Push notifications, so the data is always current even if it is stored locally.
Here is a link to the open source project: http://openmobster.googlecode.com
Here is a link to iPhone App Sync: http://code.google.com/p/openmobster/wiki/iPhoneSyncApp