How to share data across a group of applications in Android
Asked Answered
E

3

13

Consider the following scenario. A company releases many apps. And they want some data to be shared across all these apps. Any of these app can create or read these data, just like a common database. So company decided to create an android library which does this purpose. I searched for a few days and my analysis are given below.

  1. SharedPreferences- not recommended and is deprecated. It does not serve the purpose too. All other apps need to know the package name of the app that created the data to create PackageContext. Here this is impractical as any app can create/update/read data and it is not possible to say who is who.

  2. ContentProviders - This does not work for me. The reason being ContentProviders has to be present in each app. There can not be 2 content providers with same name in a device. In addition to that, ContentProviders are basically meant for one app creates data and other apps subscribe to it using Content_Uri.

  3. Network connection - We do not want to do store data in any server.

  4. External storage - This is the only option remaining. Should I go for this?

And interestingly the data has to be secured as well which is nowhere supported in any of the storage options.

Note: For iOS, we use keychain to implement the same functionality

Empressement answered 30/10, 2013 at 18:37 Comment(6)
y dont u use remote database?Connive
if you are talking about database outside the device, I don't want to. I really want the data to be stored on the device in a most secured way. But I don't mind the safety of the data if Android does not provide anything.Empressement
Great question with weak answers. I am struggling with this for weeks and found no decent answers yet even after observing ~50 related Q's. I have also another burden that I want to achieve this with react-native. I am using this module and it works as I wish for iOS with Keychain but I can not manage it on Android.Stirps
@Stirps Were you able to solve your problem? I am also currently in the same boat as you were last year.Pomegranate
@Pomegranate I was not. So I did write the data to a file with encryption and read it by the multiple parties with a shared key. Things move fast, maybe they could have solved the issue for Android as well. I hope you can achieve it better than I did.Stirps
@Stirps i'm in your shoe now and i think still your approach is the bestMichelsen
T
7

Understanding the problem on Android

Ironically, due to the intense sandboxing on iOS, there's a straightforward way to make this happen there (App Groups) provided the apps that need to share data are all by the same developer. Likely because Android is more flexible on security, this actually ends up being a more difficult problem there. The Android team have so far not seen fit to provide a convenient and secure way to specifically share this kind of data because there's a low security workaround.

That said, there are plenty of ways to share data between applications without involving the cloud.

SharedPreferences

The original question states that SharedPreferences are deprecated. This isn't true, as far as I can tell, however the MODE_WORLD_READABLE and MODE_WORLD_WRITABLE contexts are deprecated which makes this approach subject to not working in the future. The mode has been deprecated for quite some time, though - since Android 4.2 (2012). There's no threat in the current Android docs to suggest they're actually phasing it out (sometimes deprecation just means "this isn't a great idea" not "this is going to be removed"). I suspect the lack of a more secure OS-level direct alternative for application data sharing at the settings level is probably the reason for preserving it in a state of deprecation for the last 5 years.

File Access

The simplest and most common way I'm aware of to implement data sharing between applications on Android is to simply request file access on the device and create a shared location on external storage for this data. (Don't be confused by the "external storage" designation - this is just how Android refers to shared data. It doesn't necessarily refer to an SD card.) You give the file a unique name, and you store it somewhere that your apps know where to look for it. Best way to get that path is something like: Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)

The obvious problem with this is security. While not deprecated by the OS, it introduces the same problem that the Android docs list as the reason for deprecating MODE_WORLD_* - it's inherently insecure and opens up potential exploits in your application.

  • You're placing your information where everything has ready access to it.
  • You're asking for permissions that your app may not otherwise need.
  • You're reading files that you can't verify the origin of.

If your application isn't handling any sensitive data, maybe this doesn't matter to you (it might to your users). If you're planning to read data from those files, you should ensure you're providing maximum validation for that data before parsing. Check the size of the file, validate the formatting, etc.

Creating your own service

You could always create a Service or an IntentService. (There are subtle differences between the two, but IntentService is a subclass of Service that runs in a Worker thread while Service interrupts the main thread. IntentService also implements Intent support which provides the most straightforward interapplication communication on Android).

This service has its own private storage, for which it has full read/write access, but nothing else does. This service then provides an interface to receive Intents from other apps, and to return results (as Intents) to those apps. This is an extremely friendly way to implement interapplication data while maximizing data privacy and security of that data. If outlying apps mostly need to request very basic information from a central application, this is your entry-level option.

