Welcome to the Ionic forums.
The first thing I want to emphasize is how important it is to separate the two parts of your question. I’ll address them in reverse order.
The way to access business objects (a term I use instead of “data” in order to emphasize that they’re things like customers, orders, students, trouble tickets, etc, as opposed to implementation stuff like backend server URLs - frequently those two classes of things get mashed together under the umbrella of “data”) from multiple pages is covered in Chapter 4 of the Tour of Heroes:
Create a service, inject it in every page that needs the business objects, expose an
Observable of the appropriate type, subscribe to that
Observable when the page is created, and unsubscribe when the page is destroyed. This post contains some sample code for doing this with user profile settings that should generalize to other situations.
As far as your pages go, that is the end of the story. Period. Full stop.
And that’s why it’s important to separate the two issues, because the way that you store, distribute, and manage your business objects is likely to change over the life of your app, and it’s needlessly painful if those changes necessitate any modification to every page that presents and interacts with them.
As for how to persist business objects, there are several factors to consider. You covered one, which is “do we need these to stay across app restarts?”. That requirement DQs
localStorage. You also said that it needs to “remain on the mobile device”. I suspect it may at least be conceivable that at some point in the future, you will want to send these business objects out onto the Internet, and retrieve them from servers. As long as you make sure to isolate all the details of this into a service, it should be fairly painless to make that change, but for now, we’ll also forget about the option of storing things out in the cloud somewhere.
That leaves, broadly speaking, three options:
I would consider SQLite a bad fit for the sort of data you are describing, because you don’t need the overhead of a relational database here, so we’re down to two, and here are the pros and cons:
IndexedDB works in desktop browsers. This can drastically improve your development productivity (and potential deployment reach, because you can distribute the app not only as a mobile build, but as a PWA). You can reap all the benefits of live reload rapid development, and there is no need to actually build a mobile app bundle and run it on an emulator or device every time you change anything. It’s not “secure” in the sense that anybody with physical access to the unlocked device can read or modify it. I generally don’t consider that a huge concern, and I’m doubting you will in this case, either, given the way you’ve described the data. However, if it is…
The OS-specific storage options are, as you would expect, integrated with the security features of the OS. The data is encrypted at rest and access is controlled directly via lockscreen / passphrase / PIN / biometrics / whatever. This option is, when compared with IndexedDB, a PITA to develop with, because it won’t work in browsers, and must be run on a physical device or an emulator.
So my initial recommendation is IndexedDB, and you deem the specific security threat it poses a sufficient concern, then go with the native option.
Fortunately, whichever choice you make, you won’t have to deal with the underlying API directly. For IndexedDB, use @ionic/storage. For the native options, use @capacitor/storage. Each of those provide future-friendly APIs that will integrate nicely with your service provider that distributes the data to your pages.
One final question that you didn’t ask is “when should I read and write to device storage?”. To avoid race conditions, I have very strong opinions about this. Read only once per app run, either at app startup or lazily the first time the data is needed. Never read the same data from device storage twice in an app run. Following that rule allows you to be much more relaxed about writes: do them whenever you want, and treat them optimistically. Whenever they finish, they finish. You don’t care, because your app isn’t going to read them back until the next time it starts up, at which point either they finished properly or they didn’t, but there isn’t anything you can do about it then.