Implementing a BroadcastReceiver

Along the same lines is the BroadcastReceiver class. Depending on what sort of data you're intending to share between applications, and how familiar those applications may be with your specific approach, this another possibility. Again, you'll be managing the shared data under one application's private storage. Communication is done by Intents, so it's similar to an IntentService - except that applications may communicate with a BroadcastReceiver by issuing systemwide events (that is, they don't need to be explicitly communicating with your app or service - they're shouting out the world for a piece of info, and expecting an answer.)

Creating a ContentProvider

The Original Post seems to misunderstand what a ContentProvider is and how it works. You have to think of this type of item like you would a cloud solution - even though it's local to your device. Every app doesn't need a ContentProvider - they all need to communicate with a ContentProvider, and that ContentProvider maintains, updates and returns data.

This is probably the most "Android-y" solution for this particular usecase and offers the greatest expandability. You implement an independent process that handles data storage and responds to other applications. It is, however, a more evolved solution - and as such may be more a more challenging endeavor. If you need a real database service, rather than a fairly simple request/response type service, ContentProvider seems to be the best choice.

Terti answered 26/2, 2017 at 7:11 Comment(0)
L
2

Seems like what you need is shared user id.

It allows application sandbox to be shared across multiple android applications if they are all signed by the same signature.

But, watch out for gotchas!

Laxity answered 30/10, 2013 at 18:57 Comment(2)
how "shared user id" is going to help here? I cant still use SharedPreferences with MODE_PRIVATE. Is there any other way to handle this scenario?Empressement
sharedUserId was deprecated in API level 29.Fitts
U
0

Yes. Probably using same path in external storage for all applications is the best way. A common portion of code could be used to know whether database there exists or not and therefore open or create new one. For security I recommend always to use 'user' and 'password' when connecting to DB, but if you think it is not sufficient I advise you to see this: http://www.hwaci.com/sw/sqlite/see.html

Unstoppable answered 30/10, 2013 at 19:40 Comment(8)
Seems like adding encryption/password protection won't be useful in OP's scenario. There is nothing that can prevent me, malicious third party app developer, from reverse engineering OP's app to get those passwords/keys, so I can later use them to decrypt (and mess with it the way I want) the database that is stored on external storage, as you propose. On the other hand with shared user id approach I won't be able to access sandbox used by OP's appliations (and thus data) unless my app is signed with OP's signature (which is not the case because this signature should be kept secret).Laxity
Unless that password is given later by original developer to all his authenticated clients on a secure connection like SSL. Yes, password should not be put in sources, it's obvious. Encrypt data through AES-128 is fast and secure, force AES with plaintex and cyphertext known is as hard as trying brute force 2^128 bit password.Unstoppable
I can only partialy agree. "Unless that password is given later by original developer to all his authenticated clients on a secure connection [...]" implies that there is a server side that stores keys/passwords and some means of client authentication. Based on what OP said this (storing data on server) is undesired in his scenario. However, I do can think of one case when encryption could be useful. If the key/password for the database is retrieved from user himself (ie if there is an encrypted database stored in shared location and every of the OP's apps asks user for keys for this database)Laxity
... in this case there will be no need for server side.Laxity
I suppose that applications are downloadable only from certain persons (ie who pays for it) that implies that if you have my application you and only you can be able to produce MAC, authentication is resolved. Only one connection is required the first time app starts in such a way to get password and this is different from "storing data on server". Key will be saved locally in mode private and no other application can read it. But this is only my idea on how this app should work... Jose is free to use any approach he prefears.Unstoppable
How about going for a separate application for storing/retrieving this data? All other app can invoke this app to create data and using content provider we can fetch the data too. But I would like to avoid any UI from this (library) app. How about doing a background service?Empressement
Separate application?! If many read or write actions are required this approach should degrade performance. SQLite server is just a good server in order to do this. You may use services for all that applications need to perform read/write in background, when their activities are in onPause() state. Only one activity at the time is in foregraund and listens events and if your scenario provides that this interaction is strictly connected to the read/write actions you don't need further service between application and DB server.Unstoppable
Rather I would use a library to be imported that starts a new thread when application goes onResume() and terminates when application goes onPause(), a parallel flow that receives Messages in a FIFO Handler through its own Looper and performs whatever kind of action you need to forward DB server. No waste of resources whereas activity sleeps.Unstoppable

© 2022 - 2024 — McMap. All rights reserved.